[MIRROR] new space ruin, the biological research outpost [MDB IGNORE] (#24662)
* new space ruin, the biological research outpost (#79149) ## About The Pull Request  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>
4338
_maps/RandomRuins/SpaceRuins/meatderelict.dmm
Normal 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"
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
68
code/controllers/subsystem/queuelinks.dm
Normal 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
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
156
code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm
Normal 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)
|
||||||
168
code/modules/mob/living/basic/ruin_defender/flesh.dm
Normal 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)
|
||||||
96
code/modules/mob/living/basic/ruin_defender/living_floor.dm
Normal 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"
|
||||||
@@ -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)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 199 KiB |
BIN
icons/obj/doors/puzzledoor/danger.dmi
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 358 KiB After Width: | Height: | Size: 359 KiB |
BIN
icons/turf/walls/meat.dmi
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -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"
|
||||||
|
|||||||