[MIRROR] new space ruin, the biological research outpost [MDB IGNORE] (#24662)

* new space ruin, the biological research outpost (#79149)

## About The Pull Request

![2023-10-21 18 02
39](https://github.com/tgstation/tgstation/assets/70376633/5829e939-3b04-465f-a186-095ceb360bba)

adds this ruin to space ruin pool
this is a shady (as NT always is) bioresearch outpost that got fucked up
by an experiment
this has like some puzzle aspect to it since you gotta find keycards and
shit and press buttons to unlock shield gates
this ends with you fighting a heart which if you defeat, destroys the
blockade that prevents you from entering the outpost vault

also you can no longer literally just cut indestructible grilles or
unanchor indestructible windows

### new puzzle elements or something idk
variant of pressure plate that you cannot remove and it sends a puzzle
signal
cooler red puzzle doors that look very foreboding or something idk
theyre for this ruin
also puzzle blockades, which are indestructible dense objects that are
destroyed if they receive a puzzle signal
and also buttons and keycard pads for puzzles

https://github.com/tgstation/tgstation/assets/70376633/c98807ec-1e7b-49c4-a757-cdbb76a1b566

https://github.com/tgstation/tgstation/assets/70376633/9d5d9dd1-5868-44e6-a978-5ea57b30c298

stuff that throws electric shocks in a pattern, ignores insuls and only
knocks down, and no you cannot just run past

https://github.com/tgstation/tgstation/assets/70376633/5772917c-a963-48a4-a743-b0f610801d25

### enemies
living floor, it can only attack stuff on top of it and it attacks until
the victim is dead
it is invincible to all but a crowbar, and it cannot move, and it
remains hidden until a victim is in range

https://github.com/tgstation/tgstation/assets/70376633/aa1d54f6-b259-4e58-9d44-e393d2131acf

living flesh, it can replace your limbs with itself
the conditions for that are; the limb must have 20 or more brute, victim
must be alive and dismemberable, the limb may not be torso or head, or
the limb may not be living flesh
alternatively it can replace a missing limb
these are all checked with every attack
they have 20 hp
the limbs in question will sometimes act up, while passively draining
nutrition, arms will randomly start pulling nearby stuff, legs may step
randomly
limbs when detached, turn into mobs and reactivate AI 2 seconds later.
if the host is shocked, all living flesh limbs will detach, or if the
host dies they will also do that

https://github.com/tgstation/tgstation/assets/70376633/765cc99e-c800-4efb-aabe-d68817bbd7ae

## Why It's Good For The Game

ruin variety is cool i think
also the other things i added should be useful for other mappers for
bitrunning or whatever

also bug bad for that one fix
## Changelog
🆑
add: living floor, living flesh, and other stuff for the bioresearch
outpost ruin
add: bioresearch outpost ruin
fix: you may not defeat indestructible grilles and windows with mere
tools
/🆑

---------

Co-authored-by: Jacquerel <hnevard@ gmail.com>

* new space ruin, the biological research outpost

---------

Co-authored-by: jimmyl <70376633+mc-oofert@users.noreply.github.com>
Co-authored-by: Jacquerel <hnevard@ gmail.com>
This commit is contained in:
SkyratBot
2023-10-31 06:35:11 +01:00
committed by GitHub
parent 7d438d620c
commit 1a2ddececa
28 changed files with 5121 additions and 15 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -127,3 +127,5 @@
#define COMSIG_ATOM_GERM_UNEXPOSED "atom_germ_unexposed" #define COMSIG_ATOM_GERM_UNEXPOSED "atom_germ_unexposed"
/// when atom is washed /// when atom is washed
#define COMSIG_ATOM_WASHED "atom_washed" #define COMSIG_ATOM_WASHED "atom_washed"
/// signal sent to puzzle pieces by activator
#define COMSIG_PUZZLE_COMPLETED "puzzle_completed"

View File

@@ -151,6 +151,7 @@
#define BODYPART_ID_DIGITIGRADE "digitigrade" #define BODYPART_ID_DIGITIGRADE "digitigrade"
#define BODYPART_ID_LARVA "larva" #define BODYPART_ID_LARVA "larva"
#define BODYPART_ID_PSYKER "psyker" #define BODYPART_ID_PSYKER "psyker"
#define BODYPART_ID_MEAT "meat"
//See: datum/species/var/digitigrade_customization //See: datum/species/var/digitigrade_customization
///The species does not have digitigrade legs in generation. ///The species does not have digitigrade legs in generation.

View File

@@ -171,6 +171,7 @@
#define INIT_ORDER_LANGUAGE 25 #define INIT_ORDER_LANGUAGE 25
#define INIT_ORDER_MACHINES 20 #define INIT_ORDER_MACHINES 20
#define INIT_ORDER_SKILLS 15 #define INIT_ORDER_SKILLS 15
#define INIT_ORDER_QUEUELINKS 10
#define INIT_ORDER_TIMER 1 #define INIT_ORDER_TIMER 1
#define INIT_ORDER_DEFAULT 0 #define INIT_ORDER_DEFAULT 0
#define INIT_ORDER_AIR -1 #define INIT_ORDER_AIR -1

View File

@@ -1335,6 +1335,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
///Trait given by /datum/element/relay_attacker ///Trait given by /datum/element/relay_attacker
#define TRAIT_RELAYING_ATTACKER "relaying_attacker" #define TRAIT_RELAYING_ATTACKER "relaying_attacker"
///Trait given to limb by /mob/living/basic/living_limb_flesh
#define TRAIT_IGNORED_BY_LIVING_FLESH "livingflesh_ignored"
/// Trait given while using /datum/action/cooldown/mob_cooldown/wing_buffet /// Trait given while using /datum/action/cooldown/mob_cooldown/wing_buffet
#define TRAIT_WING_BUFFET "wing_buffet" #define TRAIT_WING_BUFFET "wing_buffet"
/// Trait given while tired after using /datum/action/cooldown/mob_cooldown/wing_buffet /// Trait given while tired after using /datum/action/cooldown/mob_cooldown/wing_buffet

View File

@@ -0,0 +1,68 @@
/atom/proc/MatchedLinks(id, list/partners)
SUBSYSTEM_DEF(queuelinks)
name = "Queue Links"
flags = SS_NO_FIRE
init_order = INIT_ORDER_QUEUELINKS
///assoc list of pending queues, id = /datum/queue_link
var/list/queues = list()
/datum/controller/subsystem/queuelinks/Initialize()
return SS_INIT_SUCCESS
///Creates or adds to a queue with the id supplied, if the queue is now or above the size of the queue, calls MatchedLinks and clears queue.
/// queues with a size of 0 wait never pop until something is added with an actual queue_max
/datum/controller/subsystem/queuelinks/proc/add_to_queue(atom/what, id, queue_max = 0)
if(!isatom(what))
CRASH("Attempted to add a non-atom to queue; [what]!")
if(isnull(id))
CRASH("Attempted to add to queue with no ID; [what]")
var/datum/queue_link/link
if(isnull(queues[id]))
link = new /datum/queue_link(id)
queues[id] = link
else
link = queues[id]
if(link.add(what, queue_max))
queues -= id
/datum/queue_link
/// atoms in our queue
var/list/partners = list()
/// how much length until we pop, only incrementable, 0 means the queue will not pop until a maximum is set
var/queue_max = 0
/// id
var/id
/datum/queue_link/New(new_id)
id = new_id
return ..()
///adds an atom to the queue, if we are popping this returns TRUE
/datum/queue_link/proc/add(atom/what, max = 0)
. = FALSE
if(what in partners)
return
partners += what
if(queue_max != 0 && max != 0 && max != queue_max)
CRASH("Tried to change queue size to [max] from [queue_max]!")
else if(!queue_max)
queue_max = max
if(!queue_max || length(partners) < queue_max)
return
pop()
return TRUE
/datum/queue_link/proc/pop()
for(var/atom/item as anything in partners)
item.MatchedLinks(id, partners)
qdel(src)
/datum/queue_link/Destroy()
. = ..()
partners = null

View File

@@ -389,6 +389,12 @@ suffix = "whiteshipruin_box.dmm"*/
name = "The Faceoff" name = "The Faceoff"
description = "What do you get when a meeting of the enemy corporations get crashed?" description = "What do you get when a meeting of the enemy corporations get crashed?"
/datum/map_template/ruin/space/meatstation
id = "meatderelict"
suffix = "meatderelict.dmm"
name = "Bioresearch Outpost"
description = "A bioresearch experiment gone wrong."
/datum/map_template/ruin/space/ghost_restaurant /datum/map_template/ruin/space/ghost_restaurant
id = "space_ghost_restaurant.dmm" id = "space_ghost_restaurant.dmm"
suffix = "space_ghost_restaurant.dmm" suffix = "space_ghost_restaurant.dmm"

View File

@@ -599,6 +599,13 @@
/area/ruin/space/has_grav/derelictsulaco /area/ruin/space/has_grav/derelictsulaco
name = "\improper Derelict Sulaco" name = "\improper Derelict Sulaco"
/area/ruin/space/has_grav/powered/biooutpost
name = "\improper Bioresearch Outpost"
area_flags = UNIQUE_AREA | NOTELEPORT
/area/ruin/space/has_grav/powered/biooutpost/vault
name = "\improper Bioresearch Outpost Secure Testing"
// Space Ghost Kitchen // Space Ghost Kitchen
/area/ruin/space/space_ghost_restaurant /area/ruin/space/space_ghost_restaurant
name = "\improper Space Ghost Restaurant" name = "\improper Space Ghost Restaurant"

View File

@@ -91,3 +91,21 @@
active = underfloor_accessibility < UNDERFLOOR_VISIBLE active = underfloor_accessibility < UNDERFLOOR_VISIBLE
/obj/item/pressure_plate/puzzle
protected = TRUE
anchored = TRUE //this prevents us from being picked up
active = TRUE
removable_signaller = FALSE
/// puzzle id we send if stepped on
var/puzzle_id
/// queue size must match
var/queue_size = 2
/obj/item/pressure_plate/puzzle/Initialize(mapload)
. = ..()
if(!isnull(puzzle_id))
SSqueuelinks.add_to_queue(src, puzzle_id, queue_size)
/obj/item/pressure_plate/puzzle/trigger()
can_trigger = FALSE
SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)

View File

@@ -1,7 +1,8 @@
//Every time you got lost looking for keycards, incriment: 1 //Every time you got lost looking for keycards, increment: 2
//**************
//*****Keys*****
//************** //**************
//*****Keys*******************
//************** ** **
/obj/item/keycard /obj/item/keycard
name = "security keycard" name = "security keycard"
desc = "This feels like it belongs to a door." desc = "This feels like it belongs to a door."
@@ -45,8 +46,10 @@
move_resist = MOVE_FORCE_OVERPOWERING move_resist = MOVE_FORCE_OVERPOWERING
damage_deflection = 70 damage_deflection = 70
can_open_with_hands = FALSE can_open_with_hands = FALSE
/// Make sure that the puzzle has the same puzzle_id as the keycard door! /// Make sure that the puzzle has the same puzzle_id as the keycard door! (If this is null, queuelinks dont happen!)
var/puzzle_id = null var/puzzle_id = null
/// do we use queue_links?
var/uses_queuelinks = TRUE
/// Message that occurs when the door is opened /// Message that occurs when the door is opened
var/open_message = "The door beeps, and slides opens." var/open_message = "The door beeps, and slides opens."
@@ -63,16 +66,18 @@
/obj/machinery/door/puzzle/Initialize(mapload) /obj/machinery/door/puzzle/Initialize(mapload)
. = ..() . = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_PUZZLE_COMPLETED, PROC_REF(try_signal)) if(!isnull(puzzle_id) && uses_queuelinks)
SSqueuelinks.add_to_queue(src, puzzle_id)
/obj/machinery/door/puzzle/Destroy(force) /obj/machinery/door/puzzle/MatchedLinks(id, list/partners)
. = ..() for(var/partner in partners)
UnregisterSignal(SSdcs, COMSIG_GLOB_PUZZLE_COMPLETED) RegisterSignal(partner, COMSIG_PUZZLE_COMPLETED, PROC_REF(try_signal))
/obj/machinery/door/puzzle/proc/try_signal(datum/source, try_id) /obj/machinery/door/puzzle/proc/try_signal(datum/source, try_id)
SIGNAL_HANDLER SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(try_puzzle_open), try_id) puzzle_id = null //honestly these cant be closed anyway and im not fucking around with door code anymore
INVOKE_ASYNC(src, PROC_REF(try_puzzle_open), null)
/obj/machinery/door/puzzle/Bumped(atom/movable/AM) /obj/machinery/door/puzzle/Bumped(atom/movable/AM)
return !density && ..() return !density && ..()
@@ -101,6 +106,7 @@
/obj/machinery/door/puzzle/keycard /obj/machinery/door/puzzle/keycard
desc = "This door only opens when a keycard is swiped. It looks virtually indestructible." desc = "This door only opens when a keycard is swiped. It looks virtually indestructible."
uses_queuelinks = FALSE
/obj/machinery/door/puzzle/keycard/attackby(obj/item/attacking_item, mob/user, params) /obj/machinery/door/puzzle/keycard/attackby(obj/item/attacking_item, mob/user, params)
. = ..() . = ..()
@@ -203,6 +209,8 @@
) )
/// Banned combinations of the list in decimal /// Banned combinations of the list in decimal
var/static/list/banned_combinations = list(-1, 47, 95, 203, 311, 325, 422, 473, 488, 500, 511) var/static/list/banned_combinations = list(-1, 47, 95, 203, 311, 325, 422, 473, 488, 500, 511)
/// queue size, must match count of objects this activates!
var/queue_size = 2
/datum/armor/structure_light_puzzle /datum/armor/structure_light_puzzle
melee = 100 melee = 100
@@ -224,6 +232,8 @@
var/position = !!(generated_board & (1<<i)) var/position = !!(generated_board & (1<<i))
light_list[i+1] = position light_list[i+1] = position
update_icon(UPDATE_OVERLAYS) update_icon(UPDATE_OVERLAYS)
if(!isnull(puzzle_id))
SSqueuelinks.add_to_queue(src, puzzle_id, queue_size)
/obj/structure/light_puzzle/update_overlays() /obj/structure/light_puzzle/update_overlays()
. = ..() . = ..()
@@ -272,5 +282,124 @@
return return
visible_message(span_boldnotice("[src] becomes fully charged!")) visible_message(span_boldnotice("[src] becomes fully charged!"))
powered = TRUE powered = TRUE
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PUZZLE_COMPLETED, puzzle_id) SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
playsound(src, 'sound/machines/synth_yes.ogg', 100, TRUE) playsound(src, 'sound/machines/synth_yes.ogg', 100, TRUE)
//
// literally just buttons
//
/obj/machinery/puzzle_button
name = "control panel"
desc = "A panel that controls something nearby. I'm sure it being covered in hazard stripes is fine."
icon = 'icons/obj/machines/wallmounts.dmi'
icon_state = "lockdown0"
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
base_icon_state = "lockdown"
/// have we been pressed already?
var/used = FALSE
/// can we be pressed only once?
var/single_use = TRUE
/// puzzle id we send on press
var/id = "0" //null would literally open every puzzle door without an id
/// queue size, must match count of objects this activates!
var/queue_size = 2
/obj/machinery/puzzle_button/Initialize(mapload)
. = ..()
if(!isnull(id))
SSqueuelinks.add_to_queue(src, id, queue_size)
/obj/machinery/puzzle_button/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
if(used && single_use)
return
used = single_use
update_icon_state()
visible_message(span_notice("[user] presses a button on [src]."), span_notice("You press a button on [src]."))
playsound(src, 'sound/machines/terminal_button07.ogg', 45, TRUE)
open_doors()
/obj/machinery/puzzle_button/proc/open_doors() //incase someone wants to make this do something else for some reason
SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
/obj/machinery/puzzle_button/update_icon_state()
icon_state = "[base_icon_state][used]"
return ..()
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_button, 32)
/obj/machinery/puzzle_keycardpad
name = "keycard panel"
desc = "A panel that controls something nearby. Accepts keycards."
icon = 'icons/obj/machines/wallmounts.dmi'
icon_state = "keycardpad0"
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
base_icon_state = "keycardpad"
/// were we used successfully?
var/used = FALSE
/// puzzle id we send if the correct card is swiped
var/id = "0"
/// queue size, must match count of objects this activates!
var/queue_size = 2
/obj/machinery/puzzle_keycardpad/Initialize(mapload)
. = ..()
if(!isnull(id))
SSqueuelinks.add_to_queue(src, id, queue_size)
/obj/machinery/puzzle_keycardpad/attackby(obj/item/attacking_item, mob/user, params)
. = ..()
if(!istype(attacking_item, /obj/item/keycard) || used)
return
var/obj/item/keycard/key = attacking_item
var/correct_card = key.puzzle_id == id
balloon_alert_to_viewers("[correct_card ? "correct" : "incorrect"] card swiped[correct_card ? "" : "!"]")
playsound(src, 'sound/machines/card_slide.ogg', 45, TRUE)
if(!correct_card)
return
used = TRUE
update_icon_state()
playsound(src, 'sound/machines/beep.ogg', 45, TRUE)
SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
/obj/machinery/puzzle_keycardpad/update_icon_state()
icon_state = "[base_icon_state][used]"
return ..()
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_keycardpad, 32)
//
// blockade
//
///blockades destroy themselves if they receive COMSIG_GLOB_PUZZLE_COMPLETED with their ID
/obj/structure/puzzle_blockade
name = "shield gate"
desc = "A wall of solid light, likely defending something important. Virtually indestructible, must be a way around, or to disable it."
icon = 'icons/effects/effects.dmi'
icon_state = "wave2"
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
move_resist = MOVE_FORCE_OVERPOWERING
opacity = FALSE
density = TRUE
anchored = TRUE
/// if we receive a puzzle signal with this id we get destroyed
var/id
/obj/structure/puzzle_blockade/Initialize(mapload)
. = ..()
if(!isnull(id))
SSqueuelinks.add_to_queue(src, id)
/obj/structure/puzzle_blockade/MatchedLinks(id, list/partners)
for(var/partner in partners)
RegisterSignal(partner, COMSIG_PUZZLE_COMPLETED, PROC_REF(try_signal))
/obj/structure/puzzle_blockade/proc/try_signal(datum/source)
SIGNAL_HANDLER
playsound(src, SFX_SPARKS, 100, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
do_sparks(3, cardinal_only = FALSE, source = src)
qdel(src)

View File

@@ -8,6 +8,8 @@
opacity = FALSE opacity = FALSE
plane = FLOOR_PLANE plane = FLOOR_PLANE
layer = CATWALK_LAYER layer = CATWALK_LAYER
/// do we always have FLOOR_PLANE even if we arent on plating?
var/always_floorplane = FALSE
/obj/structure/broken_flooring/Initialize(mapload) /obj/structure/broken_flooring/Initialize(mapload)
. = ..() . = ..()
@@ -16,7 +18,7 @@
/obj/structure/broken_flooring/LateInitialize() /obj/structure/broken_flooring/LateInitialize()
. = ..() . = ..()
var/turf/turf = get_turf(src) var/turf/turf = get_turf(src)
if(!isplatingturf(turf)) // Render as trash if not on plating if(!isplatingturf(turf) && !always_floorplane) // Render as trash if not on plating
plane = GAME_PLANE plane = GAME_PLANE
layer = LOW_OBJ_LAYER layer = LOW_OBJ_LAYER
return return
@@ -35,20 +37,40 @@
/obj/structure/broken_flooring/singular /obj/structure/broken_flooring/singular
icon_state = "singular" icon_state = "singular"
/obj/structure/broken_flooring/singular/always_floorplane
always_floorplane = TRUE
/obj/structure/broken_flooring/pile /obj/structure/broken_flooring/pile
icon_state = "pile" icon_state = "pile"
/obj/structure/broken_flooring/pile/always_floorplane
always_floorplane = TRUE
/obj/structure/broken_flooring/side /obj/structure/broken_flooring/side
icon_state = "side" icon_state = "side"
/obj/structure/broken_flooring/side/always_floorplane
always_floorplane = TRUE
/obj/structure/broken_flooring/corner /obj/structure/broken_flooring/corner
icon_state = "corner" icon_state = "corner"
/obj/structure/broken_flooring/corner/always_floorplane
always_floorplane = TRUE
/obj/structure/broken_flooring/plating /obj/structure/broken_flooring/plating
icon_state = "plating" icon_state = "plating"
/obj/structure/broken_flooring/plating/always_floorplane
always_floorplane = TRUE
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/singular, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/singular, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/pile, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/pile, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/side, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/side, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/corner, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/corner, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/plating, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/plating, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/singular/always_floorplane, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/pile/always_floorplane, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/side/always_floorplane, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/corner/always_floorplane, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/plating/always_floorplane, 0)

View File

@@ -52,9 +52,12 @@
/obj/structure/grille/examine(mob/user) /obj/structure/grille/examine(mob/user)
. = ..() . = ..()
if(flags_1 & NODECONSTRUCT_1)
return
if(anchored) if(anchored)
. += span_notice("It's secured in place with <b>screws</b>. The rods look like they could be <b>cut</b> through.") . += span_notice("It's secured in place with <b>screws</b>. The rods look like they could be <b>cut</b> through.")
if(!anchored) else
. += span_notice("The anchoring screws are <i>unscrewed</i>. The rods look like they could be <b>cut</b> through.") . += span_notice("The anchoring screws are <i>unscrewed</i>. The rods look like they could be <b>cut</b> through.")
/obj/structure/grille/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) /obj/structure/grille/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
@@ -186,6 +189,8 @@
add_fingerprint(user) add_fingerprint(user)
if(shock(user, 100)) if(shock(user, 100))
return return
if(flags_1 & NODECONSTRUCT_1)
return FALSE
tool.play_tool_sound(src, 100) tool.play_tool_sound(src, 100)
deconstruct() deconstruct()
return TOOL_ACT_TOOLTYPE_SUCCESS return TOOL_ACT_TOOLTYPE_SUCCESS
@@ -196,6 +201,8 @@
add_fingerprint(user) add_fingerprint(user)
if(shock(user, 90)) if(shock(user, 90))
return FALSE return FALSE
if(flags_1 & NODECONSTRUCT_1)
return FALSE
if(!tool.use_tool(src, user, 0, volume=100)) if(!tool.use_tool(src, user, 0, volume=100))
return FALSE return FALSE
set_anchored(!anchored) set_anchored(!anchored)

View File

@@ -79,6 +79,9 @@
/obj/structure/window/examine(mob/user) /obj/structure/window/examine(mob/user)
. = ..() . = ..()
if(flags_1 & NODECONSTRUCT_1)
return
switch(state) switch(state)
if(WINDOW_SCREWED_TO_FRAME) if(WINDOW_SCREWED_TO_FRAME)
. += span_notice("The window is <b>screwed</b> to the frame.") . += span_notice("The window is <b>screwed</b> to the frame.")
@@ -480,6 +483,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0)
return FALSE return FALSE
/obj/structure/window/reinforced/attackby_secondary(obj/item/tool, mob/user, params) /obj/structure/window/reinforced/attackby_secondary(obj/item/tool, mob/user, params)
if(flags_1 & NODECONSTRUCT_1)
return ..()
switch(state) switch(state)
if(RWINDOW_SECURE) if(RWINDOW_SECURE)
if(tool.tool_behaviour == TOOL_WELDER) if(tool.tool_behaviour == TOOL_WELDER)
@@ -558,6 +564,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0)
/obj/structure/window/reinforced/examine(mob/user) /obj/structure/window/reinforced/examine(mob/user)
. = ..() . = ..()
if(flags_1 & NODECONSTRUCT_1)
return
switch(state) switch(state)
if(RWINDOW_SECURE) if(RWINDOW_SECURE)
. += span_notice("It's been screwed in with one way screws, you'd need to <b>heat them</b> to have any chance of backing them out.") . += span_notice("It's been screwed in with one way screws, you'd need to <b>heat them</b> to have any chance of backing them out.")

View File

@@ -364,3 +364,13 @@ SKYRAT EDIT REMOVAL END */
/turf/closed/indestructible/grille/Initialize(mapload) /turf/closed/indestructible/grille/Initialize(mapload)
. = ..() . = ..()
underlays += mutable_appearance('icons/turf/floors.dmi', "plating") underlays += mutable_appearance('icons/turf/floors.dmi', "plating")
/turf/closed/indestructible/meat
name = "dense meat wall"
desc = "A huge chunk of dense, packed meat. Effectively impervious to conventional methods of destruction."
icon = 'icons/turf/walls/meat.dmi'
icon_state = "meatwall-0"
base_icon_state = "meatwall"
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = SMOOTH_GROUP_WALLS
canSmoothWith = SMOOTH_GROUP_WALLS

View File

@@ -124,9 +124,6 @@
/turf/open/indestructible/light /turf/open/indestructible/light
icon_state = "light_on-1" icon_state = "light_on-1"
/turf/open/indestructible/plating
icon_state = "plating"
/turf/open/indestructible/permalube /turf/open/indestructible/permalube
icon_state = "darkfull" icon_state = "darkfull"
@@ -223,6 +220,29 @@
init_air = FALSE init_air = FALSE
baseturfs = /turf/open/indestructible/airblock baseturfs = /turf/open/indestructible/airblock
/turf/open/indestructible/meat
icon_state = "meat"
footstep = FOOTSTEP_MEAT
barefootstep = FOOTSTEP_MEAT
clawfootstep = FOOTSTEP_MEAT
heavyfootstep = FOOTSTEP_MEAT
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
baseturfs = /turf/open/indestructible/meat
/turf/open/indestructible/meat/airless
initial_gas_mix = AIRLESS_ATMOS
/turf/open/indestructible/plating
name = "plating"
icon_state = "plating"
desc = "The attachment points are all bent to uselessness, looks nigh-impervious to damage."
overfloor_placed = FALSE
underfloor_accessibility = UNDERFLOOR_INTERACTABLE
footstep = FOOTSTEP_PLATING
/turf/open/indestructible/plating/airless
initial_gas_mix = AIRLESS_ATMOS
/turf/open/Initalize_Atmos(time) /turf/open/Initalize_Atmos(time)
excited = FALSE excited = FALSE
update_visuals() update_visuals()

View File

@@ -0,0 +1,156 @@
/obj/item/keycard/meatderelict/director
name = "directors keycard"
desc = "A fancy keycard. Likely unlocks the directors office. The name tag is all smudged."
color = "#990000"
puzzle_id = "md_director"
/obj/item/keycard/meatderelict/engpost
name = "post keycard"
desc = "A fancy keycard. Has the engineering insignia on it."
color = "#f0da12"
puzzle_id = "md_engpost"
/obj/item/keycard/meatderelict/armory
name = "armory keycard"
desc = "A red keycard. Has a really cool image of a gun on it. Fancy."
color = "#FF7276"
puzzle_id = "md_armory"
/obj/item/paper/crumpled/bloody/fluff/meatderelict/directoroffice
name = "directors note"
default_raw_text = "<i>The research was going smooth... but the experiment did not go as planned. He convulsed and screamed as he slowly mutated into... that thing. It started to spread everywhere, outside the lab too. There is no way we can cover up that we are not a teleport research outpost, so I locked down the lab, but they already know. They sent a squad to rescue us, but...</i>"
/obj/item/paper/crumpled/fluff/meatderelict/shieldgens
name = "shield gate marketing sketch"
default_raw_text = "The <b>QR-109 Shield Gate</b> is a robust hardlight machine capable of producing a strong shield to bar entry. With control panel integration, it can be enabled or disabled from anywhere, such as ship's Bridge, <b>Engineering Bay</b>, or wherever else! <i>The rest is faded...</i>"
/obj/item/paper/crumpled/fluff/meatderelict
name = "engineer note"
default_raw_text = "I've overclocked the power generators to add that needed juice to the experiment, though they're a bit unstable."
/obj/item/paper/crumpled/fluff/meatderelict/fridge
name = "engineer complaint"
default_raw_text = "Whoever keeps stealing my fucking ice cream from my fridge, I swear I will actually fuck you up. It is not cheap to get this delicious ice cream here, nor is it for you. <b>And don't touch my snacks in the drawer!</b>"
/obj/machinery/computer/terminal/meatderelict
upperinfo = "COPYRIGHT 2500 NANOSOFT-TM - DO NOT REDISTRIBUTE - Now with audio!" //not that old
content = list(
"Experimental Test Satellite 37B<br/>Nanotrasen™ approved deep space experimentation lab<br/><br/>Entry 1:<br/><br/>Subject - \[Species 501-C-12\]<br/>Date - \[REDACTED\]<br/>We have acquired a biological sample of unknown origins \[Species 501-C-12\] from an NT outpost on the far reaches. Initial experiments have determined the sample to be a creature never previously recorded. It weighs approximately 7 grams and seems to be docile. Initial examinations determine that it is an extremely fast replicating organism which can alter its physiology to take multiple differing shapes. \[Recording Terminated\]<br/>- Dr. Phil Cornelius",
"Entry 2:<br/><br/>Subject - \[Species 501-C-12\]<br/>Date - \[REDACTED\]<br/>The creature responds to electrical stimuli. It has failed to respond to Light, Heat, Cold, Oxygen, Plasma, CO2, Nitrogen. It, within moments, seemed to have generated muscle tissue within its otherwise shapeless form and moved away from the source of electricity. Feeding the creature has been a simple matter, it consumed just about any form of protein. It appears to rapidly digest and convert forms of protein into more of itself. Any undigestible products are simply left alone. Will continue to monitor creature and provide reports to Nanotrasen Central Command. \[Recording Terminated\]<br/>- Dr. Phil Cornelius",
"Entry 3:<br/><br/>Subject - \[Species 501-C-12\]<br/>Date - \[REDACTED\]<br/>Any attempts at contacting Nanotrasen has failed. I've never seen anything like it. I... I don't think I'm going to survive much longer, I can hear it pushing on my room door. If anyone reads this, let my family know that I- \[Loud crash\]<br/>GET BACK \[Gunshots\]<br/>AHHHHHHHHHHHH \[Recording Terminated\]<br/>- Dr. Phil Cornelius"
)
/obj/machinery/door/puzzle/meatderelict
name = "lockdown door"
desc = "A beaten door, still sturdy. Impervious to conventional methods of destruction, must be a way to open it nearby."
icon = 'icons/obj/doors/puzzledoor/danger.dmi'
puzzle_id = "md_prevault"
/mob/living/basic/meteor_heart/opens_puzzle_door
///the puzzle id we send on death
var/id
///queue size, must match
var/queue_size = 2
/mob/living/basic/meteor_heart/opens_puzzle_door/Initialize(mapload)
. = ..()
new /obj/effect/puzzle_death_signal_holder(loc, src, id, queue_size)
/obj/effect/puzzle_death_signal_holder // ok apparently registering signals on qdeling stuff is not very functional
///delay
var/delay = 2.5 SECONDS
invisibility = INVISIBILITY_ABSTRACT
/obj/effect/puzzle_death_signal_holder/Initialize(mapload, mob/listened, id, queue_size = 2)
. = ..()
if(isnull(id))
return INITIALIZE_HINT_QDEL
RegisterSignal(listened, COMSIG_LIVING_DEATH, PROC_REF(on_death))
SSqueuelinks.add_to_queue(src, id, queue_size)
/obj/effect/puzzle_death_signal_holder/proc/on_death(datum/source)
SIGNAL_HANDLER
addtimer(CALLBACK(src, PROC_REF(send_sig)), delay)
/obj/effect/puzzle_death_signal_holder/proc/send_sig()
SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
qdel(src)
/obj/machinery/puzzle_button/meatderelict
name = "lockdown panel"
desc = "A panel that controls the lockdown of this outpost."
id = "md_prevault"
/obj/machinery/puzzle_button/meatderelict/open_doors()
. = ..()
playsound(src, 'sound/effects/alert.ogg', 100, TRUE)
visible_message(span_warning("[src] lets out an alarm as the lockdown is lifted!"))
/obj/structure/puzzle_blockade/meat
name = "mass of meat and teeth"
desc = "A horrible mass of meat and teeth. Can it see you? You hope not. Virtually indestructible, must be a way around."
icon = 'icons/obj/structures.dmi'
icon_state = "meatblockade"
opacity = TRUE
/obj/structure/puzzle_blockade/meat/try_signal(datum/source)
Shake(duration = 0.5 SECONDS)
addtimer(CALLBACK(src, PROC_REF(open_up)), 0.5 SECONDS)
/obj/structure/puzzle_blockade/meat/proc/open_up()
new /obj/effect/gibspawner/generic(drop_location())
qdel(src)
/obj/lightning_thrower
name = "overcharged SMES"
desc = "An overclocked SMES, bursting with power."
anchored = TRUE
density = TRUE
icon = 'icons/obj/machines/engine/other.dmi'
icon_state = "smes"
/// do we currently want to shock diagonal tiles? if not, we shock cardinals
var/throw_diagonals = FALSE
/// flags we apply to the shock
var/shock_flags = SHOCK_KNOCKDOWN | SHOCK_NOGLOVES
/// damage of the shock
var/shock_damage = 20
/// list of turfs that are currently shocked so we can unregister the signal
var/list/signal_turfs = list()
/// how long do we shock
var/shock_duration = 0.5 SECONDS
/obj/lightning_thrower/Initialize(mapload)
. = ..()
START_PROCESSING(SSprocessing, src)
/obj/lightning_thrower/Destroy()
. = ..()
signal_turfs = null
STOP_PROCESSING(SSprocessing, src)
/obj/lightning_thrower/process(seconds_per_tick)
var/list/dirs = throw_diagonals ? GLOB.diagonals : GLOB.cardinals
throw_diagonals = !throw_diagonals
playsound(src, 'sound/magic/lightningbolt.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
for(var/direction in dirs)
var/victim_turf = get_step(src, direction)
if(isclosedturf(victim_turf))
continue
Beam(victim_turf, icon_state="lightning[rand(1,12)]", time = shock_duration)
RegisterSignal(victim_turf, COMSIG_ATOM_ENTERED, PROC_REF(shock_victim)) //we cant move anyway
signal_turfs += victim_turf
for(var/mob/living/victim in victim_turf)
shock_victim(null, victim)
addtimer(CALLBACK(src, PROC_REF(clear_signals)), shock_duration)
/obj/lightning_thrower/proc/clear_signals(datum/source)
SIGNAL_HANDLER
for(var/turf in signal_turfs)
UnregisterSignal(turf, COMSIG_ATOM_ENTERED)
signal_turfs -= turf
/obj/lightning_thrower/proc/shock_victim(datum/source, mob/living/victim)
SIGNAL_HANDLER
if(!istype(victim))
return
victim.electrocute_act(shock_damage, src, flags = shock_flags)

View File

@@ -0,0 +1,168 @@
/datum/ai_controller/basic_controller/living_limb_flesh
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/basic_melee_attack_subtree
)
/mob/living/basic/living_limb_flesh
name = "living flesh"
desc = "A vaguely leg or arm shaped flesh abomination. It pulses, like a heart."
icon = 'icons/mob/simple/animal.dmi'
icon_state = "limb"
icon_living = "limb"
mob_size = MOB_SIZE_SMALL
basic_mob_flags = DEL_ON_DEATH
faction = list(FACTION_HOSTILE)
melee_damage_lower = 10
melee_damage_upper = 10
health = 20
maxHealth = 20
attack_sound = 'sound/weapons/bite.ogg'
attack_vis_effect = ATTACK_EFFECT_BITE
attack_verb_continuous = "tries desperately to attach to"
attack_verb_simple = "try to attach to"
mob_biotypes = MOB_ORGANIC | MOB_SPECIAL
ai_controller = /datum/ai_controller/basic_controller/living_limb_flesh
/// the meat bodypart we are currently inside, used to like drain nutrition and dismember and shit
var/obj/item/bodypart/current_bodypart
/mob/living/basic/living_limb_flesh/Initialize(mapload, obj/item/bodypart/limb)
. = ..()
AddComponent(/datum/component/swarming, max_x = 8, max_y = 8)
AddElement(/datum/element/death_drops, string_list(list(/obj/effect/gibspawner/generic)))
if(!isnull(limb))
register_to_limb(limb)
/mob/living/basic/living_limb_flesh/Destroy(force)
. = ..()
QDEL_NULL(current_bodypart)
/mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT, times_fired)
. = ..()
if(stat == DEAD)
return
if(isnull(current_bodypart) || isnull(current_bodypart.owner))
return
var/mob/living/carbon/human/victim = current_bodypart.owner
if(prob(SPT_PROB(3, SSMOBS_DT)))
to_chat(victim, span_warning("The thing posing as your limb makes you feel funny...")) //warn em
//firstly as a sideeffect we drain nutrition from our host
victim.adjust_nutrition(-1.5)
if(!prob(SPT_PROB(1.5, SSMOBS_DT)))
return
if(istype(current_bodypart, /obj/item/bodypart/arm))
var/list/candidates = list()
for(var/atom/movable/movable in orange(victim, 1))
if(movable.anchored)
continue
if(movable == victim)
continue
if(!victim.CanReach(movable))
continue
candidates += movable
var/atom/movable/candidate = pick(candidates)
if(isnull(candidate))
return
victim.start_pulling(candidate, supress_message = TRUE)
victim.visible_message(span_warning("[victim][victim.p_s()] [current_bodypart] instinctually starts feeling [candidate]!"))
return
if(HAS_TRAIT(victim, TRAIT_IMMOBILIZED))
return
step(victim, pick(GLOB.cardinals))
to_chat(victim, span_warning("Your [current_bodypart] moves on its own!"))
/mob/living/basic/living_limb_flesh/melee_attack(mob/living/carbon/human/target, list/modifiers, ignore_cooldown)
. = ..()
if (!ishuman(target) || target.stat == DEAD || HAS_TRAIT(target, TRAIT_NODISMEMBER))
return
var/list/zone_candidates = target.get_missing_limbs()
for(var/obj/item/bodypart/bodypart in target.bodyparts)
if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
continue
if(HAS_TRAIT(bodypart, TRAIT_IGNORED_BY_LIVING_FLESH))
continue
if(bodypart.bodypart_flags & BODYPART_UNREMOVABLE)
continue
if(bodypart.brute_dam < 20)
continue
zone_candidates += bodypart.body_zone
if(!length(zone_candidates))
return
var/target_zone = pick(zone_candidates)
var/obj/item/bodypart/target_part = target.get_bodypart(target_zone)
if(isnull(target_part))
target.emote("scream") // dismember already makes them scream so only do this if we aren't doing that
else
target_part.dismember()
var/part_type
switch(target_zone)
if(BODY_ZONE_L_ARM)
part_type = /obj/item/bodypart/arm/left/flesh
if(BODY_ZONE_R_ARM)
part_type = /obj/item/bodypart/arm/right/flesh
if(BODY_ZONE_L_LEG)
part_type = /obj/item/bodypart/leg/left/flesh
if(BODY_ZONE_R_LEG)
part_type = /obj/item/bodypart/leg/right/flesh
target.visible_message(span_danger("[src] [target_part ? "tears off and attaches itself" : "attaches itself"] to where [target][target.p_s()] limb used to be!"))
current_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here
current_bodypart.replace_limb(target, TRUE)
forceMove(current_bodypart)
register_to_limb(current_bodypart)
/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part)
ai_controller.set_ai_status(AI_STATUS_OFF)
RegisterSignal(part, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost))
RegisterSignal(part.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died))
RegisterSignal(part.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect
/mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, source, siemens_coeff, flags)
SIGNAL_HANDLER
if(shock_damage < 10)
return
var/mob/living/carbon/human/part_owner = current_bodypart.owner
if(!detach_self())
return
var/turf/our_location = get_turf(src)
our_location.visible_message(span_warning("[part_owner][part_owner.p_s()] [current_bodypart] begins to convulse wildly!"))
/mob/living/basic/living_limb_flesh/proc/owner_died(datum/source, gibbed)
SIGNAL_HANDLER
if(gibbed)
return
addtimer(CALLBACK(src, PROC_REF(detach_self)), 1 SECONDS) //we need new hosts, dead people suck!
/mob/living/basic/living_limb_flesh/proc/detach_self()
if(isnull(current_bodypart))
return FALSE
current_bodypart.dismember()
return TRUE//on_limb_lost should be called after that
/mob/living/basic/living_limb_flesh/proc/on_limb_lost(atom/movable/source, mob/living/carbon/old_owner, dismembered)
SIGNAL_HANDLER
UnregisterSignal(source, COMSIG_BODYPART_REMOVED)
UnregisterSignal(old_owner, COMSIG_LIVING_ELECTROCUTE_ACT)
UnregisterSignal(old_owner, COMSIG_LIVING_DEATH)
addtimer(CALLBACK(src, PROC_REF(wake_up), source), 2 SECONDS)
/mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb)
ai_controller.set_ai_status(AI_STATUS_ON)
forceMove(limb.drop_location())
current_bodypart = null
qdel(limb)
visible_message(span_warning("[src] begins flailing around!"))
Shake(6, 6, 0.5 SECONDS)

View File

@@ -0,0 +1,96 @@
/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic/on_top/SelectBehaviors(datum/ai_controller/controller, delta_time)
var/mob/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
if(!target || QDELETED(target))
return
if(target.loc != controller.pawn.loc)
return
return ..()
/datum/ai_controller/basic_controller/living_floor
max_target_distance = 2
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic/on_top
)
/mob/living/basic/living_floor
name = "floor"
desc = "The floor you walk on. It looks near-impervious to damage."
icon = 'icons/turf/floors.dmi'
icon_state = "floor"
icon_living = "floor"
mob_size = MOB_SIZE_HUGE
mob_biotypes = MOB_SPECIAL
status_flags = GODMODE //nothing but crowbars may kill us
death_message = ""
unsuitable_atmos_damage = 0
minimum_survivable_temperature = 0
maximum_survivable_temperature = INFINITY
basic_mob_flags = DEL_ON_DEATH
move_resist = INFINITY
density = FALSE
combat_mode = TRUE
layer = TURF_LAYER
plane = FLOOR_PLANE
faction = list(FACTION_HOSTILE)
melee_damage_lower = 20
melee_damage_upper = 40 //pranked.....
attack_sound = 'sound/weapons/bite.ogg'
attack_vis_effect = ATTACK_EFFECT_BITE
attack_verb_continuous = "bites"
attack_verb_simple = "bite"
ai_controller = /datum/ai_controller/basic_controller/living_floor
melee_attack_cooldown = 0.5 SECONDS // get real
var/icon_aggro = "floor-hostile"
var/desc_aggro = "This flooring is alive and filled with teeth, better not step on that. Being covered in plating, it is immune to damage. Seems vulnerable to prying though."
/mob/living/basic/living_floor/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_IMMOBILIZED, INNATE_TRAIT)
var/static/list/connections = list(COMSIG_ATOM_ENTERED = PROC_REF(look_aggro), COMSIG_ATOM_EXITED = PROC_REF(look_deaggro))
AddComponent(/datum/component/connect_range, tracked = src, connections = connections, range = 1, works_in_containers = FALSE)
/mob/living/basic/living_floor/proc/look_aggro(datum/source, mob/living/victim)
SIGNAL_HANDLER
if(!istype(victim) || istype(victim, /mob/living/basic/living_floor) || victim.stat == DEAD)
return
if(victim.loc == loc) //guaranteed bite
var/datum/targetting_datum/basic/targetting = ai_controller.blackboard[BB_TARGETTING_DATUM]
if(targetting.can_attack(src, victim))
melee_attack(victim)
icon_state = icon_aggro
desc = desc_aggro
/mob/living/basic/living_floor/proc/look_deaggro(datum/source, mob/living/victim)
SIGNAL_HANDLER
if(!istype(victim) && !istype(victim, /mob/living/basic/living_floor))
return
icon_state = initial(icon_state)
desc = initial(desc_aggro)
/mob/living/basic/living_floor/med_hud_set_health()
return
/mob/living/basic/living_floor/med_hud_set_status()
return
/mob/living/basic/living_floor/attackby(obj/item/weapon, mob/user, params)
if(weapon.tool_behaviour != TOOL_CROWBAR)
return ..()
balloon_alert(user, "prying...")
playsound(src, 'sound/items/crowbar.ogg', 45, TRUE)
if(!do_after(user, 5 SECONDS, src))
return
new /obj/effect/gibspawner/generic(loc)
qdel(src)
/mob/living/basic/living_floor/white
icon_state = "white"
icon_living = "white"
icon_aggro = "whitefloor-hostile"

View File

@@ -568,3 +568,45 @@
unarmed_damage_low = 7 unarmed_damage_low = 7
unarmed_damage_high = 21 unarmed_damage_high = 21
unarmed_stun_threshold = 11 unarmed_stun_threshold = 11
///flesh
/obj/item/bodypart/arm/left/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
/obj/item/bodypart/arm/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE)
. = ..()
if(!dont_spawn_flesh)
new /mob/living/basic/living_limb_flesh(src, src)
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
/obj/item/bodypart/arm/right/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
/obj/item/bodypart/arm/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE)
. = ..()
if(!dont_spawn_flesh)
new /mob/living/basic/living_limb_flesh(src, src)
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
/obj/item/bodypart/leg/left/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
/obj/item/bodypart/leg/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE)
. = ..()
if(!dont_spawn_flesh)
new /mob/living/basic/living_limb_flesh(src, src)
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
/obj/item/bodypart/leg/right/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
/obj/item/bodypart/leg/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE)
. = ..()
if(!dont_spawn_flesh)
new /mob/living/basic/living_limb_flesh(src, src)
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 359 KiB

BIN
icons/turf/walls/meat.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -730,6 +730,7 @@
#include "code\controllers\subsystem\ping.dm" #include "code\controllers\subsystem\ping.dm"
#include "code\controllers\subsystem\points_of_interest.dm" #include "code\controllers\subsystem\points_of_interest.dm"
#include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\profiler.dm"
#include "code\controllers\subsystem\queuelinks.dm"
#include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radiation.dm"
#include "code\controllers\subsystem\radio.dm" #include "code\controllers\subsystem\radio.dm"
#include "code\controllers\subsystem\radioactive_nebula.dm" #include "code\controllers\subsystem\radioactive_nebula.dm"
@@ -4336,6 +4337,7 @@
#include "code\modules\mapfluff\ruins\spaceruin_code\hilbertshotel.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\hilbertshotel.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\interdyne.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\interdyne.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\listeningstation.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\listeningstation.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\meatderelict.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\meateor.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\meateor.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\originalcontent.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\originalcontent.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\spacehotel.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\spacehotel.dm"
@@ -4580,6 +4582,8 @@
#include "code\modules\mob\living\basic\pets\dog\corgi.dm" #include "code\modules\mob\living\basic\pets\dog\corgi.dm"
#include "code\modules\mob\living\basic\pets\dog\dog_subtypes.dm" #include "code\modules\mob\living\basic\pets\dog\dog_subtypes.dm"
#include "code\modules\mob\living\basic\pets\dog\strippable_items.dm" #include "code\modules\mob\living\basic\pets\dog\strippable_items.dm"
#include "code\modules\mob\living\basic\ruin_defender\flesh.dm"
#include "code\modules\mob\living\basic\ruin_defender\living_floor.dm"
#include "code\modules\mob\living\basic\ruin_defender\skeleton.dm" #include "code\modules\mob\living\basic\ruin_defender\skeleton.dm"
#include "code\modules\mob\living\basic\ruin_defender\stickman.dm" #include "code\modules\mob\living\basic\ruin_defender\stickman.dm"
#include "code\modules\mob\living\basic\space_fauna\ant.dm" #include "code\modules\mob\living\basic\space_fauna\ant.dm"