mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
Sensors can now be printed, removed and installed on jumpsuits. HANDCRAFTED jumpsuits no longer have sensors by default (also mild crafting refactor) (#93121)
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
This commit is contained in:
@@ -132,9 +132,6 @@
|
|||||||
///cancel clean
|
///cancel clean
|
||||||
#define COMSIG_ATOM_CANCEL_CLEAN (1<<0)
|
#define COMSIG_ATOM_CANCEL_CLEAN (1<<0)
|
||||||
|
|
||||||
/// From /obj/item/stack/make_item()
|
|
||||||
#define COMSIG_ATOM_CONSTRUCTED "atom_constructed"
|
|
||||||
|
|
||||||
/// From /obj/effect/particle_effect/sparks/proc/sparks_touched(datum/source, atom/movable/singed)
|
/// From /obj/effect/particle_effect/sparks/proc/sparks_touched(datum/source, atom/movable/singed)
|
||||||
#define COMSIG_ATOM_TOUCHED_SPARKS "atom_touched_sparks"
|
#define COMSIG_ATOM_TOUCHED_SPARKS "atom_touched_sparks"
|
||||||
#define COMSIG_ATOM_TOUCHED_HAZARDOUS_SPARKS "atom_touched_hazardous_sparks"
|
#define COMSIG_ATOM_TOUCHED_HAZARDOUS_SPARKS "atom_touched_hazardous_sparks"
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
#define COMPONENT_BULLET_PIERCED (1<<2)
|
#define COMPONENT_BULLET_PIERCED (1<<2)
|
||||||
///from base of atom/bullet_act(): (/obj/proj, def_zone, piercing_hit, blocked)
|
///from base of atom/bullet_act(): (/obj/proj, def_zone, piercing_hit, blocked)
|
||||||
#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act"
|
#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act"
|
||||||
///from base of atom/on_craft_completion(): (components, datum/crafting_recipe/current_recipe)
|
///from base of atom/on_craft_completion(): (components, datum/crafting_recipe/current_recipe, atom/crafter)
|
||||||
#define COMSIG_ATOM_ON_CRAFT "atom_checkparts"
|
#define COMSIG_ATOM_ON_CRAFT "atom_on_craft_completion"
|
||||||
///from base of atom/used_in_craft(): (atom/result)
|
///from base of atom/used_in_craft(): (atom/result)
|
||||||
#define COMSIG_ATOM_USED_IN_CRAFT "atom_used_in_craft"
|
#define COMSIG_ATOM_USED_IN_CRAFT "atom_used_in_craft"
|
||||||
///from base of atom/blob_act(): (/obj/structure/blob)
|
///from base of atom/blob_act(): (/obj/structure/blob)
|
||||||
|
|||||||
@@ -229,6 +229,10 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
|
|||||||
|
|
||||||
var/holding = user.get_active_held_item()
|
var/holding = user.get_active_held_item()
|
||||||
|
|
||||||
|
#ifdef UNIT_TESTS
|
||||||
|
timed_action_flags &= ~IGNORE_SLOWDOWNS //it shouldn't stop unit test dummies from being fast as hell
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!(timed_action_flags & IGNORE_SLOWDOWNS))
|
if(!(timed_action_flags & IGNORE_SLOWDOWNS))
|
||||||
delay *= user.cached_multiplicative_actions_slowdown
|
delay *= user.cached_multiplicative_actions_slowdown
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,11 @@ GLOBAL_LIST_INIT(backpacklist, list(
|
|||||||
GMESSENGER,
|
GMESSENGER,
|
||||||
LSATCHEL,
|
LSATCHEL,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
GLOBAL_LIST_INIT(suit_sensor_mode_to_defines, list(
|
||||||
|
"Off" = SENSOR_OFF,
|
||||||
|
"Binary vitals" = SENSOR_LIVING,
|
||||||
|
"Exact vitals" = SENSOR_VITALS,
|
||||||
|
"Tracking beacon" = SENSOR_COORDS,
|
||||||
|
))
|
||||||
|
|||||||
@@ -372,19 +372,17 @@
|
|||||||
if(recipe.structures)
|
if(recipe.structures)
|
||||||
requirements += recipe.structures
|
requirements += recipe.structures
|
||||||
|
|
||||||
|
var/list/surroundings = get_environment(atom, recipe.blacklist)
|
||||||
for(var/path_key in requirements)
|
for(var/path_key in requirements)
|
||||||
var/list/surroundings
|
|
||||||
var/amount = recipe.reqs?[path_key] || recipe.machinery?[path_key] || recipe.structures?[path_key]
|
var/amount = recipe.reqs?[path_key] || recipe.machinery?[path_key] || recipe.structures?[path_key]
|
||||||
if(!amount)//since machinery & structures can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it!
|
if(!amount)//since machinery & structures can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it!
|
||||||
continue
|
continue
|
||||||
surroundings = get_environment(atom, recipe.blacklist)
|
|
||||||
surroundings -= return_list
|
|
||||||
if(ispath(path_key, /datum/reagent))
|
if(ispath(path_key, /datum/reagent))
|
||||||
if(!holder)
|
if(!holder)
|
||||||
holder = new(INFINITY, NO_REACT) //an infinite volume holder than can store reagents without reacting
|
holder = new(INFINITY, NO_REACT) //an infinite volume holder than can store reagents without reacting
|
||||||
return_list += holder
|
return_list += holder
|
||||||
while(amount > 0)
|
while(amount > 0)
|
||||||
var/obj/item/reagent_containers/container = locate() in surroundings
|
var/obj/item/reagent_containers/container = (locate() in surroundings) || (locate() in return_list)
|
||||||
if(isnull(container)) //This would only happen if the previous checks for contents and tools were flawed.
|
if(isnull(container)) //This would only happen if the previous checks for contents and tools were flawed.
|
||||||
stack_trace("couldn't fulfill the required amount for [path_key]. Dangit")
|
stack_trace("couldn't fulfill the required amount for [path_key]. Dangit")
|
||||||
if(QDELING(container)) //it's deleting...
|
if(QDELING(container)) //it's deleting...
|
||||||
@@ -394,7 +392,6 @@
|
|||||||
if(reagent_volume)
|
if(reagent_volume)
|
||||||
container.reagents.trans_to(holder, min(amount, reagent_volume), target_id = path_key, no_react = TRUE)
|
container.reagents.trans_to(holder, min(amount, reagent_volume), target_id = path_key, no_react = TRUE)
|
||||||
amount -= reagent_volume
|
amount -= reagent_volume
|
||||||
surroundings -= container
|
|
||||||
container.update_appearance(UPDATE_ICON)
|
container.update_appearance(UPDATE_ICON)
|
||||||
else if(ispath(path_key, /obj/item/stack))
|
else if(ispath(path_key, /obj/item/stack))
|
||||||
var/obj/item/stack/tally_stack
|
var/obj/item/stack/tally_stack
|
||||||
|
|||||||
@@ -336,11 +336,12 @@
|
|||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure a list of atoms/reagents exists inside this atom
|
* Called whenever an item is crafted, either via stack recipes or crafting recipes from the crafting menu
|
||||||
*
|
*
|
||||||
* Cycles through the list of movables used up in the recipe and calls used_in_craft() for each of them
|
* By default, it just cycles through the list of movables used in the recipe and calls used_in_craft() for each of them,
|
||||||
* then it either moves them inside the object or deletes
|
* then it either moves them inside the object if they're in the list of parts for the recipe
|
||||||
* them depending on whether they're in the list of parts for the recipe or not
|
* or deletes them if they're not.
|
||||||
|
* The proc can be overriden by subtypes, as long as it always call parent.
|
||||||
*/
|
*/
|
||||||
/atom/proc/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
|
/atom/proc/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
|
||||||
SHOULD_CALL_PARENT(TRUE)
|
SHOULD_CALL_PARENT(TRUE)
|
||||||
@@ -349,17 +350,17 @@
|
|||||||
var/list/parts_by_type = remaining_parts?.Copy()
|
var/list/parts_by_type = remaining_parts?.Copy()
|
||||||
for(var/parttype in parts_by_type) //necessary for our is_type_in_list() call with the zebra arg set to true
|
for(var/parttype in parts_by_type) //necessary for our is_type_in_list() call with the zebra arg set to true
|
||||||
parts_by_type[parttype] = parttype
|
parts_by_type[parttype] = parttype
|
||||||
for(var/obj/item/item in components) // machinery or structure objects in the list are guaranteed to be used up. We only check items.
|
for(var/atom/movable/movable as anything in components) // machinery or structure objects in the list are guaranteed to be used up. We only check items.
|
||||||
item.used_in_craft(src, current_recipe)
|
movable.used_in_craft(src, current_recipe)
|
||||||
var/matched_type = is_type_in_list(item, parts_by_type, zebra = TRUE)
|
var/matched_type = is_type_in_list(movable, parts_by_type, zebra = TRUE)
|
||||||
if(!matched_type)
|
if(!matched_type)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if(isliving(item.loc))
|
if(isliving(movable.loc) && isitem(movable))
|
||||||
var/mob/living/living = item.loc
|
var/mob/living/living = movable.loc
|
||||||
living.transferItemToLoc(item, src)
|
living.transferItemToLoc(movable, src)
|
||||||
else
|
else
|
||||||
item.forceMove(src)
|
movable.forceMove(src)
|
||||||
|
|
||||||
if(matched_type)
|
if(matched_type)
|
||||||
remaining_parts[matched_type] -= 1
|
remaining_parts[matched_type] -= 1
|
||||||
|
|||||||
@@ -594,7 +594,8 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \
|
|||||||
. = ..()
|
. = ..()
|
||||||
. += GLOB.durathread_recipes
|
. += GLOB.durathread_recipes
|
||||||
|
|
||||||
/obj/item/stack/sheet/durathread/on_item_crafted(mob/builder, atom/created)
|
/obj/item/stack/sheet/durathread/used_in_craft(atom/created, datum/crafting_recipe/recipe)
|
||||||
|
. = ..()
|
||||||
created.set_armor_rating(CONSUME, max(50, created.get_armor_rating(CONSUME)))
|
created.set_armor_rating(CONSUME, max(50, created.get_armor_rating(CONSUME)))
|
||||||
|
|
||||||
/obj/item/stack/sheet/cotton
|
/obj/item/stack/sheet/cotton
|
||||||
|
|||||||
@@ -454,22 +454,22 @@
|
|||||||
var/turf/covered_turf = builder.drop_location()
|
var/turf/covered_turf = builder.drop_location()
|
||||||
if(!isturf(covered_turf))
|
if(!isturf(covered_turf))
|
||||||
return
|
return
|
||||||
var/turf/created_turf = covered_turf.place_on_top(recipe.result_type, flags = CHANGETURF_INHERIT_AIR)
|
created = covered_turf.place_on_top(recipe.result_type, flags = CHANGETURF_INHERIT_AIR)
|
||||||
builder.balloon_alert(builder, "placed [ispath(recipe.result_type, /turf/open) ? "floor" : "wall"]")
|
builder.balloon_alert(builder, "placed [ispath(recipe.result_type, /turf/open) ? "floor" : "wall"]")
|
||||||
if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit))
|
if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit))
|
||||||
created_turf.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount)
|
created.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount)
|
||||||
|
|
||||||
else
|
else
|
||||||
created = new recipe.result_type(builder.drop_location())
|
created = new recipe.result_type(builder.drop_location())
|
||||||
builder.balloon_alert(builder, "built item")
|
builder.balloon_alert(builder, "built item")
|
||||||
|
|
||||||
if(created)
|
// split the material and use it for the craft
|
||||||
|
var/obj/item/stack/used_stack = split_stack(recipe.req_amount * multiplier)
|
||||||
|
if(ismovable(created))
|
||||||
created.setDir(builder.dir)
|
created.setDir(builder.dir)
|
||||||
SEND_SIGNAL(created, COMSIG_ATOM_CONSTRUCTED, builder)
|
created.on_craft_completion(list(used_stack), null, builder)
|
||||||
on_item_crafted(builder, created)
|
qdel(used_stack) //you've outlived your purpose
|
||||||
|
|
||||||
// Use up the material
|
|
||||||
use(recipe.req_amount * multiplier)
|
|
||||||
builder.investigate_log("crafted [recipe.title]", INVESTIGATE_CRAFTING)
|
builder.investigate_log("crafted [recipe.title]", INVESTIGATE_CRAFTING)
|
||||||
|
|
||||||
// Apply mat datums
|
// Apply mat datums
|
||||||
@@ -497,10 +497,6 @@
|
|||||||
|
|
||||||
return TRUE
|
return TRUE
|
||||||
|
|
||||||
/// Run special logic on created items after they've been successfully crafted.
|
|
||||||
/obj/item/stack/proc/on_item_crafted(mob/builder, atom/created)
|
|
||||||
return
|
|
||||||
|
|
||||||
/obj/item/stack/vv_edit_var(vname, vval)
|
/obj/item/stack/vv_edit_var(vname, vval)
|
||||||
if(vname == NAMEOF(src, amount))
|
if(vname == NAMEOF(src, amount))
|
||||||
add(clamp(vval, 1-amount, max_amount - amount)) //there must always be one.
|
add(clamp(vval, 1-amount, max_amount - amount)) //there must always be one.
|
||||||
|
|||||||
@@ -232,9 +232,12 @@
|
|||||||
if(!flushing && cover_open)
|
if(!flushing && cover_open)
|
||||||
. += "[base_icon_state]-water"
|
. += "[base_icon_state]-water"
|
||||||
|
|
||||||
/obj/structure/toilet/atom_deconstruct(dissambled = TRUE)
|
/obj/structure/toilet/dump_contents()
|
||||||
for(var/obj/toilet_item in cistern_items)
|
for(var/obj/toilet_item in (cistern_items + fishes))
|
||||||
toilet_item.forceMove(drop_location())
|
toilet_item.forceMove(drop_location())
|
||||||
|
|
||||||
|
/obj/structure/toilet/atom_deconstruct(dissambled = TRUE)
|
||||||
|
dump_contents()
|
||||||
if(buildstacktype)
|
if(buildstacktype)
|
||||||
new buildstacktype(loc,buildstackamount)
|
new buildstacktype(loc,buildstackamount)
|
||||||
else
|
else
|
||||||
@@ -242,8 +245,6 @@
|
|||||||
new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1))
|
new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1))
|
||||||
if(has_water_reclaimer)
|
if(has_water_reclaimer)
|
||||||
new /obj/item/stock_parts/water_recycler(drop_location())
|
new /obj/item/stock_parts/water_recycler(drop_location())
|
||||||
if(stuck_item)
|
|
||||||
stuck_item.forceMove(drop_location())
|
|
||||||
|
|
||||||
/obj/structure/toilet/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
/obj/structure/toilet/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||||
if(user.combat_mode)
|
if(user.combat_mode)
|
||||||
|
|||||||
@@ -19,12 +19,11 @@
|
|||||||
cult_team = null
|
cult_team = null
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/obj/structure/destructible/cult/Initialize(mapload)
|
/obj/structure/destructible/cult/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
|
||||||
. = ..()
|
. = ..()
|
||||||
RegisterSignal(src, COMSIG_ATOM_CONSTRUCTED, PROC_REF(on_constructed))
|
if(!ismob(crafter))
|
||||||
|
return
|
||||||
/obj/structure/destructible/cult/proc/on_constructed(datum/source, mob/builder)
|
var/mob/living/builder = crafter
|
||||||
SIGNAL_HANDLER
|
|
||||||
var/datum/antagonist/cult/cultist = builder.mind?.has_antag_datum(/datum/antagonist/cult, TRUE)
|
var/datum/antagonist/cult/cultist = builder.mind?.has_antag_datum(/datum/antagonist/cult, TRUE)
|
||||||
cult_team = cultist?.get_team()
|
cult_team = cultist?.get_team()
|
||||||
|
|
||||||
|
|||||||
84
code/modules/clothing/under/_suit_sensor.dm
Normal file
84
code/modules/clothing/under/_suit_sensor.dm
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
///The item representing suit sensors when removed from a suit or dress (obj/item/clothing/under)
|
||||||
|
/obj/item/suit_sensor
|
||||||
|
name = "suit sensor"
|
||||||
|
desc = "That thingamabob medbay keeps telling you to set to 'Tracking Beacon'. It needs to be attached to a worn suit or dress to work."
|
||||||
|
icon = 'icons/obj/devices/tracker.dmi'
|
||||||
|
icon_state = "suit_sensor"
|
||||||
|
base_icon_state = "suit_sensor"
|
||||||
|
obj_flags = CONDUCTS_ELECTRICITY
|
||||||
|
w_class = WEIGHT_CLASS_TINY
|
||||||
|
custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT, /datum/material/glass= SMALL_MATERIAL_AMOUNT)
|
||||||
|
drop_sound = 'sound/items/handling/component_drop.ogg'
|
||||||
|
pickup_sound = 'sound/items/handling/component_pickup.ogg'
|
||||||
|
throwforce = 2
|
||||||
|
throw_speed = 3
|
||||||
|
throw_range = 7
|
||||||
|
///The current sensor mode, inherited from the clothing it's cut from. Can also be changed when using it in hand.
|
||||||
|
var/sensor_mode = SENSOR_OFF
|
||||||
|
///Suit sensors are busted when struck by a heavy electromagnetic pulse.
|
||||||
|
var/broken = FALSE
|
||||||
|
|
||||||
|
/obj/item/suit_sensor/examine(mob/user)
|
||||||
|
. = ..()
|
||||||
|
if(broken)
|
||||||
|
. += span_warning("It's currently broken. You can use a piece of [EXAMINE_HINT("cable")] to fix it.")
|
||||||
|
else
|
||||||
|
. += span_notice("It's currently set on '[GLOB.suit_sensor_mode_to_defines.Find(sensor_mode + 1)]'.")
|
||||||
|
|
||||||
|
/obj/item/suit_sensor/update_overlays()
|
||||||
|
. = ..()
|
||||||
|
if(broken)
|
||||||
|
return
|
||||||
|
switch(sensor_mode)
|
||||||
|
if(SENSOR_LIVING)
|
||||||
|
. += "suit_sensor_binary"
|
||||||
|
if(SENSOR_VITALS)
|
||||||
|
. += "suit_sensor_vitals"
|
||||||
|
if(SENSOR_COORDS)
|
||||||
|
. += "suit_sensor_tracking"
|
||||||
|
|
||||||
|
/obj/item/suit_sensor/proc/set_mode(new_mode)
|
||||||
|
if(sensor_mode == new_mode)
|
||||||
|
return FALSE
|
||||||
|
sensor_mode = new_mode
|
||||||
|
update_appearance(UPDATE_OVERLAYS)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/obj/item/suit_sensor/attack_self(mob/living/user)
|
||||||
|
. = ..()
|
||||||
|
if(!(user.mobility_flags & MOBILITY_USE) || !IsReachableBy(user))
|
||||||
|
return FALSE
|
||||||
|
if(broken)
|
||||||
|
balloon_alert(user, "fix it first!")
|
||||||
|
return
|
||||||
|
var/current_mode_text = GLOB.suit_sensor_mode_to_defines[sensor_mode + 1]
|
||||||
|
var/new_mode = tgui_input_list(user, "Select a sensor mode", "Suit Sensors", GLOB.suit_sensor_mode_to_defines, current_mode_text)
|
||||||
|
if(isnull(new_mode) || broken|| !(user.mobility_flags & MOBILITY_USE) || !IsReachableBy(user))
|
||||||
|
user.balloon_alert(user, "can't do that now!")
|
||||||
|
return
|
||||||
|
set_mode(GLOB.suit_sensor_mode_to_defines[new_mode])
|
||||||
|
balloon_alert(user, "sensor set to '[LOWER_TEXT(new_mode)]'")
|
||||||
|
|
||||||
|
/obj/item/suit_sensor/emp_act(severity)
|
||||||
|
. = ..()
|
||||||
|
if(. & EMP_PROTECT_SELF || broken)
|
||||||
|
return
|
||||||
|
|
||||||
|
if(severity <= EMP_HEAVY)
|
||||||
|
broken = TRUE
|
||||||
|
else
|
||||||
|
set_mode(pick(SENSOR_OFF, SENSOR_OFF, SENSOR_OFF, SENSOR_LIVING, SENSOR_LIVING, SENSOR_VITALS, SENSOR_VITALS, SENSOR_COORDS))
|
||||||
|
playsound(source = src, soundin = 'sound/effects/sparks/sparks3.ogg', vol = 75, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
|
||||||
|
|
||||||
|
/obj/item/suit_sensor/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||||
|
if(!istype(tool, /obj/item/stack/cable_coil))
|
||||||
|
return ..()
|
||||||
|
if(!broken)
|
||||||
|
balloon_alert(user, "not broken!")
|
||||||
|
return ITEM_INTERACT_BLOCKING
|
||||||
|
var/obj/item/stack/cable_coil/cabling = tool
|
||||||
|
cabling.use(1)
|
||||||
|
balloon_alert(user, "suit sensor repaired")
|
||||||
|
broken = FALSE
|
||||||
|
update_appearance(UPDATE_OVERLAYS)
|
||||||
|
return ITEM_INTERACT_SUCCESS
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
/// Does this undersuit spawn with a random sensor value
|
/// Does this undersuit spawn with a random sensor value
|
||||||
var/random_sensor = TRUE
|
var/random_sensor = TRUE
|
||||||
/// What is the active sensor mode of this udnersuit
|
/// What is the active sensor mode of this udnersuit
|
||||||
var/sensor_mode = NO_SENSORS
|
var/sensor_mode = SENSOR_OFF
|
||||||
|
|
||||||
// Accessory handling (Can be componentized eventually)
|
// Accessory handling (Can be componentized eventually)
|
||||||
/// The max number of accessories we can have on this suit.
|
/// The max number of accessories we can have on this suit.
|
||||||
@@ -60,6 +60,19 @@
|
|||||||
register_context()
|
register_context()
|
||||||
AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING|ITEM_SLOT_NECK, body = TRUE)
|
AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING|ITEM_SLOT_NECK, body = TRUE)
|
||||||
|
|
||||||
|
/obj/item/clothing/under/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
|
||||||
|
. = ..()
|
||||||
|
var/obj/item/clothing/under/any_original = locate() in components
|
||||||
|
if(!any_original)
|
||||||
|
set_has_sensor(NO_SENSORS)
|
||||||
|
return
|
||||||
|
set_has_sensor(any_original.has_sensor)
|
||||||
|
set_sensor_mode(any_original.sensor_mode)
|
||||||
|
|
||||||
|
/obj/item/clothing/under/used_in_craft(atom/result, datum/crafting_recipe/current_recipe)
|
||||||
|
. = ..()
|
||||||
|
dump_attachments()
|
||||||
|
|
||||||
/obj/item/clothing/under/setup_reskinning()
|
/obj/item/clothing/under/setup_reskinning()
|
||||||
if(!check_setup_reskinning())
|
if(!check_setup_reskinning())
|
||||||
return
|
return
|
||||||
@@ -72,7 +85,7 @@
|
|||||||
|
|
||||||
var/changed = FALSE
|
var/changed = FALSE
|
||||||
|
|
||||||
if((isnull(held_item) || held_item == src) && has_sensor == HAS_SENSORS)
|
if(has_sensor == HAS_SENSORS && (isnull(held_item) || held_item == src))
|
||||||
context[SCREENTIP_CONTEXT_RMB] = "Toggle suit sensors"
|
context[SCREENTIP_CONTEXT_RMB] = "Toggle suit sensors"
|
||||||
context[SCREENTIP_CONTEXT_CTRL_LMB] = "Set suit sensors to tracking"
|
context[SCREENTIP_CONTEXT_CTRL_LMB] = "Set suit sensors to tracking"
|
||||||
changed = TRUE
|
changed = TRUE
|
||||||
@@ -85,10 +98,18 @@
|
|||||||
context[SCREENTIP_CONTEXT_ALT_RMB] = "Remove accessory"
|
context[SCREENTIP_CONTEXT_ALT_RMB] = "Remove accessory"
|
||||||
changed = TRUE
|
changed = TRUE
|
||||||
|
|
||||||
if(istype(held_item, /obj/item/stack/cable_coil) && has_sensor == BROKEN_SENSORS)
|
if(has_sensor == BROKEN_SENSORS && istype(held_item, /obj/item/stack/cable_coil))
|
||||||
context[SCREENTIP_CONTEXT_LMB] = "Repair suit sensors"
|
context[SCREENTIP_CONTEXT_LMB] = "Repair suit sensors"
|
||||||
changed = TRUE
|
changed = TRUE
|
||||||
|
|
||||||
|
if(has_sensor == NO_SENSORS)
|
||||||
|
if(istype(held_item, /obj/item/suit_sensor))
|
||||||
|
context[SCREENTIP_CONTEXT_LMB] = "Install suit sensors"
|
||||||
|
changed = TRUE
|
||||||
|
else if(held_item?.tool_behaviour == TOOL_WIRECUTTER)
|
||||||
|
context[SCREENTIP_CONTEXT_LMB] = "Cut suit sensors"
|
||||||
|
changed = TRUE
|
||||||
|
|
||||||
if(can_adjust && adjusted != DIGITIGRADE_STYLE)
|
if(can_adjust && adjusted != DIGITIGRADE_STYLE)
|
||||||
context[SCREENTIP_CONTEXT_ALT_LMB] = "Wear [adjusted == ALT_STYLE ? "normally" : "casually"]"
|
context[SCREENTIP_CONTEXT_ALT_LMB] = "Wear [adjusted == ALT_STYLE ? "normally" : "casually"]"
|
||||||
changed = TRUE
|
changed = TRUE
|
||||||
@@ -114,15 +135,55 @@
|
|||||||
if (blood_overlay)
|
if (blood_overlay)
|
||||||
. += blood_overlay
|
. += blood_overlay
|
||||||
|
|
||||||
/obj/item/clothing/under/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
|
/obj/item/clothing/under/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||||
if(repair_sensors(attacking_item, user))
|
if(istype(tool, /obj/item/stack/cable_coil))
|
||||||
return TRUE
|
if(!repair_sensors(user))
|
||||||
|
return ITEM_INTERACT_BLOCKING
|
||||||
|
var/obj/item/stack/cable_coil/cabling = tool
|
||||||
|
cabling.use(1)
|
||||||
|
cabling.visible_message(span_notice("[user] repairs the suit sensors on [src] with [cabling]."))
|
||||||
|
return ITEM_INTERACT_SUCCESS
|
||||||
|
|
||||||
if(istype(attacking_item, /obj/item/clothing/accessory))
|
if(istype(tool, /obj/item/clothing/accessory))
|
||||||
return attach_accessory(attacking_item, user)
|
return attach_accessory(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||||
|
|
||||||
|
if(istype(tool, /obj/item/suit_sensor))
|
||||||
|
if(has_sensor != NO_SENSORS)
|
||||||
|
balloon_alert(user, "already has sensors!")
|
||||||
|
return ITEM_INTERACT_BLOCKING
|
||||||
|
balloon_alert(user, "installing sensors...")
|
||||||
|
if(!do_after(user, 5 SECONDS, target = src))
|
||||||
|
return ITEM_INTERACT_BLOCKING
|
||||||
|
var/obj/item/suit_sensor/sensor = tool
|
||||||
|
if(sensor.broken)
|
||||||
|
set_has_sensor(BROKEN_SENSORS)
|
||||||
|
else
|
||||||
|
set_has_sensor(HAS_SENSORS)
|
||||||
|
set_sensor_mode(sensor.sensor_mode)
|
||||||
|
qdel(tool)
|
||||||
|
balloon_alert(user, "sensors installed")
|
||||||
|
playsound(source = src, soundin = 'sound/effects/sparks/sparks4.ogg', vol = 50, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
|
||||||
|
return ITEM_INTERACT_SUCCESS
|
||||||
|
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
|
/obj/item/clothing/under/wirecutter_act(mob/living/user, obj/item/tool)
|
||||||
|
if(has_sensor == NO_SENSORS)
|
||||||
|
balloon_alert(user, "doesn't have sensors!")
|
||||||
|
return ITEM_INTERACT_BLOCKING
|
||||||
|
balloon_alert(user, "cutting out sensors...")
|
||||||
|
if(!do_after(user, 5 SECONDS, target = src))
|
||||||
|
return ITEM_INTERACT_BLOCKING
|
||||||
|
var/obj/item/suit_sensor/sensor = new (drop_location())
|
||||||
|
if(sensor.IsReachableBy(user))
|
||||||
|
user.put_in_hands(sensor)
|
||||||
|
if(has_sensor == BROKEN_SENSORS)
|
||||||
|
sensor.broken = TRUE
|
||||||
|
else
|
||||||
|
sensor.set_mode(sensor_mode)
|
||||||
|
set_has_sensor(NO_SENSORS)
|
||||||
|
return ITEM_INTERACT_SUCCESS
|
||||||
|
|
||||||
/obj/item/clothing/under/attack_hand_secondary(mob/user, params)
|
/obj/item/clothing/under/attack_hand_secondary(mob/user, params)
|
||||||
. = ..()
|
. = ..()
|
||||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||||
@@ -144,7 +205,7 @@
|
|||||||
if(damaged_state == CLOTHING_SHREDDED && has_sensor > NO_SENSORS)
|
if(damaged_state == CLOTHING_SHREDDED && has_sensor > NO_SENSORS)
|
||||||
break_sensors()
|
break_sensors()
|
||||||
else if(damaged_state == CLOTHING_PRISTINE && has_sensor == BROKEN_SENSORS)
|
else if(damaged_state == CLOTHING_PRISTINE && has_sensor == BROKEN_SENSORS)
|
||||||
repair_sensors(cable_required = FALSE)
|
repair_sensors()
|
||||||
update_appearance()
|
update_appearance()
|
||||||
|
|
||||||
/obj/item/clothing/under/visual_equipped(mob/user, slot)
|
/obj/item/clothing/under/visual_equipped(mob/user, slot)
|
||||||
@@ -189,23 +250,12 @@
|
|||||||
/**
|
/**
|
||||||
* Repair the suit sensors and update the mob's status on the global sensor list.
|
* Repair the suit sensors and update the mob's status on the global sensor list.
|
||||||
* Can be called either through player action such as repairing with coil, or as part of a general fixing proc
|
* Can be called either through player action such as repairing with coil, or as part of a general fixing proc
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* * attacking_item - the item being used for the repair, if any
|
|
||||||
* * user - mob that's doing the repair
|
|
||||||
* * cable_required - set to FALSE to bypass consuming cable coil
|
|
||||||
*/
|
*/
|
||||||
/obj/item/clothing/under/proc/repair_sensors(obj/item/attacking_item, mob/user, cable_required = TRUE)
|
/obj/item/clothing/under/proc/repair_sensors(mob/user)
|
||||||
if(has_sensor != BROKEN_SENSORS)
|
if(has_sensor != BROKEN_SENSORS)
|
||||||
return
|
if(user)
|
||||||
|
balloon_alert(user, "sensors [has_sensor == NO_SENSORS ? "missing" : "not broken"]!")
|
||||||
if(cable_required)
|
return FALSE
|
||||||
if(!istype(attacking_item, /obj/item/stack/cable_coil))
|
|
||||||
return
|
|
||||||
var/obj/item/stack/cable_coil/cabling = attacking_item
|
|
||||||
if(!cabling.use(1))
|
|
||||||
return
|
|
||||||
cabling.visible_message(span_notice("[user] repairs the suit sensors on [src] with [cabling]."))
|
|
||||||
|
|
||||||
playsound(source = src, soundin = 'sound/effects/sparks/sparks4.ogg', vol = 100, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
|
playsound(source = src, soundin = 'sound/effects/sparks/sparks4.ogg', vol = 100, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
|
||||||
set_has_sensor(HAS_SENSORS)
|
set_has_sensor(HAS_SENSORS)
|
||||||
@@ -393,6 +443,9 @@
|
|||||||
. += "Its vital tracker appears to be enabled."
|
. += "Its vital tracker appears to be enabled."
|
||||||
if(SENSOR_COORDS)
|
if(SENSOR_COORDS)
|
||||||
. += "Its vital tracker and tracking beacon appear to be enabled."
|
. += "Its vital tracker and tracking beacon appear to be enabled."
|
||||||
|
else
|
||||||
|
. += span_tooltip("You can always get new suit sensors to install from a lathe.", "It isn't equipped with medical sensors.")
|
||||||
|
|
||||||
if(LAZYLEN(attached_accessories))
|
if(LAZYLEN(attached_accessories))
|
||||||
var/list/accessories = list_accessories_with_icon(user)
|
var/list/accessories = list_accessories_with_icon(user)
|
||||||
. += "It has [english_list(accessories)] attached."
|
. += "It has [english_list(accessories)] attached."
|
||||||
@@ -414,14 +467,14 @@
|
|||||||
if(!can_toggle_sensors(user_mob))
|
if(!can_toggle_sensors(user_mob))
|
||||||
return
|
return
|
||||||
|
|
||||||
var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon")
|
var/current_mode_text = GLOB.suit_sensor_mode_to_defines[sensor_mode + 1]
|
||||||
var/switchMode = tgui_input_list(user_mob, "Select a sensor mode", "Suit Sensors", modes, modes[sensor_mode + 1])
|
var/new_mode = tgui_input_list(user_mob, "Select a sensor mode", "Suit Sensors", GLOB.suit_sensor_mode_to_defines, current_mode_text)
|
||||||
if(isnull(switchMode))
|
if(isnull(new_mode))
|
||||||
return
|
return
|
||||||
if(!can_toggle_sensors(user_mob))
|
if(!can_toggle_sensors(user_mob))
|
||||||
return
|
return
|
||||||
|
|
||||||
set_sensor_mode(modes.Find(switchMode) - 1)
|
set_sensor_mode(GLOB.suit_sensor_mode_to_defines[new_mode])
|
||||||
if (loc == user_mob)
|
if (loc == user_mob)
|
||||||
switch(sensor_mode)
|
switch(sensor_mode)
|
||||||
if(SENSOR_OFF)
|
if(SENSOR_OFF)
|
||||||
|
|||||||
@@ -157,6 +157,21 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
|||||||
/mob/living/carbon/human/consistent/domutcheck()
|
/mob/living/carbon/human/consistent/domutcheck()
|
||||||
return // We skipped adding any mutations so this runtimes
|
return // We skipped adding any mutations so this runtimes
|
||||||
|
|
||||||
|
/mob/living/carbon/human/consistent/slow
|
||||||
|
|
||||||
|
#ifdef UNIT_TESTS
|
||||||
|
//unit test dummies should be very fast with actions
|
||||||
|
/mob/living/carbon/human/dummy/consistent/initialize_actionspeed()
|
||||||
|
add_or_update_variable_actionspeed_modifier(/datum/actionspeed_modifier/base, multiplicative_slowdown = -1)
|
||||||
|
|
||||||
|
/mob/living/carbon/human/consistent/initialize_actionspeed()
|
||||||
|
add_or_update_variable_actionspeed_modifier(/datum/actionspeed_modifier/base, multiplicative_slowdown = -1)
|
||||||
|
|
||||||
|
//this one gives us a small window of time for checks on asynced actions.
|
||||||
|
/mob/living/carbon/human/consistent/slow/initialize_actionspeed()
|
||||||
|
add_or_update_variable_actionspeed_modifier(/datum/actionspeed_modifier/base, multiplicative_slowdown = 0.1)
|
||||||
|
#endif
|
||||||
|
|
||||||
//Inefficient pooling/caching way.
|
//Inefficient pooling/caching way.
|
||||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||||
GLOBAL_LIST_EMPTY(dummy_mob_list)
|
GLOBAL_LIST_EMPTY(dummy_mob_list)
|
||||||
|
|||||||
@@ -495,6 +495,18 @@
|
|||||||
)
|
)
|
||||||
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE
|
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE
|
||||||
|
|
||||||
|
/datum/design/suit_sensor
|
||||||
|
name = "Suit Sensor"
|
||||||
|
id = "suit_sensor"
|
||||||
|
build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE
|
||||||
|
materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT)
|
||||||
|
build_path = /obj/item/suit_sensor
|
||||||
|
category = list(
|
||||||
|
RND_CATEGORY_INITIAL,
|
||||||
|
RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_ASSEMBLIES,
|
||||||
|
)
|
||||||
|
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SECURITY
|
||||||
|
|
||||||
/datum/design/conveyor_belt
|
/datum/design/conveyor_belt
|
||||||
name = "Conveyor Belt"
|
name = "Conveyor Belt"
|
||||||
id = "conveyor_belt"
|
id = "conveyor_belt"
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"jerrycan",
|
"jerrycan",
|
||||||
"reflex_hammer",
|
"reflex_hammer",
|
||||||
"blood_scanner",
|
"blood_scanner",
|
||||||
|
"suit_sensor",
|
||||||
)
|
)
|
||||||
experiments_to_unlock = list(
|
experiments_to_unlock = list(
|
||||||
/datum/experiment/autopsy/human,
|
/datum/experiment/autopsy/human,
|
||||||
|
|||||||
@@ -91,22 +91,25 @@
|
|||||||
// Only followers of Asclepius have the ability to use Healing Touch and perform miracle feats of surgery.
|
// Only followers of Asclepius have the ability to use Healing Touch and perform miracle feats of surgery.
|
||||||
// Prevents people from performing multiple simultaneous surgeries unless they're holding a Rod of Asclepius.
|
// Prevents people from performing multiple simultaneous surgeries unless they're holding a Rod of Asclepius.
|
||||||
|
|
||||||
surgery.step_in_progress = TRUE
|
var/interaction_key = HAS_TRAIT(user, TRAIT_HIPPOCRATIC_OATH) ? target : DOAFTER_SOURCE_SURGERY
|
||||||
var/speed_mod = 1
|
if(DOING_INTERACTION(user, interaction_key))
|
||||||
var/fail_prob = 0//100 - fail_prob = success_prob
|
user.balloon_alert(user, "already doing surgery!")
|
||||||
var/advance = FALSE
|
return FALSE
|
||||||
|
|
||||||
if(!chem_check(target))
|
if(!chem_check(target))
|
||||||
user.balloon_alert(user, "missing [LOWER_TEXT(get_chem_list())]!")
|
user.balloon_alert(user, "missing [LOWER_TEXT(get_chem_list())]!")
|
||||||
to_chat(user, span_warning("[target] is missing the [LOWER_TEXT(get_chem_list())] required to perform this surgery step!"))
|
to_chat(user, span_warning("[target] is missing the [LOWER_TEXT(get_chem_list())] required to perform this surgery step!"))
|
||||||
surgery.step_in_progress = FALSE
|
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
if(preop(user, target, target_zone, tool, surgery) == SURGERY_STEP_FAIL)
|
if(preop(user, target, target_zone, tool, surgery) == SURGERY_STEP_FAIL)
|
||||||
update_surgery_mood(target, SURGERY_STATE_FAILURE)
|
update_surgery_mood(target, SURGERY_STATE_FAILURE)
|
||||||
surgery.step_in_progress = FALSE
|
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
|
surgery.step_in_progress = TRUE
|
||||||
|
var/speed_mod = 1
|
||||||
|
var/fail_prob = 0//100 - fail_prob = success_prob
|
||||||
|
var/advance = FALSE
|
||||||
|
|
||||||
update_surgery_mood(target, SURGERY_STATE_STARTED)
|
update_surgery_mood(target, SURGERY_STATE_STARTED)
|
||||||
play_preop_sound(user, target, target_zone, tool, surgery) // Here because most steps overwrite preop
|
play_preop_sound(user, target, target_zone, tool, surgery) // Here because most steps overwrite preop
|
||||||
|
|
||||||
@@ -153,7 +156,7 @@
|
|||||||
|
|
||||||
var/was_sleeping = (target.stat != DEAD && target.IsSleeping())
|
var/was_sleeping = (target.stat != DEAD && target.IsSleeping())
|
||||||
|
|
||||||
if(do_after(user, modded_time, target = target, interaction_key = user.has_status_effect(/datum/status_effect/hippocratic_oath) ? target : DOAFTER_SOURCE_SURGERY)) //If we have the hippocratic oath, we can perform one surgery on each target, otherwise we can only do one surgery in total.
|
if(do_after(user, modded_time, target = target, interaction_key = interaction_key)) //If we have the hippocratic oath, we can perform one surgery on each target, otherwise we can only do one surgery in total.
|
||||||
|
|
||||||
if((prob(100-fail_prob) || (iscyborg(user) && !silicons_obey_prob)) && !try_to_fail)
|
if((prob(100-fail_prob) || (iscyborg(user) && !silicons_obey_prob)) && !try_to_fail)
|
||||||
if(success(user, target, target_zone, tool, surgery))
|
if(success(user, target, target_zone, tool, surgery))
|
||||||
|
|||||||
@@ -306,6 +306,7 @@
|
|||||||
#include "stuns.dm"
|
#include "stuns.dm"
|
||||||
#include "style_hotswapping.dm"
|
#include "style_hotswapping.dm"
|
||||||
#include "subsystem_init.dm"
|
#include "subsystem_init.dm"
|
||||||
|
#include "suit_sensor.dm"
|
||||||
#include "suit_storage_icons.dm"
|
#include "suit_storage_icons.dm"
|
||||||
#include "surgeries.dm"
|
#include "surgeries.dm"
|
||||||
#include "syringe_gun.dm"
|
#include "syringe_gun.dm"
|
||||||
|
|||||||
@@ -57,4 +57,4 @@
|
|||||||
|
|
||||||
butcher.put_in_active_hand(gun, forced = TRUE)
|
butcher.put_in_active_hand(gun, forced = TRUE)
|
||||||
click_wrapper(butcher, meat, list(RIGHT_CLICK = TRUE, BUTTON = RIGHT_CLICK))
|
click_wrapper(butcher, meat, list(RIGHT_CLICK = TRUE, BUTTON = RIGHT_CLICK))
|
||||||
TEST_ASSERT(DOING_INTERACTION(butcher, meat), "The butcher did not start butchering the monkey when using a bayonetted weapon.")
|
TEST_ASSERT(QDELETED(meat), "The butcher did not butchering the monkey when using a bayonetted weapon.")
|
||||||
|
|||||||
43
code/modules/unit_tests/suit_sensor.dm
Normal file
43
code/modules/unit_tests/suit_sensor.dm
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
///Test that ensures that basic functions and interactions around suit sensors are working
|
||||||
|
/datum/unit_test/suit_sensor
|
||||||
|
|
||||||
|
/datum/unit_test/suit_sensor/Run()
|
||||||
|
var/mob/living/carbon/human/consistent/dummy = allocate(__IMPLIED_TYPE__)
|
||||||
|
var/obj/item/clothing/under/sensor_test/under = allocate(__IMPLIED_TYPE__)
|
||||||
|
|
||||||
|
dummy.equip_to_slot_or_del(under, ITEM_SLOT_ICLOTHING)
|
||||||
|
|
||||||
|
TEST_ASSERT(under.set_sensor_mode(SENSOR_LIVING), "couldn't set the suit sensor mode to '[GLOB.suit_sensor_mode_to_defines[SENSOR_LIVING + 1]]'")
|
||||||
|
TEST_ASSERT((dummy in GLOB.suit_sensors_list), "couldn't find the dummy in the GLOB.suit_sensors_list")
|
||||||
|
|
||||||
|
var/obj/item/wirecutters/cutter = allocate(__IMPLIED_TYPE__)
|
||||||
|
dummy.put_in_active_hand(cutter, forced = TRUE)
|
||||||
|
click_wrapper(dummy, under) //cut sensor
|
||||||
|
TEST_ASSERT_EQUAL(under.has_sensor, NO_SENSORS, "couldn't properly cut suit sensor from the jumpsuit")
|
||||||
|
|
||||||
|
var/obj/item/suit_sensor/sensor = dummy.is_holding_item_of_type(__IMPLIED_TYPE__)
|
||||||
|
TEST_ASSERT(sensor, "dummy isn't holding the cut sensor")
|
||||||
|
//we set it to sensor_living before, remember?
|
||||||
|
TEST_ASSERT_EQUAL(sensor.sensor_mode, SENSOR_LIVING, "cut sensor isn't set to '[GLOB.suit_sensor_mode_to_defines[SENSOR_LIVING + 1]]'")
|
||||||
|
TEST_ASSERT(sensor.set_mode(SENSOR_OFF), "couldn't set cut sensor's mode to '[GLOB.suit_sensor_mode_to_defines[SENSOR_OFF + 1]]'")
|
||||||
|
sensor.emp_act(EMP_HEAVY)
|
||||||
|
TEST_ASSERT(sensor.broken, "cut sensor wasn't broken by EMP")
|
||||||
|
|
||||||
|
dummy.dropItemToGround(cutter) //thank you for your service, wirecutters o7
|
||||||
|
var/obj/item/stack/cable_coil/thirty/coil = allocate(__IMPLIED_TYPE__)
|
||||||
|
dummy.put_in_active_hand(coil, forced = TRUE)
|
||||||
|
click_wrapper(dummy, sensor) //fix sensor
|
||||||
|
TEST_ASSERT(!sensor.broken, "cut sensor couldn't be fixed by cable coil")
|
||||||
|
|
||||||
|
dummy.swap_hand(dummy.get_held_index_of_item(sensor))
|
||||||
|
click_wrapper(dummy, under) //install sensor
|
||||||
|
TEST_ASSERT_EQUAL(under.has_sensor, HAS_SENSORS, "couldn't properly install suit sensor on the jumpsuit")
|
||||||
|
under.emp_act(EMP_HEAVY)
|
||||||
|
TEST_ASSERT_EQUAL(under.has_sensor, BROKEN_SENSORS, "the jumpsuit sensor wasn't broken by EMP")
|
||||||
|
dummy.swap_hand(dummy.get_held_index_of_item(coil))
|
||||||
|
click_wrapper(dummy, under) //fix sensor, again
|
||||||
|
TEST_ASSERT_EQUAL(under.has_sensor, HAS_SENSORS, "couldn't fix the jumpsuit sensor with cable coil")
|
||||||
|
|
||||||
|
|
||||||
|
/obj/item/clothing/under/sensor_test
|
||||||
|
random_sensor = FALSE
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
TEST_ASSERT_EQUAL(alice.facial_hair_color, COLOR_LIGHT_BROWN, "Bob's head was transplanted onto Alice's body, but their facial hair color is not COLOR_LIGHT_BROWN")
|
TEST_ASSERT_EQUAL(alice.facial_hair_color, COLOR_LIGHT_BROWN, "Bob's head was transplanted onto Alice's body, but their facial hair color is not COLOR_LIGHT_BROWN")
|
||||||
|
|
||||||
/datum/unit_test/multiple_surgeries/Run()
|
/datum/unit_test/multiple_surgeries/Run()
|
||||||
var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent)
|
var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent/slow)
|
||||||
var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human/consistent)
|
var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human/consistent)
|
||||||
var/mob/living/carbon/human/patient_one = allocate(/mob/living/carbon/human/consistent)
|
var/mob/living/carbon/human/patient_one = allocate(/mob/living/carbon/human/consistent)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
@@ -4156,6 +4156,7 @@
|
|||||||
#include "code\modules\clothing\suits\wetfloor.dm"
|
#include "code\modules\clothing\suits\wetfloor.dm"
|
||||||
#include "code\modules\clothing\suits\wintercoats.dm"
|
#include "code\modules\clothing\suits\wintercoats.dm"
|
||||||
#include "code\modules\clothing\suits\wiz_robe.dm"
|
#include "code\modules\clothing\suits\wiz_robe.dm"
|
||||||
|
#include "code\modules\clothing\under\_suit_sensor.dm"
|
||||||
#include "code\modules\clothing\under\_under.dm"
|
#include "code\modules\clothing\under\_under.dm"
|
||||||
#include "code\modules\clothing\under\color.dm"
|
#include "code\modules\clothing\under\color.dm"
|
||||||
#include "code\modules\clothing\under\costume.dm"
|
#include "code\modules\clothing\under\costume.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user