diff --git a/_maps/map_files/LayeniaStation/LayeniaStation.dmm b/_maps/map_files/LayeniaStation/LayeniaStation.dmm
index 0e119361..b7bba568 100644
--- a/_maps/map_files/LayeniaStation/LayeniaStation.dmm
+++ b/_maps/map_files/LayeniaStation/LayeniaStation.dmm
@@ -254,7 +254,7 @@
"aIp" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 6; name = "scrubbers pipe"},/turf/open/floor/plasteel,/area/crew_quarters/fitness/pool)
"aIr" = (/obj/effect/turf_decal/stripes/line{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 5; name = "air supply pipe"},/turf/open/floor/plasteel{dir = 8; icon_state = "floor_trim"},/area/ai_monitored/security/armory)
"aIB" = (/obj/machinery/chem_heater,/obj/effect/turf_decal/tile/yellow{dir = 8},/obj/effect/turf_decal/tile/yellow{dir = 1},/turf/open/floor/plasteel/white,/area/medical/chemistry)
-"aIE" = (/obj/machinery/door/airlock/public/glass{name = "Abandon Maintenance Pool"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/turf/open/floor/plasteel/dark,/area/maintenance/fore)
+"aIE" = (/obj/machinery/door/airlock/public/glass{name = "Abandoned Maintenance Pool"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/turf/open/floor/plasteel/dark,/area/maintenance/fore)
"aIJ" = (/obj/effect/spawner/structure/window/reinforced,/turf/open/floor/plating,/area/medical/virology)
"aIK" = (/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer3{dir = 1; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer1{dir = 1; name = "scrubbers pipe"},/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel{dir = 1; icon_plating = "floor"; icon_state = "floor_whole"},/area/hallway/secondary/exit)
"aIT" = (/obj/machinery/atm{pixel_y = 30},/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/brown,/turf/open/floor/plasteel,/area/hallway/primary/aft)
@@ -2953,7 +2953,7 @@
"iqp" = (/obj/structure/table,/obj/effect/turf_decal/tile/yellow{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral,/obj/item/clothing/glasses/meson{pixel_x = 2; pixel_y = 4},/obj/item/clothing/glasses/meson,/turf/open/floor/plasteel,/area/engine/engineering)
"iqt" = (/obj/effect/turf_decal/tile/blue{dir = 1},/obj/effect/turf_decal/tile/blue{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/obj/machinery/atmospherics/components/unary/vent_pump/on/layer3{name = "air vent"},/obj/structure/cable{icon_state = "2-4"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/newscaster{pixel_y = 32},/turf/open/floor/plasteel/white,/area/medical/sleeper)
"iqu" = (/obj/structure/table,/turf/open/floor/plasteel/freezer,/area/medical/sleeper)
-"iqD" = (/obj/structure/flora/crystal/medium/growth,/turf/open/indestructible/layenia/crystal/garden,/area/layenia)
+"iqD" = (/obj/structure/flora/crystal/medium/growth,/turf/open/indestructible/layenia/crystal/garden,/area/crew_quarters/heads/hop)
"iqP" = (/obj/structure/flora/junglebush,/obj/structure/window/reinforced{dir = 8},/turf/open/floor/grass,/area/medical/sleeper)
"ire" = (/obj/machinery/light{dir = 4; pixel_x = 7; pixel_y = 0},/obj/machinery/porta_turret/ai{dir = 8},/turf/open/floor/circuit,/area/ai_monitored/turret_protected/ai_upload)
"irn" = (/obj/structure/chair{dir = 8},/obj/structure/window{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel{dir = 4; icon_state = "floor_plate"},/area/hallway/secondary/exit)
@@ -3236,7 +3236,7 @@
"jax" = (/obj/machinery/meter/atmos/atmos_waste_loop,/obj/machinery/camera{c_tag = "Atmospherics North East"},/obj/machinery/light{dir = 1; pixel_y = 16},/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{dir = 1},/obj/structure/cable{icon_state = "2-4"},/turf/open/floor/plasteel,/area/engine/atmos)
"jaB" = (/obj/item/twohanded/required/kirbyplants/random,/turf/open/floor/wood,/area/lawoffice)
"jaD" = (/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral,/turf/open/floor/plasteel/dark,/area/security/main)
-"jaH" = (/obj/structure/cable/yellow{icon_state = "1-4"},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat_interior"; name = "Antechamber Turret Control"; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat_interior)
+"jaH" = (/obj/structure/cable/yellow{icon_state = "1-4"},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat/hallway"; name = "Antechamber Turret Control"; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat_interior)
"jaR" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/machinery/light{pixel_y = -1},/obj/structure/sign/departments/restroom{pixel_y = -32},/turf/open/floor/plasteel{icon_state = "floor_plate"},/area/hallway/primary/fore)
"jaX" = (/obj/effect/baseturf_helper/asteroid/layenia,/turf/closed/wall/r_wall,/area/science/xenobiology)
"jaZ" = (/obj/machinery/vending/wardrobe/law_wardrobe,/obj/machinery/light{dir = 4; pixel_x = 7; pixel_y = 0},/turf/open/floor/wood,/area/lawoffice)
@@ -6365,7 +6365,7 @@
"rNe" = (/obj/effect/turf_decal/tile/red,/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/turf/open/floor/plasteel/dark/side{dir = 8},/area/security/main)
"rNg" = (/obj/machinery/atmospherics/pipe/simple/cyan/visible,/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel{dir = 8; icon_state = "floor_trim"},/area/engine/atmos)
"rNj" = (/obj/machinery/power/apc{areastring = "/area/crew_quarters/fitness"; name = "Fitness Room APC"; pixel_y = -24},/obj/structure/cable,/turf/open/floor/wood,/area/crew_quarters/fitness)
-"rNv" = (/obj/structure/flora/crystal/small/pile,/obj/structure/flora/crystal/small/growth{icon_state = "crystalgrowth3"},/turf/open/indestructible/layenia/crystal/garden,/area/layenia)
+"rNv" = (/obj/structure/flora/crystal/small/pile,/obj/structure/flora/crystal/small/growth{icon_state = "crystalgrowth3"},/turf/open/indestructible/layenia/crystal/garden,/area/crew_quarters/heads/hop)
"rNy" = (/obj/structure/toilet{dir = 4},/obj/machinery/light{dir = 8; pixel_x = -7; pixel_y = 0},/turf/open/floor/plasteel/freezer,/area/crew_quarters/toilet)
"rNz" = (/obj/structure/table/reinforced,/obj/machinery/keycard_auth{pixel_x = 3; pixel_y = 5},/obj/effect/turf_decal/tile/green,/obj/effect/turf_decal/tile/green{dir = 4},/obj/effect/turf_decal/tile/blue{dir = 1},/turf/open/floor/plasteel/white/corner{dir = 8},/area/bridge)
"rNF" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/turf/open/floor/plasteel/white/corner{dir = 1},/area/science/research)
@@ -7304,7 +7304,7 @@
"ulb" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8; layer = 2.9},/obj/machinery/conveyor{id = "gasstor"},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/open/floor/plating,/area/engine/engineering)
"ulm" = (/obj/structure/flora/crystal/medium/growth{icon_state = "crystalgrowth1"},/turf/open/indestructible/layenia/crystal/garden,/area/crew_quarters/heads/hor)
"ulp" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/plasteel/dark,/area/maintenance/disposal/incinerator)
-"ulL" = (/obj/structure/cable/yellow{icon_state = "1-2"},/obj/structure/cable/yellow{icon_state = "1-8"},/obj/machinery/atmospherics/components/unary/vent_pump/on{dir = 8},/obj/machinery/light{dir = 1; pixel_y = 16},/obj/item/twohanded/required/kirbyplants/photosynthetic{pixel_y = 10},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat/hallway"; name = "Chamber Hallway Turret Control"; pixel_x = 32; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/structure/extinguisher_cabinet{pixel_x = 27},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat/hallway)
+"ulL" = (/obj/structure/cable/yellow{icon_state = "1-2"},/obj/structure/cable/yellow{icon_state = "1-8"},/obj/machinery/atmospherics/components/unary/vent_pump/on{dir = 8},/obj/machinery/light{dir = 1; pixel_y = 16},/obj/item/twohanded/required/kirbyplants/photosynthetic{pixel_y = 10},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat_interior"; name = "Chamber Hallway Turret Control"; pixel_x = 32; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/structure/extinguisher_cabinet{pixel_x = 27},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat/hallway)
"ulM" = (/obj/machinery/vending/wardrobe/chem_wardrobe,/obj/effect/turf_decal/tile/yellow{dir = 1},/obj/effect/turf_decal/tile/yellow{dir = 8},/obj/effect/turf_decal/tile/yellow,/turf/open/floor/plasteel/white,/area/medical/chemistry)
"umu" = (/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/turf/open/floor/plasteel/white,/area/medical/medbay/central)
"umv" = (/obj/structure/cable{icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/turf/open/floor/plasteel,/area/security/main)
diff --git a/_maps/shuttles/emergency_imfedupwiththisworld.dmm b/_maps/shuttles/emergency_imfedupwiththisworld.dmm
index e0e86815..b025f092 100644
--- a/_maps/shuttles/emergency_imfedupwiththisworld.dmm
+++ b/_maps/shuttles/emergency_imfedupwiththisworld.dmm
@@ -20,8 +20,8 @@
"t" = (/obj/structure/table/reinforced,/obj/effect/turf_decal/tile/bar,/obj/effect/turf_decal/tile/bar{dir = 1},/turf/open/floor/plasteel,/area/shuttle/escape)
"u" = (/obj/machinery/light{dir = 8},/turf/open/floor/wood,/area/shuttle/escape)
"v" = (/obj/structure/chair/office/dark,/turf/open/floor/wood,/area/shuttle/escape)
-"w" = (/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/blood/drip,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/mob_spawn/human/corpse,/obj/item/gun/ballistic/automatic/pistol/m1911,/obj/machinery/light/small{dir = 8},/obj/item/reagent_containers/food/snacks/cakeslice/birthday,/turf/open/floor/carpet,/area/shuttle/escape)
-"x" = (/obj/structure/bed,/obj/item/bedsheet/red,/obj/item/paper/fluff/shuttles/daniel,/turf/open/floor/carpet,/area/shuttle/escape)
+"w" = (/obj/machinery/light/small{dir = 8},/mob/living/simple_animal/bot/hugbot,/turf/open/floor/carpet,/area/shuttle/escape)
+"x" = (/obj/structure/bed,/obj/item/bedsheet/red,/turf/open/floor/carpet,/area/shuttle/escape)
"y" = (/obj/item/twohanded/required/kirbyplants,/turf/open/floor/wood,/area/shuttle/escape)
"z" = (/obj/structure/table/wood,/obj/item/papercutter,/turf/open/floor/wood,/area/shuttle/escape)
"A" = (/obj/structure/table/wood,/obj/machinery/computer/libraryconsole/bookmanagement,/turf/open/floor/wood,/area/shuttle/escape)
diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index d8b5ab0b..36966d0a 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -80,6 +80,7 @@
#define ADMIN_PUNISHMENT_NUGGET "Nugget"
#define ADMIN_PUNISHMENT_BREADIFY ":b:read"
#define ADMIN_PUNISHMENT_BOOKIFY "Bookify"
+#define ADMIN_PUNISHMENT_BONK "Bonk"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index 24d381d1..eb9ed377 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -28,7 +28,9 @@
#define ITEM_SLOT_POCKET (1<<11) // this is to allow items with a w_class of WEIGHT_CLASS_NORMAL or WEIGHT_CLASS_BULKY to fit in pockets.
#define ITEM_SLOT_DENYPOCKET (1<<12) // this is to deny items with a w_class of WEIGHT_CLASS_SMALL or WEIGHT_CLASS_TINY to fit in pockets.
#define ITEM_SLOT_NECK (1<<13)
-#define ITEM_SLOT_SUITSTORE (1<<14)
+#define ITEM_SLOT_HANDS (1<<14)
+#define ITEM_SLOT_BACKPACK (1<<15)
+#define ITEM_SLOT_SUITSTORE (1<<16)
//SLOTS
#define SLOT_BACK 1
@@ -86,6 +88,10 @@
. = ITEM_SLOT_ICLOTHING
if(SLOT_L_STORE, SLOT_R_STORE)
. = ITEM_SLOT_POCKET
+ if(SLOT_HANDS)
+ . = ITEM_SLOT_HANDS
+ if(SLOT_IN_BACKPACK)
+ . = ITEM_SLOT_BACKPACK
if(SLOT_S_STORE)
. = ITEM_SLOT_SUITSTORE
diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm
index 952f4021..5ce2bd13 100644
--- a/code/__HELPERS/_cit_helpers.dm
+++ b/code/__HELPERS/_cit_helpers.dm
@@ -158,6 +158,17 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
return FALSE
return TRUE
+/mob/living/carbon/proc/is_butt_exposed(var/list/L)
+ if(!L)
+ L = get_equipped_items()
+ for(var/obj/item/I in L)
+ if(I.body_parts_covered & GROIN)
+ if(!I.do_not_cover_butt)
+ return FALSE
+ else
+ return TRUE
+ return TRUE
+
/mob/living/carbon/proc/is_chest_exposed(var/list/L)
if(!L)
L = get_equipped_items()
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index ce17243b..af7e92b1 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -183,6 +183,7 @@
"cock_shape" = pick(GLOB.cock_shapes_list),
"cock_length" = 6,
"belly_size" = 1,
+ "butt_size" = 1,
"cock_girth_ratio" = COCK_GIRTH_RATIO_DEF,
"cock_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"has_sheath" = FALSE,
@@ -192,6 +193,7 @@
"inflatable_belly" = FALSE,
"belly_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"has_balls" = FALSE,
+ "has_anus" = FALSE,
"balls_internal" = FALSE,
"balls_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"balls_amount" = 2,
diff --git a/code/datums/components/anti_magic.dm b/code/datums/components/anti_magic.dm
index e9133244..6f289af1 100644
--- a/code/datums/components/anti_magic.dm
+++ b/code/datums/components/anti_magic.dm
@@ -2,12 +2,13 @@
var/magic = FALSE
var/holy = FALSE
var/psychic = FALSE
+ var/allowed_slots = ~ITEM_SLOT_BACKPACK
var/charges = INFINITY
var/blocks_self = TRUE
var/datum/callback/reaction
var/datum/callback/expire
-/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire)
+/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _allowed_slots, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire)
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
@@ -19,6 +20,8 @@
magic = _magic
holy = _holy
psychic = _psychic
+ if(_allowed_slots)
+ allowed_slots = _allowed_slots
if(!isnull(_charges))
charges = _charges
blocks_self = _blocks_self
@@ -26,6 +29,9 @@
expire = _expire
/datum/component/anti_magic/proc/on_equip(datum/source, mob/equipper, slot)
+ if(!CHECK_BITFIELD(allowed_slots, slotdefine2slotbit(slot))) //Check that the slot is valid for antimagic
+ UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC)
+ return
RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect, TRUE)
/datum/component/anti_magic/proc/on_drop(datum/source, mob/user)
diff --git a/code/datums/components/phantomthief.dm b/code/datums/components/phantomthief.dm
index ff1c4893..7afe6499 100644
--- a/code/datums/components/phantomthief.dm
+++ b/code/datums/components/phantomthief.dm
@@ -7,33 +7,24 @@
var/filter_x
var/filter_y
var/filter_size
- var/filter_border
var/filter_color
-/datum/component/wearertargeting/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _border = 0, _color = "#E62111", list/_valid_slots = list(SLOT_GLASSES))
+/datum/component/wearertargeting/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _color = "#E62111", list/_valid_slots = list(SLOT_GLASSES))
. = ..()
if(. == COMPONENT_INCOMPATIBLE)
return
filter_x = _x
filter_y = _y
filter_size = _size
- filter_border = _border
filter_color = _color
valid_slots = _valid_slots
/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(datum/source, mob/user, combatmodestate)
- if(istype(user))
- var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color)
- if(!combatmodestate)
- user.filters -= thefilter
- else
- user.filters += thefilter
-
-/datum/component/wearertargeting/phantomthief/proc/stripdesiredfilter(mob/user)
- if(istype(user))
- var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color)
- user.filters -= thefilter
+ if(!combatmodestate)
+ user.remove_filter("phantomthief")
+ else
+ user.add_filter("phantomthief", 4, list(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, color = filter_color))
/datum/component/wearertargeting/phantomthief/on_drop(datum/source, mob/user)
. = ..()
- stripdesiredfilter(user)
+ user.remove_filter("phantomthief")
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 9f9fe9de..65b1ce35 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -26,10 +26,10 @@
/datum/proc/vv_get_dropdown()
. = list()
. += "---"
- .["Call Proc"] = "?_src_=vars;[HrefToken()];proc_call=[REF(src)]"
- .["Mark Object"] = "?_src_=vars;[HrefToken()];mark_object=[REF(src)]"
- .["Delete"] = "?_src_=vars;[HrefToken()];delete=[REF(src)]"
- .["Show VV To Player"] = "?_src_=vars;[HrefToken(TRUE)];expose=[REF(src)]"
+ .["Call Proc"] = "?_src_=vars;[HrefToken()];proc_call=\ref[src]"
+ .["Mark Object"] = "?_src_=vars;[HrefToken()];mark_object=\ref[src]"
+ .["Delete"] = "?_src_=vars;[HrefToken()];delete=\ref[src]"
+ .["Show VV To Player"] = "?_src_=vars;[HrefToken(TRUE)];expose=\ref[src]"
/datum/proc/on_reagent_change(changetype)
@@ -54,7 +54,7 @@
return
var/title = ""
- var/refid = REF(D)
+ var/refid = "\ref[D]"
var/icon/sprite
var/hash
@@ -62,8 +62,6 @@
if (!islist)
type = D.type
-
-
if(istype(D, /atom))
var/atom/AT = D
if(AT.icon && AT.icon_state)
@@ -411,7 +409,7 @@
/client/proc/vv_update_display(datum/D, span, content)
- src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
+ src << output("[span]:[content]", "variables\ref[D].browser:replace_span")
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
@@ -424,9 +422,9 @@
name = DA[name] //name is really the index until this line
else
value = DA[name]
- header = "
(E) (C) (-) "
+ header = "(E) (C) (-) "
else
- header = "(E) (C) (M) "
+ header = "(E) (C) (M) "
else
header = ""
@@ -441,7 +439,7 @@
#ifdef VARSICON
var/icon/I = new/icon(value)
var/rnd = rand(1,10000)
- var/rname = "tmp[REF(I)][rnd].png"
+ var/rname = "tmp\ref[I][rnd].png"
usr << browse_rsc(I, rname)
item = "[VV_HTML_ENCODE(name)] = ([value])
"
#else
@@ -454,9 +452,9 @@
else if (istype(value, /datum))
var/datum/D = value
if ("[D]" != "[D.type]") //if the thing as a name var, lets use it.
- item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D] [D.type]"
+ item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D] [D.type]"
else
- item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D.type]"
+ item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D.type]"
else if (islist(value))
var/list/L = value
@@ -474,9 +472,9 @@
items += debug_variable(key, val, level + 1, sanitize = sanitize)
- item = "[VV_HTML_ENCODE(name)] = /list ([L.len])"
+ item = "[VV_HTML_ENCODE(name)] = /list ([L.len])"
else
- item = "[VV_HTML_ENCODE(name)] = /list ([L.len])"
+ item = "[VV_HTML_ENCODE(name)] = /list ([L.len])"
else if (name in GLOB.bitfields)
var/list/flags = list()
@@ -588,7 +586,7 @@
var/prompt = alert("Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anything nor open nested vv windows unless they themselves are an admin)", "Confirm", "Yes", "No")
if (prompt != "Yes" || !usr.client)
return
- message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window")
+ message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window")
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [thing]")
to_chat(C, "[usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window")
C.debug_variables(thing)
diff --git a/code/datums/elements/squish.dm b/code/datums/elements/squish.dm
new file mode 100644
index 00000000..823d391e
--- /dev/null
+++ b/code/datums/elements/squish.dm
@@ -0,0 +1,28 @@
+#define SHORT 5/7
+#define TALL 7/5
+
+/datum/element/squish
+ element_flags = ELEMENT_DETACH
+
+/datum/element/squish/Attach(datum/target, duration)
+ . = ..()
+ if(!iscarbon(target))
+ return ELEMENT_INCOMPATIBLE
+
+ var/mob/living/carbon/C = target
+ var/was_lying = (C.lying != 0)
+ addtimer(CALLBACK(src, .proc/Detach, C, was_lying), duration)
+
+ C.transform = C.transform.Scale(TALL, SHORT)
+
+/datum/element/squish/Detach(mob/living/carbon/C, was_lying)
+ . = ..()
+ if(istype(C))
+ var/is_lying = (C.lying != 0)
+ if(was_lying == is_lying)
+ C.transform = C.transform.Scale(SHORT, TALL)
+ else
+ C.transform = C.transform.Scale(TALL, SHORT)
+
+#undef SHORT
+#undef TALL
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 237afdd5..86145409 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -223,7 +223,7 @@
/datum/status_effect/belligerent/proc/do_movement_toggle(force_damage)
var/number_legs = owner.get_num_legs(FALSE)
- if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.anti_magic_check() && number_legs)
+ if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.anti_magic_check(chargecost = 0) && number_legs)
if(force_damage || owner.m_intent != MOVE_INTENT_WALK)
if(GLOB.ratvar_awakens)
owner.Knockdown(20)
@@ -316,7 +316,7 @@
if(owner.confused)
owner.confused = 0
severity = 0
- else if(!owner.anti_magic_check() && owner.stat != DEAD && severity)
+ else if(!owner.anti_magic_check(chargecost = 0) && owner.stat != DEAD && severity)
var/static/hum = get_sfx('sound/effects/screech.ogg') //same sound for every proc call
if(owner.getToxLoss() > MANIA_DAMAGE_TO_CONVERT)
if(is_eligible_servant(owner))
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 3bc00c84..43ac13fb 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -78,6 +78,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/strip_delay = 40 //In deciseconds, how long an item takes to remove from another person
var/breakouttime = 0
var/list/materials
+ var/reskinned = FALSE
var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
var/list/species_exception = null // list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item
@@ -123,6 +124,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
//Hyper economy
var/price = 0
+ //Hyper, for clothes that reveal your behind! butt stuff, you know how it is.
+ var/do_not_cover_butt = FALSE
/obj/item/Initialize()
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 463bc809..4a0fa867 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -35,6 +35,24 @@
drop_sound = 'sound/items/handling/multitool_drop.ogg'
pickup_sound = 'sound/items/handling/multitool_pickup.ogg'
+/obj/item/multitool/chaplain
+ name = "\improper hypertool"
+ desc = "Used for pulsing wires to test which to cut. Also emits microwaves to fry some brains!"
+ damtype = BRAIN
+ force = 18
+ armour_penetration = 35
+ hitsound = 'sound/effects/sparks4.ogg'
+ var/chaplain_spawnable = TRUE
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
+ throw_speed = 3
+ throw_range = 4
+ throwforce = 10
+ obj_flags = UNIQUE_RENAME
+
+/obj/item/multitool/chaplain/Initialize()
+ . = ..()
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
+
/obj/item/multitool/examine(mob/user)
. = ..()
if(selected_io)
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 56237527..6a144a01 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -547,7 +547,9 @@ GENE SCANNER
var/turf/location = user.loc
if(!istype(location))
return
+ scan_turf(user, location)
+/obj/item/analyzer/proc/scan_turf(mob/user, turf/location)
var/datum/gas_mixture/environment = location.return_air()
var/pressure = environment.return_pressure()
@@ -658,6 +660,20 @@ GENE SCANNER
amount += inaccurate
return DisplayTimeText(max(1,amount))
+/obj/item/analyzer/ranged
+ desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function."
+ name = "long-range analyzer"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "ranged_analyzer"
+
+/obj/item/analyzer/ranged/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ . = ..()
+ if(target.tool_act(user, src, tool_behaviour))
+ return
+ // Tool act didn't scan it, so let's get it's turf.
+ var/turf/location = get_turf(target)
+ scan_turf(user, location)
+
/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src)
var/icon = target
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].")
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index 93da4a30..9c597187 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -229,12 +229,12 @@
throwforce = 10
w_class = WEIGHT_CLASS_TINY
obj_flags = UNIQUE_RENAME
- var/reskinned = FALSE
var/chaplain_spawnable = TRUE
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/nullrod/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, TRUE)
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
/obj/item/nullrod/suicide_act(mob/user)
user.visible_message("[user] is killing [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to get closer to god!")
@@ -248,7 +248,12 @@
if(GLOB.holy_weapon_type)
return
var/obj/item/holy_weapon
- var/list/holy_weapons_list = subtypesof(/obj/item/nullrod)
+ var/list/holy_weapons_list = subtypesof(/obj/item/nullrod) + list(
+ /obj/item/twohanded/dualsaber/hypereutactic/chaplain,
+ /obj/item/gun/energy/laser/redtag/hitscan/chaplain,
+ /obj/item/multitool/chaplain,
+ /obj/item/melee/baseball_bat/chaplain
+ )
var/list/display_names = list()
var/list/nullrod_icons = list()
for(var/V in holy_weapons_list)
@@ -289,6 +294,13 @@
return FALSE
return TRUE
+/obj/item/nullrod/proc/jedi_spin(mob/living/user)
+ for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
+ user.setDir(i)
+ if(i == WEST)
+ user.emote("flip")
+ sleep(1)
+
/obj/item/nullrod/godhand
icon_state = "disintegrate"
item_state = "disintegrate"
@@ -344,7 +356,6 @@
sharpness = IS_SHARP
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/nullrod/claymore/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == PROJECTILE_ATTACK)
@@ -541,7 +552,6 @@
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_HUGE
attack_verb = list("smashed", "bashed", "hammered", "crunched")
- total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/nullrod/chainsaw
name = "chainsaw hand"
@@ -606,6 +616,7 @@
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
slot_flags = ITEM_SLOT_BELT
+ force = 12
reach = 2
attack_verb = list("whipped", "lashed")
hitsound = 'sound/weapons/chainhit.ogg'
@@ -682,6 +693,44 @@
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
+/obj/item/nullrod/claymore/bostaff/attack(mob/target, mob/living/user)
+ add_fingerprint(user)
+ if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
+ to_chat(user, "You club yourself over the head with [src].")
+ user.Knockdown(60)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
+ else
+ user.take_bodypart_damage(2*force)
+ return
+ if(iscyborg(target))
+ return ..()
+ if(!isliving(target))
+ return ..()
+ var/mob/living/carbon/C = target
+ if(C.stat || C.health < 0 || C.staminaloss > 130 )
+ to_chat(user, "It would be dishonorable to attack a foe while they cannot retaliate.")
+ return
+ if(user.a_intent == INTENT_DISARM)
+ if(!ishuman(target))
+ return ..()
+ var/mob/living/carbon/human/H = target
+ var/list/fluffmessages = list("[user] clubs [H] with [src]!", \
+ "[user] smacks [H] with the butt of [src]!", \
+ "[user] broadsides [H] with [src]!", \
+ "[user] smashes [H]'s head with [src]!", \
+ "[user] beats [H] with front of [src]!", \
+ "[user] twirls and slams [H] with [src]!")
+ H.visible_message("[pick(fluffmessages)]", \
+ "[pick(fluffmessages)]")
+ playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, 1, -1)
+ H.adjustStaminaLoss(rand(12,18))
+ if(prob(25))
+ (INVOKE_ASYNC(src, .proc/jedi_spin, user))
+ else
+ return ..()
+
/obj/item/nullrod/tribal_knife
icon_state = "crysknife"
item_state = "crysknife"
@@ -695,7 +744,6 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
item_flags = SLOWS_WHILE_IN_HAND
- total_mass = TOTAL_MASS_NORMAL_ITEM
/obj/item/nullrod/tribal_knife/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index f76c1a27..0196daee 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -86,7 +86,7 @@
new /obj/item/multitool(src)
new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
new /obj/item/extinguisher/mini(src)
- new /obj/item/analyzer(src)
+ new /obj/item/analyzer/ranged(src)
//much roomier now that we've managed to remove two tools
/obj/item/storage/belt/utility/full/PopulateContents()
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 71a1ded2..c4a21900 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -517,6 +517,19 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
var/homerun_able = 0
total_mass = 2.7 //a regular wooden major league baseball bat weighs somewhere between 2 to 3.4 pounds, according to google
+/obj/item/melee/baseball_bat/chaplain
+ name = "blessed baseball bat"
+ desc = "There ain't a cult in the league that can withstand a swatter."
+ force = 14
+ throwforce = 14
+ obj_flags = UNIQUE_RENAME
+ var/chaplain_spawnable = TRUE
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
+
+/obj/item/melee/baseball_bat/chaplain/Initialize()
+ . = ..()
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
+
/obj/item/melee/baseball_bat/homerun
name = "home run bat"
desc = "This thing looks dangerous... Dangerously good at baseball, that is."
diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm
index b3c19334..9c1859df 100644
--- a/code/game/objects/structures/traps.dm
+++ b/code/game/objects/structures/traps.dm
@@ -65,6 +65,8 @@
var/mob/M = AM
if(M.mind in immune_minds)
return
+ if(M.anti_magic_check())
+ flare()
if(charges <= 0)
return
flare()
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 1f780448..01d1902f 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -1274,7 +1274,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
ADMIN_PUNISHMENT_FAKEBWOINK,
ADMIN_PUNISHMENT_NUGGET,
ADMIN_PUNISHMENT_BREADIFY,
- ADMIN_PUNISHMENT_BOOKIFY)
+ ADMIN_PUNISHMENT_BOOKIFY,
+ ADMIN_PUNISHMENT_BONK)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1393,6 +1394,10 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
addtimer(CALLBACK(GLOBAL_PROC, .proc/bookify, target), BOOKIFY_TIME)
playsound(target, 'hyperstation/sound/misc/bookify.ogg', 60, 1)
#undef BOOKIFY_TIME
+ if(ADMIN_PUNISHMENT_BONK)
+ playsound(target, 'hyperstation/sound/misc/bonk.ogg', 100, 1)
+ target.AddElement(/datum/element/squish, 60 SECONDS)
+ to_chat(target, "Bonk.")
punish_log(target, punishment)
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 603dd433..ca336db4 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -343,8 +343,8 @@
if(QDELETED(G))
return
- if(istype(C.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
- to_chat(user, "Your target seems to have some sort of protective headgear on, blocking the message from being sent!")
+ if(C.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(user, "Your target seems to have some sort of tinfoil protection on, blocking the message from being sent!")
return
G.mind_control(command, user)
@@ -520,10 +520,10 @@ Congratulations! You are now trained for invasive xenobiology research!"}
/obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
if(L.incapacitated(TRUE, TRUE))
- if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
- to_chat(user, "The specimen's protective headgear is interfering with the sleep inducement!")
- L.visible_message("[user] tried to induced sleep in [L] with [src], but [L.p_their()] headgear protected [L.p_them()]!", \
- "You feel a strange wave of heavy drowsiness wash over you, but your headgear deflects most of it!")
+ if(L.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(user, "The specimen's tinfoil protection is interfering with the sleep inducement!")
+ L.visible_message("[user] tried to induced sleep in [L] with [src], but [L.p_their()] tinfoil protected [L.p_them()]!", \
+ "You feel a strange wave of heavy drowsiness wash over you, but your tinfoil protection deflects most of it!")
L.drowsyness += 2
return
L.visible_message("[user] has induced sleep in [L] with [src]!", \
@@ -532,10 +532,10 @@ Congratulations! You are now trained for invasive xenobiology research!"}
L.Sleeping(1200)
log_combat(user, L, "put to sleep")
else
- if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
- to_chat(user, "The specimen's protective headgear is completely blocking our sleep inducement methods!")
- L.visible_message("[user] tried to induce sleep in [L] with [src], but [L.p_their()] headgear completely protected [L.p_them()]!", \
- "Any sense of drowsiness is quickly diminished as your headgear deflects the effects!")
+ if(L.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(user, "The specimen's tinfoil protection is completely blocking our sleep inducement methods!")
+ L.visible_message("[user] tried to induce sleep in [L] with [src], but [L.p_their()] tinfoil completely protected [L.p_them()]!", \
+ "Any sense of drowsiness is quickly diminished as your tinfoil protection deflects the effects!")
return
L.drowsyness += 1
to_chat(user, "Sleep inducement works fully only on stunned specimens! ")
diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm
index 30b82398..6ab1e58c 100644
--- a/code/modules/antagonists/abductor/machinery/console.dm
+++ b/code/modules/antagonists/abductor/machinery/console.dm
@@ -178,8 +178,8 @@
c.console = src
/obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target)
- if(istype(target.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
- say("Subject wearing specialized protective headgear, unable to get a proper scan!")
+ if(target.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ say("Subject wearing specialized protective tinfoil gear, unable to get a proper scan!")
return
var/datum/icon_snapshot/entry = new
entry.name = target.name
diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm
index 386a463a..93d1e2af 100644
--- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm
@@ -35,7 +35,7 @@
/obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user)
. = ..()
- if(!QDELETED(target) && target.stat != DEAD && !target.anti_magic_check() && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead
+ if(!QDELETED(target) && target.stat != DEAD && !target.anti_magic_check(chargecost = 0) && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead
var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar
if(issilicon(target))
target.visible_message("[target] shudders violently at [src]'s touch!", "ERROR: Temperature rising!")
diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
index f44f67e9..fe6fe72d 100644
--- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
+++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
@@ -190,8 +190,8 @@
for(var/mob/living/L in range(1, src))
if(is_servant_of_ratvar(L))
continue
- if(L.anti_magic_check())
- var/atom/I = L.anti_magic_check()
+ var/atom/I = L.anti_magic_check()
+ if(I)
if(isitem(I))
L.visible_message("Strange energy flows into [L]'s [I.name]!", \
"Your [I.name] shields you from [src]!")
diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm
index bf50ed2b..31632b22 100644
--- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm
@@ -60,7 +60,7 @@
else
if(isliving(target))
var/mob/living/L = target
- if(!L.anti_magic_check())
+ if(!L.anti_magic_check(chargecost = 0))
if(isrevenant(L))
var/mob/living/simple_animal/revenant/R = L
if(R.revealed)
diff --git a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm
index 10c68b60..1158b02a 100644
--- a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm
@@ -53,7 +53,7 @@
/obj/structure/destructible/clockwork/taunting_trail/proc/affect_mob(mob/living/L)
if(istype(L) && !is_servant_of_ratvar(L))
- if(!L.anti_magic_check())
+ if(!L.anti_magic_check(chargecost = 0))
L.confused = min(L.confused + 15, 50)
L.dizziness = min(L.dizziness + 15, 50)
if(L.confused >= 25)
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 48a9879c..82d78480 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -62,8 +62,8 @@ Runes can either be invoked by one's self or with many different cultists. Each
if(do_after(user, 15, target = src))
to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.")
qdel(src)
- else if(istype(I, /obj/item/nullrod))
- user.say("BEGONE FOUL MAGIKS!!", forced = "nullrod")
+ else if(istype(I, /obj/item/storage/book/bible) || istype(I, /obj/item/nullrod))
+ user.say("BEGONE FOUL MAGICKS!!", forced = "bible")
to_chat(user, "You disrupt the magic of [src] with [I].")
qdel(src)
@@ -238,7 +238,7 @@ structure_check() searches for nearby cultist structures required for the invoca
to_chat(M, "You need at least two invokers to convert [convertee]!")
log_game("Offer rune failed - tried conversion with one invoker")
return 0
- if(convertee.anti_magic_check(TRUE, TRUE, FALSE, 0)) //Not chargecost because it can be spammed
+ if(convertee.anti_magic_check(TRUE, TRUE, chargecost = 0)) //Not major because it can be spammed
for(var/M in invokers)
to_chat(M, "Something is shielding [convertee]'s mind!")
log_game("Offer rune failed - convertee had anti-magic")
@@ -772,7 +772,7 @@ structure_check() searches for nearby cultist structures required for the invoca
set_light(6, 1, color)
for(var/mob/living/L in viewers(T))
if(!iscultist(L) && L.blood_volume)
- var/atom/I = L.anti_magic_check()
+ var/atom/I = L.anti_magic_check(chargecost = 0)
if(I)
if(isitem(I))
to_chat(L, "[I] suddenly burns hotly before returning to normal!")
@@ -802,7 +802,7 @@ structure_check() searches for nearby cultist structures required for the invoca
set_light(6, 1, color)
for(var/mob/living/L in viewers(T))
if(!iscultist(L) && L.blood_volume)
- if(L.anti_magic_check())
+ if(L.anti_magic_check(chargecost = 0))
continue
L.take_overall_damage(tick_damage*multiplier, tick_damage*multiplier)
if(is_servant_of_ratvar(L))
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index 2fa5306c..a3984803 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -65,7 +65,7 @@
if(target.anti_magic_check(FALSE, TRUE))
to_chat(src, "Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!")
target.visible_message("[target] slumps onto the ground.", \
- "Violets lights, dancing in your vision, receding--")
+ "Violet lights, dancing in your vision, receding--")
draining = FALSE
return
var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY)
@@ -112,7 +112,8 @@
action_background_icon_state = "bg_revenant"
notice = "revennotice"
boldnotice = "revenboldnotice"
-
+ holy_check = TRUE
+ tinfoil_check = FALSE
/obj/effect/proc_holder/spell/aoe_turf/revenant
clothes_req = 0
diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm
index c040d063..fe130349 100644
--- a/code/modules/cargo/packs/science.dm
+++ b/code/modules/cargo/packs/science.dm
@@ -208,7 +208,7 @@
/datum/supply_pack/science/hev
name = "Hazard Suit Crate"
desc = "A familiar suit from the times of interdimensional exploring. Research Directors might prefer these due to their superior radioactive protection over the standard RD suit."
- cost = 10000
+ cost = 15000
access = ACCESS_RD
contains = list(/obj/item/clothing/suit/space/hardsuit/rd/hev)
crate_name = "hazard suit crate"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index ab40a77c..42ae307a 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -134,6 +134,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"cock_shape" = "Human",
"cock_length" = 6,
"belly_size" = 1,
+ "butt_size" = 1,
"cock_girth_ratio" = COCK_GIRTH_RATIO_DEF,
"cock_color" = "fff",
"has_sheath" = FALSE,
@@ -142,6 +143,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"hide_belly" = FALSE,
"inflatable_belly" = FALSE,
"belly_color" = "fff",
+ "has_anus" = FALSE,
"has_balls" = FALSE,
"balls_internal" = FALSE,
"balls_color" = "fff",
@@ -920,6 +922,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Inflation (Climax With):[features["inflatable_belly"] == 1 ? "Yes" : "No"]"
dat += ""
+
+ dat += APPEARANCE_CATEGORY_COLUMN
+ dat += "Butt
"
+ dat += "[features["has_anus"] == TRUE ? "Yes" : "No"]"
+ if(features["has_anus"])
+ dat += "Butt Size: [features["butt_size"]]"
+ dat += ""
+
dat += ""
dat += ""
@@ -2340,6 +2350,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_bellysize)
features["belly_size"] = clamp(new_bellysize, 1, 3)
+ if("butt_size")
+ var/new_buttsize = input(user, "Butt size :\n(0-4)", "Character Preference") as num|null
+ features["butt_size"] = clamp(new_buttsize, 0, 4)
+
if("vag_shape")
var/new_shape
new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list
@@ -2502,6 +2516,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(features["has_vag"] == FALSE)
features["has_womb"] = FALSE
features["can_get_preg"] = FALSE
+ if("has_anus")
+ features["has_anus"] = !features["has_anus"]
+ if(features["has_anus"] == FALSE)
+ features["butt_size"] = 0
if("has_womb")
features["has_womb"] = !features["has_womb"]
if("can_get_preg")
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index ebd93b81..71379b48 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
-#define SAVEFILE_VERSION_MAX 23
+#define SAVEFILE_VERSION_MAX 24
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -402,6 +402,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_has_sheath"] >> features["sheath_color"]
//belly size
S["feature_belly_size"] >> features["belly_size"]
+ //belly size
+ S["feature_butt_size"] >> features["butt_size"]
//balls features
S["feature_has_balls"] >> features["has_balls"]
S["feature_balls_color"] >> features["balls_color"]
@@ -423,11 +425,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//womb features
S["feature_has_womb"] >> features["has_womb"]
S["feature_can_get_preg"] >> features["can_get_preg"] //hyperstation 13
- //balls features
+ //belly features
S["feature_has_belly"] >> features["has_belly"]
S["feature_belly_color"] >> features["belly_color"]
S["feature_hide_belly"] >> features["hide_belly"]
S["feature_inflatable_belly"] >> features["inflatable_belly"]
+ //anus features
+ S["feature_has_anus"] >> features["has_anus"]
//flavor text
//Let's make our players NOT cry desperately as we wipe their savefiles of their special snowflake texts:
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 44644962..9b63fdef 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -238,26 +238,62 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = -5,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = -5, "fire" = 0, "acid" = 0)
equip_delay_other = 140
var/datum/brain_trauma/mild/phobia/paranoia
+ var/warped = FALSE
clothing_flags = IGNORE_HAT_TOSS
+/obj/item/clothing/head/foilhat/Initialize(mapload)
+ . = ..()
+ if(!warped)
+ AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, 6, TRUE, null, CALLBACK(src, .proc/warp_up))
+ else
+ warp_up()
+
/obj/item/clothing/head/foilhat/equipped(mob/living/carbon/human/user, slot)
- ..()
- if(slot == SLOT_HEAD)
- if(paranoia)
- QDEL_NULL(paranoia)
- paranoia = new()
- user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies")
- to_chat(user, "As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. ")
+ . = ..()
+ if(slot != SLOT_HEAD || warped)
+ return
+ if(paranoia)
+ QDEL_NULL(paranoia)
+ paranoia = new()
+ user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies")
+ to_chat(user, "As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. ")
+
+/obj/item/clothing/head/foilhat/MouseDrop(atom/over_object)
+ //God Im sorry
+ if(!warped && iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ if(src == C.head)
+ to_chat(C, "Why would you want to take this off? Do you want them to get into your mind?!")
+ return
+ return ..()
/obj/item/clothing/head/foilhat/dropped(mob/user)
- ..()
+ . = ..()
if(paranoia)
QDEL_NULL(paranoia)
+/obj/item/clothing/head/foilhat/proc/warp_up()
+ name = "scorched tinfoil hat"
+ desc = "A badly warped up hat. Quite unprobable this will still work against any of fictional and contemporary dangers it used to."
+ warped = TRUE
+ if(!isliving(loc) || !paranoia)
+ return
+ var/mob/living/target = loc
+ if(target.get_item_by_slot(SLOT_HEAD) != src)
+ return
+ QDEL_NULL(paranoia)
+ if(!target.IsUnconscious())
+ to_chat(target, "Your zealous conspirationism rapidly dissipates as the donned hat warps up into a ruined mess. All those theories starting to sound like nothing but a ridicolous fanfare.")
+
/obj/item/clothing/head/foilhat/attack_hand(mob/user)
- if(iscarbon(user))
+ if(!warped && iscarbon(user))
var/mob/living/carbon/C = user
if(src == C.head)
to_chat(user, "Why would you want to take this off? Do you want them to get into your mind?!")
return
- ..()
+ return ..()
+
+/obj/item/clothing/head/foilhat/microwave_act(obj/machinery/microwave/M)
+ . = ..()
+ if(!warped)
+ warp_up()
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 83315a40..560455b5 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -432,7 +432,7 @@
/obj/item/clothing/suit/space/hardsuit/wizard/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, FALSE)
+ AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE)
//Medical hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/medical
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index dd91258f..85b55607 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -368,6 +368,10 @@ Contains:
resistance_flags = FIRE_PROOF
mutantrace_variation = NO_MUTANTRACE_VARIATION
+/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize()
+ . = ..()
+ AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD)
+
/obj/item/clothing/suit/space/hardsuit/ert/paranormal
name = "paranormal response team suit"
desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats."
@@ -380,7 +384,7 @@ Contains:
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, TRUE)
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING)
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
name = "inquisitor's hardsuit"
diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm
index 25c67cc3..c59a8004 100644
--- a/code/modules/fields/timestop.dm
+++ b/code/modules/fields/timestop.dm
@@ -133,6 +133,7 @@
/datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L)
if(L.anti_magic_check(check_anti_magic, check_holy))
+ immune += L
return
L.Stun(20, 1, 1)
frozen_mobs[L] = L.anchored
diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm
index adf710d9..54cfd0bd 100644
--- a/code/modules/hydroponics/grown/melon.dm
+++ b/code/modules/hydroponics/grown/melon.dm
@@ -64,14 +64,14 @@
var/uses = 1
if(seed)
uses = round(seed.potency / 20)
- AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_HANDS, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god
/obj/item/reagent_containers/food/snacks/grown/holymelon/proc/block_magic(mob/user, major)
if(major)
- visible_message("[src] hums slightly, and seems to decay a bit.")
+ to_chat(user, "[src] hums slightly, and seems to decay a bit.")
/obj/item/reagent_containers/food/snacks/grown/holymelon/proc/expire(mob/user)
- visible_message("[src] rapidly turns into ash!")
+ to_chat(user, "[src] rapidly turns into ash!")
qdel(src)
new /obj/effect/decal/cleanable/ash(drop_location())
diff --git a/code/modules/jobs/job_types/civilian_chaplain.dm b/code/modules/jobs/job_types/civilian_chaplain.dm
index 1a74eec9..5f3daf1b 100644
--- a/code/modules/jobs/job_types/civilian_chaplain.dm
+++ b/code/modules/jobs/job_types/civilian_chaplain.dm
@@ -12,6 +12,7 @@ Chaplain
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#dddddd"
+ custom_spawn_text = "You're playing a job that is essential for when the station deals with paranormal threats. While you have access to weapons, armor and tools such as your nullrod and bible, this does not mean you should hunt those threats unless warranted. If you have any questions, don't hesitate to ask mentors."
outfit = /datum/outfit/job/chaplain
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index 509caf81..e013137b 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -95,8 +95,14 @@ Doesn't work on other aliens/AI.*/
var/mob/living/M = input("Select who to whisper to:","Whisper to?",null) as null|mob in options
if(!M)
return 0
+ if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(user, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.")
+ return FALSE
var/msg = sanitize(input("Message:", "Alien Whisper") as text|null)
if(msg)
+ if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(user, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.")
+ return
log_directed_talk(user, M, msg, LOG_SAY, tag="alien whisper")
to_chat(M, "You hear a strange, alien voice in your head...[msg]")
to_chat(user, "You said: \"[msg]\" to [M]")
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 6d811bdc..137cca07 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -603,6 +603,8 @@
return FALSE
if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice
return FALSE
+ if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ return FALSE
if(M in linked_mobs)
return FALSE
linked_mobs.Add(M)
@@ -688,9 +690,14 @@
var/mob/living/M = input("Select who to send your message to:","Send thought to?",null) as null|mob in options
if(!M)
return
-
+ if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(H, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.")
+ return
var/msg = sanitize(input("Message:", "Telepathy") as text|null)
if(msg)
+ if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ to_chat(H, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.")
+ return
log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy")
to_chat(M, "You hear an alien voice in your head... [msg]")
to_chat(H, "You telepathically said: \"[msg]\" to [M]")
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 6c1ac8b1..17388825 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -88,7 +88,7 @@
to_chat(H, "[victim] doesn't have blood!")
return
V.drain_cooldown = world.time + 30
- if(victim.anti_magic_check(FALSE, TRUE))
+ if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0))
to_chat(victim, "[H] tries to bite you, but stops before touching you!")
to_chat(H, "[victim] is blessed! You stop just in time to avoid catching fire.")
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index c36aa535..d457a3d5 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -976,7 +976,7 @@
apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), EFFECT_IRRADIATE, blocked)
-/mob/living/anti_magic_check(magic = TRUE, holy = FALSE)
+/mob/living/anti_magic_check(magic = TRUE, holy = FALSE, chargecost = 1, self = FALSE)
. = ..()
if(.)
return
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 5c99826d..fac2f8d3 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -804,15 +804,17 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
if(client)
client << output(null, "statbrowser:check_spells")
-/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE)
- if(!magic && !holy)
+/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE)
+ if(!magic && !holy && !tinfoil)
return
var/list/protection_sources = list()
- if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, magic, holy, protection_sources) & COMPONENT_BLOCK_MAGIC)
+ if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, src, magic, holy, tinfoil, chargecost, self, protection_sources) & COMPONENT_BLOCK_MAGIC)
if(protection_sources.len)
return pick(protection_sources)
else
return src
+ if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY)))
+ return src
//You can buckle on mobs if you're next to them since most are dense
/mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm
index aa0cda91..f0aa9eae 100644
--- a/code/modules/projectiles/ammunition/energy/laser.dm
+++ b/code/modules/projectiles/ammunition/energy/laser.dm
@@ -59,6 +59,9 @@
/obj/item/ammo_casing/energy/laser/redtag/hitscan
projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan
+/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy
+ projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan/holy
+
/obj/item/ammo_casing/energy/xray
projectile_type = /obj/item/projectile/beam/xray
e_cost = 50
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 353983e0..fd28694e 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -159,3 +159,65 @@
/obj/item/gun/energy/laser/redtag/hitscan
ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan)
+
+/obj/item/gun/energy/laser/redtag/hitscan/chaplain
+ name = "\improper holy lasrifle"
+ desc = "A lasrifle from the old Imperium. This one seems to be blessed by techpriests."
+ icon_state = "LaserAK"
+ item_state = null
+ force = 14
+ pin = /obj/item/firing_pin/holy
+ icon = 'modular_citadel/icons/obj/guns/VGguns.dmi'
+ ammo_x_offset = 4
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy)
+ lefthand_file = 'modular_citadel/icons/mob/citadel/guns_lefthand.dmi'
+ righthand_file = 'modular_citadel/icons/mob/citadel/guns_righthand.dmi'
+ var/chaplain_spawnable = TRUE
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
+ throw_speed = 3
+ throw_range = 4
+ throwforce = 10
+ obj_flags = UNIQUE_RENAME
+
+/obj/item/gun/energy/laser/redtag/hitscan/chaplain/Initialize()
+ . = ..()
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
+
+/obj/item/gun/energy/laser/redtag/hitscan/chaplain/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer)
+ if(!ishuman(user) || !ishuman(target))
+ return
+
+ if(semicd)
+ return
+
+ if(user == target)
+ target.visible_message("[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger...", \
+ "You stick [src] in your mouth, ready to pull the trigger...")
+ else
+ target.visible_message("[user] points [src] at [target]'s head, ready to pull the trigger...", \
+ "[user] points [src] at your head, ready to pull the trigger...")
+
+ semicd = TRUE
+
+ if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
+ if(user)
+ if(user == target)
+ user.visible_message("[user] decided not to shoot.")
+ else if(target && target.Adjacent(user))
+ target.visible_message("[user] has decided to spare [target]", "[user] has decided to spare your life!")
+ semicd = FALSE
+ return
+
+ semicd = FALSE
+
+ target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!")
+
+ playsound('sound/weapons/dink.ogg', 30, 1)
+
+ if((iscultist(target)) || (is_servant_of_ratvar(target)))
+ chambered.BB.damage *= 1500
+
+ else if(chambered && chambered.BB)
+ chambered.BB.damage *= 5
+
+ process_fire(target, user, TRUE, params)
diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm
index e62392ff..f724f982 100644
--- a/code/modules/projectiles/guns/magic.dm
+++ b/code/modules/projectiles/guns/magic.dm
@@ -9,6 +9,7 @@
fire_sound = 'sound/weapons/emitter.ogg'
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_HUGE
+ var/checks_antimagic = FALSE
var/max_charges = 6
var/charges = 0
var/recharge_rate = 4
@@ -31,6 +32,9 @@
return
else
no_den_usage = 0
+ if(checks_antimagic && user.anti_magic_check(TRUE, FALSE, FALSE, 0, TRUE))
+ to_chat(user, "Something is interfering with [src].")
+ return
. = ..()
/obj/item/gun/magic/can_shoot()
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index d5815205..52236ab6 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -87,14 +87,17 @@
max_charges = 10 //10, 5, 5, 4
/obj/item/gun/magic/wand/resurrection/zap_self(mob/living/user)
+ ..()
+ charges--
+ if(user.anti_magic_check())
+ user.visible_message("[src] has no effect on [user]!")
+ return
user.revive(full_heal = 1)
if(iscarbon(user))
var/mob/living/carbon/C = user
C.regenerate_limbs()
C.regenerate_organs()
to_chat(user, "You feel great!")
- charges--
- ..()
/obj/item/gun/magic/wand/resurrection/debug //for testing
name = "debug wand of healing"
diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm
index 99102a2d..381ec09c 100644
--- a/code/modules/projectiles/pins.dm
+++ b/code/modules/projectiles/pins.dm
@@ -186,6 +186,15 @@
desc = "This is a DNA-locked firing pin which only authorizes one user. Attempt to fire once to DNA-link. It has a small explosive charge on it."
selfdestruct = TRUE
+/obj/item/firing_pin/holy
+ name = "blessed pin"
+ desc = "A firing pin that only responds to those who are holier than thou."
+
+/obj/item/firing_pin/holy/pin_auth(mob/living/user)
+ if(user.mind.isholy)
+ return TRUE
+ return FALSE
+
// Laser tag pins
/obj/item/firing_pin/tag
name = "laser tag firing pin"
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 5065eed6..43ca5cfd 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -151,6 +151,11 @@
/obj/item/projectile/beam/lasertag/redtag/hitscan
hitscan = TRUE
+/obj/item/projectile/beam/lasertag/redtag/hitscan/holy
+ name = "lasrifle beam"
+ damage = 0.1
+ damage_type = BURN
+
/obj/item/projectile/beam/lasertag/bluetag
icon_state = "bluelaser"
suit_types = list(/obj/item/clothing/suit/redtag)
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
index be55ed17..d698e11b 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
@@ -93,7 +93,7 @@
/datum/design/medkit
- name = "Medkit Cabinent"
+ name = "Medkit Cabinet"
id = "medkit_cabinet"
build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 4000)
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index 8e723ecf..df51f023 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -483,6 +483,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/ranged_analyzer
+ name = "Long-range Analyzer"
+ desc = "A new advanced atmospheric analyzer design, capable of performing scans at long range."
+ id = "ranged_analyzer"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 400, MAT_GLASS = 1000, MAT_URANIUM = 800, MAT_GOLD = 200, MAT_PLASTIC = 200)
+ build_path = /obj/item/analyzer/ranged
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/rcd_loaded
name = "Rapid Construction Device (RCD)"
desc = "A tool that can construct and deconstruct walls, airlocks and floors on the fly."
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 28e4be9a..0579b956 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -636,7 +636,7 @@
id = "exp_tools"
display_name = "Experimental Tools"
description = "Highly advanced construction tools."
- design_ids = list("exwelder", "jawsoflife", "handdrill")
+ design_ids = list("exwelder", "jawsoflife", "handdrill", "ranged_analyzer")
prereq_ids = list("adv_engi")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750)
export_price = 5000
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 98eb6f56..22dee60e 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -115,6 +115,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities
var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells
var/phase_allowed = 0 // If true, the spell can be cast while phased, eg. blood crawling, ethereal jaunting
+ var/antimagic_allowed = TRUE // If false, the spell cannot be cast while under the effect of antimagic
var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell
var/invocation_emote_self = null
var/invocation_type = "none" //can be none, whisper, emote and shout
@@ -147,27 +148,36 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(player_lock)
if(!user.mind || !(src in user.mind.spell_list) && !(src in user.mob_spell_list))
to_chat(user, "You shouldn't have this spell! Something's wrong.")
- return 0
+ return FALSE
else
if(!(src in user.mob_spell_list))
- return 0
+ return FALSE
var/turf/T = get_turf(user)
if(is_centcom_level(T.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
to_chat(user, "You can't cast this spell here.")
- return 0
+ return FALSE
if(!skipcharge)
if(!charge_check(user))
- return 0
+ return FALSE
if(user.stat && !stat_allowed)
to_chat(user, "Not when you're incapacitated.")
- return 0
+ return FALSE
+
+ if(!antimagic_allowed)
+ var/antimagic = user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE)
+ if(antimagic)
+ if(isitem(antimagic))
+ to_chat(user, "[antimagic] is interfering with your magic.")
+ else
+ to_chat(user, "Magic seems to flee from you, you can't gather enough power to cast this spell.")
+ return FALSE
if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.")
- return 0
+ return FALSE
if(ishuman(user))
@@ -175,7 +185,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if((invocation_type == "whisper" || invocation_type == "shout") && !H.can_speak_vocal())
to_chat(user, "You can't get the words out!")
- return 0
+ return FALSE
var/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe,
/obj/item/clothing/suit/space/hardsuit/wizard,
@@ -187,24 +197,24 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(clothes_req) //clothes check
if(!is_type_in_typecache(H.wear_suit, casting_clothes))
to_chat(H, "I don't feel strong enough without my robe.")
- return 0
+ return FALSE
if(!is_type_in_typecache(H.head, casting_clothes))
to_chat(H, "I don't feel strong enough without my hat.")
- return 0
+ return FALSE
if(cult_req) //CULT_REQ CLOTHES CHECK
if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult))
to_chat(H, "I don't feel strong enough without my armor.")
- return 0
+ return FALSE
if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult))
to_chat(H, "I don't feel strong enough without my helmet.")
- return 0
+ return FALSE
else
if(clothes_req || human_req)
to_chat(user, "This spell can only be cast by humans!")
- return 0
+ return FALSE
if(nonabstract_req && (isbrain(user) || ispAI(user)))
to_chat(user, "This spell can only be cast by physical beings!")
- return 0
+ return FALSE
if(!skipcharge)
@@ -499,6 +509,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(user.stat && !stat_allowed)
return FALSE
+ if(!antimagic_allowed && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE))
+ return FALSE
+
if(!ishuman(user))
if(clothes_req || human_req)
return FALSE
diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm
index 47d6f71f..ed78e331 100644
--- a/code/modules/spells/spell_types/forcewall.dm
+++ b/code/modules/spells/spell_types/forcewall.dm
@@ -35,6 +35,6 @@
return TRUE
if(ismob(mover))
var/mob/M = mover
- if(M.anti_magic_check())
+ if(M.anti_magic_check(chargecost = 0))
return TRUE
return FALSE
diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm
index 7fd857dc..7a197876 100644
--- a/code/modules/spells/spell_types/spacetime_distortion.dm
+++ b/code/modules/spells/spell_types/spacetime_distortion.dm
@@ -86,7 +86,7 @@
/obj/effect/cross_action/spacetime_dist/proc/walk_link(atom/movable/AM)
if(ismob(AM))
var/mob/M = AM
- if(M.anti_magic_check())
+ if(M.anti_magic_check(chargecost = 0))
return
if(linked_dist && walks_left > 0)
flick("purplesparkles", src)
diff --git a/code/modules/spells/spell_types/telepathy.dm b/code/modules/spells/spell_types/telepathy.dm
index db7e284e..34f100f7 100644
--- a/code/modules/spells/spell_types/telepathy.dm
+++ b/code/modules/spells/spell_types/telepathy.dm
@@ -10,9 +10,11 @@
action_background_icon_state = "bg_spell"
var/notice = "notice"
var/boldnotice = "boldnotice"
- var/magic_check = TRUE
+ var/magic_check = FALSE
+ var/holy_check = FALSE
+ var/tinfoil_check = TRUE
-/obj/effect/proc_holder/spell/targeted/telepathy/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
+/obj/effect/proc_holder/spell/targeted/telepathy/cast(list/targets, mob/living/user = usr)
for(var/mob/living/M in targets)
var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "")
if(!msg)
@@ -20,11 +22,11 @@
return
log_directed_talk(user, M, msg, LOG_SAY, "[name]")
to_chat(user, "You transmit to [M]: [msg]")
- if(!magic_check || !M.anti_magic_check(FALSE, TRUE)) //hear no evil
+ if(!M.anti_magic_check(magic_check, holy_check, tinfoil_check, 0)) //hear no evil
to_chat(M, "You hear something behind you talking... [msg]")
for(var/ded in GLOB.dead_mob_list)
if(!isobserver(ded))
continue
var/follow_rev = FOLLOW_LINK(ded, user)
var/follow_whispee = FOLLOW_LINK(ded, M)
- to_chat(ded, "[follow_rev] [user] [name]: \"[msg]\" to [follow_whispee] [M]")
\ No newline at end of file
+ to_chat(ded, "[follow_rev] [user] [name]: \"[msg]\" to [follow_whispee] [M]")
diff --git a/hyperstation/code/mobs/mimic.dm b/hyperstation/code/mobs/mimic.dm
index 96707f75..c89e973c 100644
--- a/hyperstation/code/mobs/mimic.dm
+++ b/hyperstation/code/mobs/mimic.dm
@@ -1,14 +1,14 @@
/mob/living/simple_animal/hostile/hs13mimic
name = "Mimic"
icon = 'hyperstation/icons/mobs/mimic.dmi'
- desc = "What the fuck is that?"
+ desc = "A writhing mass of black flesh, unlikely to be happy to see you."
icon_state = "mimic"
icon_living = "mimic"
icon_dead = "mimic_dead"
gender = NEUTER
speak_chance = 0
- maxHealth = 38
- health = 38
+ maxHealth = 35
+ health = 35
turns_per_move = 5
move_to_delay = 1
speed = 0
@@ -21,14 +21,14 @@
response_harm = "smacks"
melee_damage_lower = 8
melee_damage_upper = 12
- attacktext = "glomps"
- attack_sound = 'sound/effects/blobattack.ogg'
+ attacktext = "stings"
+ attack_sound = 'hyperstation/sound/creatures/mimic/mimic_attack.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
ventcrawler = VENTCRAWLER_ALWAYS
blood_volume = 0
faction = list("mimic")
gold_core_spawnable = NO_SPAWN
- vision_range = 2
+ vision_range = 1
aggro_vision_range = 9
wander = TRUE
minbodytemp = 250 //weak to cold
@@ -43,6 +43,7 @@
/obj/item/projectile,
/obj/item/radio/intercom,
/mob/living/simple_animal/bot))
+ var/transformsound = 'hyperstation/sound/creatures/mimic/mimic_transform.ogg'
var/playstyle_string = "You are a mimic, a tricky creature that can take the form of \
almost any item nearby by shift-clicking it. While morphed, you move slowly and do less damage. \
Finally, you can restore yourself to your original form while morphed by shift-clicking yourself. \
@@ -139,10 +140,10 @@
icon_state = "yellow"
desc = "These gloves will protect the wearer from electric shock."
if(21 to 30)
- name = "Private Security Officer"
- desc = "A cardboard cutout of a private security officer."
- icon = 'icons/obj/cardboard_cutout.dmi'
- icon_state = "cutout_ntsec"
+ name = "stunbaton"
+ desc = "A stun baton for incapacitating people with."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "stunbaton"
if(31 to 40)
name = "pen"
icon = 'icons/obj/bureaucracy.dmi'
@@ -154,10 +155,10 @@
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "newspaper"
if(51 to 60)
- name = "toolbox"
- desc = "Danger. Very robust."
- icon = 'icons/obj/storage.dmi'
- icon_state = "red"
+ name = "stechkin pistol" //greytider bait
+ desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors."
+ icon = 'icons/obj/guns/projectile.dmi'
+ icon_state = "pistol"
if(61 to 70)
name = "emergency oxygen tank"
desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it."
@@ -212,7 +213,7 @@
if(stealthed && stat == CONSCIOUS)
visible_message("The [src] Reveals itself to be a Mimic!")
restore()
- playsound(loc, 'hyperstation/sound/creatures/mimictransform.ogg', 75, TRUE)
+ playsound(loc, transformsound, 75, TRUE)
triggerOthers(target) // Friends too!
/mob/living/simple_animal/hostile/hs13mimic/proc/triggerOthers(passtarget) //
@@ -242,6 +243,48 @@
/mob/living/simple_animal/hostile/hs13mimic/proc/allowed(atom/movable/A)
return !is_type_in_typecache(A, mimic_blacklisted_transform_items) && (isitem(A) || isanimal(A))
+//One leader mimic spawns per mimic event spawn, they are able to consume and transform themselves into the station's dead pets. Buckle up.
+/mob/living/simple_animal/hostile/hs13mimic/leader
+ var/mob/living/consumptionTarget = null
+ var/consuming = FALSE
+ health = 38 //They have a teeeny tiny more health.
+ maxHealth = 38
+
+/mob/living/simple_animal/hostile/hs13mimic/leader/Life()
+ . = ..()
+ if(!consuming)
+ if(!consumptionTarget)
+ for(var/mob/living/simple_animal/pet/A in oview(5, src))
+ if(A.stat == DEAD)
+ consumptionTarget = A
+ break
+ if(!target && consumptionTarget) //Don't try to consume anything if we're currently attacking something.
+ var/target_distance = get_dist(targets_from, consumptionTarget)
+ if(target_distance > minimum_distance)
+ Goto(consumptionTarget,move_to_delay,minimum_distance)
+ else
+ tryConsume(consumptionTarget)
+
+/mob/living/simple_animal/hostile/hs13mimic/leader/proc/tryConsume(var/mob/living/simple_animal/pet/A)
+ src.visible_message("[A] is being consumed...",
+ "You start to consume the dead [A]...", "You hear strange fleshy sounds.")
+ consuming = TRUE
+ if(do_after(src, 100, target = A))
+ stealthed = TRUE
+ speed = 5
+ wander = TRUE
+ name = A.name
+ desc = A.desc
+ icon = A.icon
+ icon_state = A.icon_living
+ desc += " But something about it seems wrong..."
+ qdel(A)
+ consuming = FALSE
+ consumptionTarget = FALSE
+ return TRUE
+ consuming = FALSE
+ return FALSE
+
//Player control code
/mob/living/simple_animal/hostile/hs13mimic/ShiftClickOn(atom/movable/A)
@@ -252,7 +295,7 @@
return
if(istype(A) && allowed(A))
stealthed = TRUE
- SEND_SOUND(src, sound('hyperstation/sound/creatures/mimictransform.ogg',volume=50))
+ SEND_SOUND(src, sound(transformsound,volume=50))
name = A.name
icon = A.icon
icon_state = A.icon_state
@@ -297,6 +340,7 @@
/area/asteroid/nearstation,
/area/science/server,
/area/science/explab,
+ /area/science/xenobiology,
/area/security/processing)
var/spawncount = 1
fakeable = FALSE
@@ -359,8 +403,12 @@
notify_ghosts("A group of mimics has spawned in [pickedArea]!", source=pickedArea, action=NOTIFY_ATTACK, flashwindow = FALSE)
while(spawncount > 0 && validTurfs.len)
- var/turf/pickedTurf = pick_n_take(validTurfs)
- var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic
- spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
spawncount--
+ var/turf/pickedTurf = pick_n_take(validTurfs)
+ if(spawncount != 0)
+ var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic
+ spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
+ else
+ var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic/leader
+ spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
return SUCCESSFUL_SPAWN
diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm
index 92850f06..cf903eb7 100644
--- a/hyperstation/code/modules/arousal/arousalhud.dm
+++ b/hyperstation/code/modules/arousal/arousalhud.dm
@@ -9,8 +9,9 @@
var/mob/living/carbon/U = user
for(var/obj/item/organ/genital/G in U.internal_organs)
- if(!G.dontlist)
- dat += "[G.mode == "hidden" ? "[G.name] (Hidden)" : (G.mode == "clothes" ? "[G.name] (Hidden by Clothes)" : (G.mode == "visable" ? "[G.name] (Visable)" : "[G.name] (Visable)"))]
"
+ if(!G.nochange)
+ if(!G.dontlist)
+ dat += "[G.mode == "hidden" ? "[G.name] (Hidden)" : (G.mode == "clothes" ? "[G.name] (Hidden by Clothes)" : (G.mode == "visable" ? "[G.name] (Visable)" : "[G.name] (Visable)"))]
"
dat += {"
Contexual Options
"}
var/obj/item/organ/genital/penis/P = user.getorganslot("penis")
@@ -237,6 +238,13 @@
usr.put_in_hands(I)
O.equipment = null
+ if(href_list["removeequipmentanus"])
+ var/obj/item/organ/genital/anus/O = usr.getorganslot("anus")
+ var/obj/item/I = O.equipment
+ usr.put_in_hands(I)
+ O.equipment = null
+
+
if(href_list["omenu"])
usr << browse(null, "window=arousal") //closes the window
H.mob_climax()
diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm
index 19aff71e..0befcc44 100644
--- a/hyperstation/code/obj/fleshlight.dm
+++ b/hyperstation/code/obj/fleshlight.dm
@@ -100,7 +100,7 @@
/obj/item/portallight/examine(mob/user)
. = ..()
if(!portalunderwear)
- . += "The device is unpaired, to pair, swipe against a pair of portal panties(TM). "
+ . += "The device is unpaired, to pair, swipe against a pair of portal panties. "
else
. += "The device is paired, and awaiting input. "
@@ -117,12 +117,12 @@
else
option = "Fuck"
- var/obj/item/organ/genital/vagina/V
- if(istype(portalunderwear.loc, /obj/item/organ/genital/vagina)) //Sanity check. Without this it will runtime.
- V = portalunderwear.loc
- if(!V)
+ var/obj/item/organ/genital/G
+ if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime error.
+ G = portalunderwear.loc
+ if(!G)
return
- var/mob/living/carbon/human/M = V.owner
+ var/mob/living/carbon/human/M = G.owner
if(option == "Fuck"&&!P.is_exposed()) //we are trying to fuck with no penis!
to_chat(user, "You don't see anywhere to use this on.")
@@ -156,7 +156,7 @@
M.emote("moan")
if(option == "Fuck")// normal fuck
- to_chat(M, "You feel a [P.shape] shaped penis pumping through the portal into your vagina.")//message your partner and kinky!
+ to_chat(M, "You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [G.name].")//message your partner, and kinky!
if(prob(30)) //30% chance to make them moan.
C.emote("moan")
if(prob(30)) //30% chance to make your partner moan.
@@ -166,10 +166,10 @@
M.do_jitter_animation() //make your partner shake too!
if (M.getArousalLoss() >= 100 && ishuman(M) && prob(5))//Why not have a probability to cum when someone's getting nailed with max arousal?~
- if(V.is_exposed()) //Oh yea, if vagina is not exposed, the climax will not cause a spill
- M.mob_climax_outside(V, spillage = TRUE)
+ if(G.is_exposed()) //Oh yea, if vagina is not exposed, the climax will not cause a spill
+ M.mob_climax_outside(G, spillage = TRUE)
else
- M.mob_climax_outside(V, spillage = FALSE)
+ M.mob_climax_outside(G, spillage = FALSE)
if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna())
var/mob/living/carbon/human/O = C
@@ -180,10 +180,10 @@
O.mob_climax_partner(P, M, FALSE, TRUE, FALSE, TRUE) //climax with their partner remotely, and impreg because people keep asking!
if(option == "Lick")
- to_chat(M, "You feel a tongue lick you through the portal against your vagina.")
+ to_chat(M, "You feel a tongue lick you through the portal against your [G.name].")
M.adjustArousalLoss(10)
if(option == "Touch")
- to_chat(M, "You feel someone touching your vagina through the portal.")
+ to_chat(M, "You feel someone touching your [G.name] through the portal.")
M.adjustArousalLoss(5)
return
@@ -193,13 +193,14 @@
//get their looks and vagina colour!
cut_overlays()//remove current overlays
- var/obj/item/organ/genital/vagina/V
- if(istype(portalunderwear.loc, /obj/item/organ/genital/vagina)) //Sanity check. Without this it will runtime.
- V = portalunderwear.loc
- if(!V)
+ var/obj/item/organ/genital/G
+ if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime.
+ G = portalunderwear.loc
+ if(!G)
useable = FALSE
return
- var/mob/living/carbon/human/H = V.owner
+
+ var/mob/living/carbon/human/H = G.owner
if(H) //if the portal panties are on someone.
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_normal")
@@ -215,8 +216,12 @@
sleeve.color = "#" + H.dna.features["mcolor"]
add_overlay(sleeve)
- organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_vag")
- organ.color = portalunderwear.loc.color
+ if(G.name == "vagina")
+ organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_vag")
+ organ.color = portalunderwear.loc.color
+ if(G.name == "anus")
+ organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_anus")
+ organ.color = "#" + H.dna.features["mcolor"]
useable = TRUE
add_overlay(organ)
@@ -224,7 +229,7 @@
useable = FALSE
//Hyperstation 13 portal underwear
-//can be attached to vagina, just like the vibrator, still requires pairing with the portallight
+//can be attached to vagina or anus, just like the vibrator, still requires pairing with the portallight
/obj/item/portalpanties
name = "portal panties"
@@ -235,6 +240,7 @@
w_class = WEIGHT_CLASS_SMALL
var/obj/item/portallight
var/attached = FALSE
+ var/shapetype = "vagina"
/obj/item/portalpanties/examine(mob/user)
. = ..()
@@ -267,33 +273,34 @@
var/obj/item/organ/genital/picked_organ
var/mob/living/carbon/human/S = user
var/mob/living/carbon/human/T = C
- picked_organ = S.target_genitals(T) //allowing to pick organ for anus down the line
+ picked_organ = S.target_genitals(T)
if(picked_organ)
C.visible_message("[user] is trying to attach [src] to [T]!",\
"[user] is trying to put [src] on you!")
- if(!do_mob(user, C, 5 SECONDS))//warn them and have a delay of 5 seconds to apply.
+ if(!do_mob(user, C, 3 SECONDS))//warn them and have a delay of 5 seconds to apply.
return
- if(!(picked_organ.name == "vagina")) //only fits on a vagina
- to_chat(user, "[src] can only be attached to a vagina.")
- return
+ if((picked_organ.name == "vagina")||(picked_organ.name == "anus")) //only fits on a vagina or anus
- if(!picked_organ.equipment)
- to_chat(user, "You wrap [src] around [T]'s [picked_organ.name].")
+ src.shapetype = picked_organ.name
+ if(!picked_organ.equipment)
+ to_chat(user, "You wrap [src] around [T]'s [picked_organ.name].")
+ else
+ to_chat(user, "They already have [picked_organ.equipment.name] there.")
+ return
+
+ if(!user.transferItemToLoc(src, picked_organ)) //check if you can put it in
+ return
+ src.attached = TRUE
+ picked_organ.equipment = src
+
+ var/obj/item/portallight/P = portallight
+ //now we need to send what they look like, but saddly if the person changes colour for what ever reason, it wont update. but dont tell people shh.
+ if(P) //just to make sure
+ P.updatesleeve()
else
- to_chat(user, "They already have a [picked_organ.equipment.name] there.")
+ to_chat(user, "[src] can only be attached to a vagina or anus.")
return
-
- if(!user.transferItemToLoc(src, picked_organ)) //check if you can put it in
- return
- src.attached = TRUE
- picked_organ.equipment = src
-
- var/obj/item/portallight/P = portallight
- //now we need to send what they look like, but saddly if the person changes colour for what ever reason, it wont update. but dont tell people shh.
- if(P) //just to make sure
- P.updatesleeve()
-
else
to_chat(user, "You don't see anywhere to attach this.")
diff --git a/hyperstation/code/obj/kinkyclothes.dm b/hyperstation/code/obj/kinkyclothes.dm
index 06d65362..dbdcbd05 100644
--- a/hyperstation/code/obj/kinkyclothes.dm
+++ b/hyperstation/code/obj/kinkyclothes.dm
@@ -86,6 +86,7 @@ obj/item/clothing/neck/stole/black
item_state = "r_suit"
can_adjust = FALSE
mutantrace_variation = NO_MUTANTRACE_VARIATION
+ do_not_cover_butt = TRUE
/obj/item/clothing/under/sexynursesuit
name = "Sexy nurse outfit"
diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm
index b6655af9..51f49594 100644
--- a/hyperstation/code/obj/vibrator.dm
+++ b/hyperstation/code/obj/vibrator.dm
@@ -115,12 +115,10 @@ Code:
if(G)
switch(G.name) //just being fancy
- if("penis")
- to_chat(U, "[src] vibrates against your [G.name]!")
if("breasts")
to_chat(U, "[src] vibrates against your nipples!")
- if("vagina")
- to_chat(U, "[src] vibrates inside you!")
+ else
+ to_chat(U, "[src] vibrates against your [G.name]!")
var/intencity = 6*mode
U.adjustArousalLoss(intencity) //give pleasure
diff --git a/hyperstation/icons/obj/fleshlight.dmi b/hyperstation/icons/obj/fleshlight.dmi
index e40a8dd6..fe41d26e 100644
Binary files a/hyperstation/icons/obj/fleshlight.dmi and b/hyperstation/icons/obj/fleshlight.dmi differ
diff --git a/hyperstation/icons/obj/genitals/butt.dmi b/hyperstation/icons/obj/genitals/butt.dmi
new file mode 100644
index 00000000..08e60ea5
Binary files /dev/null and b/hyperstation/icons/obj/genitals/butt.dmi differ
diff --git a/hyperstation/icons/obj/plushes.dmi b/hyperstation/icons/obj/plushes.dmi
index 55bd43a5..1f67aedf 100644
Binary files a/hyperstation/icons/obj/plushes.dmi and b/hyperstation/icons/obj/plushes.dmi differ
diff --git a/hyperstation/sound/creatures/mimic/mimic_attack.ogg b/hyperstation/sound/creatures/mimic/mimic_attack.ogg
new file mode 100644
index 00000000..4d448840
Binary files /dev/null and b/hyperstation/sound/creatures/mimic/mimic_attack.ogg differ
diff --git a/hyperstation/sound/creatures/mimictransform.ogg b/hyperstation/sound/creatures/mimic/mimic_transform.ogg
similarity index 100%
rename from hyperstation/sound/creatures/mimictransform.ogg
rename to hyperstation/sound/creatures/mimic/mimic_transform.ogg
diff --git a/hyperstation/sound/misc/bonk.ogg b/hyperstation/sound/misc/bonk.ogg
new file mode 100644
index 00000000..8f03c8ec
Binary files /dev/null and b/hyperstation/sound/misc/bonk.ogg differ
diff --git a/icons/mob/suit_digi.dmi b/icons/mob/suit_digi.dmi
deleted file mode 100644
index 88c30722..00000000
Binary files a/icons/mob/suit_digi.dmi and /dev/null differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 331dc911..9d1323cc 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/modular_citadel/code/game/objects/items/holy_weapons.dm b/modular_citadel/code/game/objects/items/holy_weapons.dm
index 3ecc6cc3..06cdb0f5 100644
--- a/modular_citadel/code/game/objects/items/holy_weapons.dm
+++ b/modular_citadel/code/game/objects/items/holy_weapons.dm
@@ -30,24 +30,16 @@
"You kneel[M == user ? null : " next to [M]"] and begin a prayer to [deity_name].")
praying = TRUE
- if(do_after(user, 100, target = M))
+ if(do_after(user, 20, target = M))
if(istype(M, /mob/living/carbon/human)) // This probably should not work on catpeople. They're unholy abominations.
var/mob/living/carbon/human/target = M
-
- if(iscultist(M) || is_servant_of_ratvar(M)) //ripped from holywater code.
- if(iscultist(M))
- SSticker.mode.remove_cultist(M.mind, FALSE, TRUE)
- else if(is_servant_of_ratvar(M))
- remove_servant_of_ratvar(M)
-
+ M.reagents.add_reagent("holywater", 5)
to_chat(target, "[user]'s prayer to [deity_name] has eased your pain!")
target.adjustToxLoss(-5, TRUE, TRUE)
target.adjustOxyLoss(-5)
target.adjustBruteLoss(-5)
target.adjustFireLoss(-5)
-
praying = FALSE
-
else
to_chat(user, "Your prayer to [deity_name] was interrupted.")
praying = FALSE
diff --git a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
index d0e059e7..ff0ab7df 100644
--- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
+++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
@@ -275,7 +275,7 @@
/obj/item/twohanded/dualsaber/hypereutactic/chaplain/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, TRUE)
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
/obj/item/twohanded/dualsaber/hypereutactic/chaplain/IsReflect()
return FALSE
diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm
index beb5f8b9..97d8ac36 100644
--- a/modular_citadel/code/modules/arousal/arousal.dm
+++ b/modular_citadel/code/modules/arousal/arousal.dm
@@ -78,6 +78,9 @@
amt_nude++
if(getorganslot("vagina"))
amt_nude++
+ if(is_butt_exposed())
+ if(getorganslot("anus"))
+ amt_nude++
if(amt_nude)
var/watchers = 0
for(var/mob/_M in view(world.view, src))
@@ -321,7 +324,7 @@
src.visible_message("[src] orgasms with [p_their()] [G.name]!", \
"You climax with your [G.name].", \
"You climax using your [G.name].")
-
+
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
if(G.can_climax)
setArousalLoss(min_arousal)
@@ -522,10 +525,9 @@
var/list/worn_stuff = get_equipped_items()
for(var/obj/item/organ/genital/G in T.internal_organs)
- if(G.can_climax) //filter out what you can't masturbate with
- if(G.is_exposed(worn_stuff)) //Nude or through_clothing
- if(!G.dontlist)
- genitals_list += G
+ if(G.is_exposed(worn_stuff)) //Nude or through_clothing
+ if(!G.dontlist)
+ genitals_list += G
if(genitals_list.len)
ret_organ = input(src, "", "Genitals", null) as null|obj in genitals_list
return ret_organ
diff --git a/modular_citadel/code/modules/arousal/organs/anus.dm b/modular_citadel/code/modules/arousal/organs/anus.dm
new file mode 100644
index 00000000..8e0f5564
--- /dev/null
+++ b/modular_citadel/code/modules/arousal/organs/anus.dm
@@ -0,0 +1,36 @@
+/obj/item/organ/genital/anus
+ name = "anus"
+ desc = "You see a butt."
+ icon_state = "butt"
+ icon = 'modular_citadel/icons/obj/genitals/breasts.dmi'
+ zone = "anus"
+ slot = "anus"
+ w_class = 3
+ size = 0
+ var/statuscheck = FALSE
+ shape = "Pair"
+ masturbation_verb = "massage"
+ can_climax = FALSE
+
+
+
+
+/obj/item/organ/genital/anus/on_life()
+ if(QDELETED(src))
+ return
+ if(!owner)
+ return
+
+
+/obj/item/organ/genital/anus/update_appearance()
+ var/string
+ if(owner)
+ var/mob/living/carbon/human/H = owner
+ color = "#[skintone2hex(H.skin_tone)]"
+
+ if(ishuman(owner))
+ icon_state = sanitize_text(string)
+ H.update_genitals()
+
+ icon_state = sanitize_text(string)
+
diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/genitals.dm
index 83bb73e8..a33c68d8 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals.dm
@@ -25,6 +25,7 @@
var/mode = "clothes"
var/obj/item/equipment //for fun stuff that goes on the gentials/maybe rings down the line
var/dontlist = FALSE
+ var/nochange = FALSE //stops people changing visablity.
/obj/item/organ/genital/Initialize()
. = ..()
@@ -67,6 +68,8 @@
return owner.is_chest_exposed()
if("groin")
return owner.is_groin_exposed()
+ if("anus")
+ return owner.is_butt_exposed()
return FALSE
@@ -150,6 +153,8 @@
if (NOGENITALS in dna.species.species_traits)
return
//Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in.
+ if(dna.features["has_anus"])
+ give_anus()
if(dna.features["has_vag"])
give_vagina()
if(dna.features["has_womb"])
@@ -239,6 +244,20 @@
if(dna.features["inflatable_belly"]) //autohide bellies if they have the option ticked.
B.inflatable = TRUE
+/mob/living/carbon/human/proc/give_anus()
+ if(!dna)
+ return FALSE
+ if(NOGENITALS in dna.species.species_traits)
+ return FALSE
+ if(!getorganslot("anus"))
+ var/obj/item/organ/genital/anus/A = new
+ if(dna.features["butt_size"])
+ A.size = dna.features["butt_size"]
+ A.Insert(src)
+ if(A)
+ A.color = "#[skintone2hex(skin_tone)]"
+ A.update()
+
/mob/living/carbon/human/proc/give_breasts()
@@ -426,6 +445,8 @@
S = GLOB.breasts_shapes_list[G.shape]
if(/obj/item/organ/genital/belly)
S = GLOB.breasts_shapes_list[G.shape]
+ if(/obj/item/organ/genital/anus)
+ S = GLOB.breasts_shapes_list[G.shape]
if(!S || S.icon_state == "none")
continue
@@ -444,11 +465,24 @@
//Get the icon
genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]_[aroused_state]_[layertext]"
colourcode = S.color_src
+
if(G.slot == "belly") //we have a different size system
genital_overlay.icon = 'hyperstation/icons/obj/genitals/belly.dmi'
genital_overlay.icon_state = "belly_[size]"
colourcode = "belly_color"
+ if(G.slot == "anus") //we have a different size system
+ genital_overlay.icon = 'hyperstation/icons/obj/genitals/butt.dmi'
+ genital_overlay.icon_state = "butt_[size]"
+ genital_overlay.layer = -FRONT_MUTATIONS_LAYER
+ colourcode = "butt_color"
+ if(use_skintones) //butts are forced a colour, either skin tones, or main colour. how ever, mutants use a darker version, because of their body tone.
+ genital_overlay.color = "#[skintone2hex(H.skin_tone)]"
+ genital_overlay.icon_state = "butt_[size]"
+ else
+ genital_overlay.color = "#[H.dna.features["mcolor"]]"
+ genital_overlay.icon_state = "butt_[size]_m"
+
if(S.center)
genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y)
@@ -471,6 +505,7 @@
if("belly_color")
genital_overlay.color = "#[H.dna.features["belly_color"]]"
+
standing += genital_overlay
if(LAZYLEN(standing))
diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
index ae86c097..8fe929e8 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
@@ -136,7 +136,7 @@
icon_state = "gaping"
name = "Gaping"
-//BREASTS BE HERE
+//BELLY BE HERE
/datum/sprite_accessory/belly
icon = 'hyperstation/icons/obj/genitals/belly.dmi'
icon_state = "belly"
@@ -145,6 +145,15 @@
color_src = "belly_color"
locked = 0
+//BUTT BE HERE
+/datum/sprite_accessory/anus
+ icon = 'hyperstation/icons/obj/genitals/butt.dmi'
+ icon_state = "butt"
+ name = "butt"
+ gender_specific = 0
+ color_src = "butt_color"
+ locked = 0
+
//BREASTS BE HERE
/datum/sprite_accessory/breasts
icon = 'modular_citadel/icons/obj/genitals/breasts_onmob.dmi'
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index 7b09b997..1b1a2997 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -63,6 +63,8 @@
WRITE_FILE(S["feature_has_sheath"], features["sheath_color"])
//belly feature
WRITE_FILE(S["feature_belly_size"], features["belly_size"])
+ //butt feature
+ WRITE_FILE(S["feature_butt_size"], features["butt_size"])
//balls features
WRITE_FILE(S["feature_has_balls"], features["has_balls"])
WRITE_FILE(S["feature_balls_color"], features["balls_color"])
@@ -96,6 +98,8 @@
WRITE_FILE(S["feature_belly_color"], features["belly_color"])
WRITE_FILE(S["feature_hide_belly"], features["hide_belly"])
WRITE_FILE(S["feature_inflatable_belly"], features["inflatable_belly"])
+ //anus
+ WRITE_FILE(S["feature_has_anus"], features["has_anus"])
//gear loadout
if(islist(chosen_gear))
diff --git a/modular_citadel/code/modules/clothing/under/polychromic_clothes.dm b/modular_citadel/code/modules/clothing/under/polychromic_clothes.dm
index a5514898..a91e5b81 100644
--- a/modular_citadel/code/modules/clothing/under/polychromic_clothes.dm
+++ b/modular_citadel/code/modules/clothing/under/polychromic_clothes.dm
@@ -144,6 +144,7 @@
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#8CC6FF"
body_parts_covered = GROIN
+ do_not_cover_butt = TRUE
/obj/item/clothing/under/polychromic/bottomless
name = "polychromic bottomless shirt"
@@ -177,6 +178,7 @@
primary_color = "#808080" //RGB in hexcode
secondary_color = "#FFFFFF"
body_parts_covered = CHEST|GROIN
+ do_not_cover_butt = TRUE
/obj/item/clothing/under/polychromic/stripper
name = "polychromic stripper outfit"
@@ -188,6 +190,7 @@
primary_color = "#808080" //RGB in hexcode
secondary_color = "#FFFFFF"
body_parts_covered = CHEST|GROIN
+ do_not_cover_butt = TRUE
/obj/item/clothing/under/polychromic/bulge
name = "polychromic voluminous thong"
@@ -199,6 +202,7 @@
primary_color = "#808080" //RGB in hexcode
secondary_color = "#FF3535"
body_parts_covered = GROIN
+ do_not_cover_butt = TRUE
/obj/item/clothing/under/polychromic/shortsbra
name = "Kromatic Shorts and Top"
@@ -231,4 +235,5 @@
primary_color = "#010052" //RGB in hexcode
secondary_color = "#eb7a7a"
tertiary_color = "#ffffff"
- body_parts_covered = CHEST|GROIN
\ No newline at end of file
+ body_parts_covered = CHEST|GROIN
+ do_not_cover_butt = TRUE
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index 52811d1a..ba17e369 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -476,6 +476,7 @@
#include "code\datums\elements\flavor_text.dm"
#include "code\datums\elements\ghost_role_eligibility.dm"
#include "code\datums\elements\mob_holder.dm"
+#include "code\datums\elements\squish.dm"
#include "code\datums\elements\swimming.dm"
#include "code\datums\elements\wuv.dm"
#include "code\datums\helper_datums\events.dm"
@@ -3238,6 +3239,7 @@
#include "modular_citadel\code\modules\admin\holder2.dm"
#include "modular_citadel\code\modules\admin\secrets.dm"
#include "modular_citadel\code\modules\arousal\arousal.dm"
+#include "modular_citadel\code\modules\arousal\organs\anus.dm"
#include "modular_citadel\code\modules\arousal\organs\belly.dm"
#include "modular_citadel\code\modules\arousal\organs\breasts.dm"
#include "modular_citadel\code\modules\arousal\organs\eggsack.dm"