mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
Melee attack chain now has a list passed along with it, `attack_modifiers`, which you can stick force modifiers to change the resulting attack This is basically a soft implementation of damage packets until a more definitive pr, but one that only applies to item attack chain, and not unarmed attacks. This change was done to facilitate a baton refactor - batons no longer hack together their own attack chain, and are now integrated straight into the real attack chain. This refactor itself was done because batons don't send any attack signals, which has been annoying in the past (for swing combat). 🆑 Melbert refactor: Batons have been refactored again. Baton stuns now properly count as an attack, when before it was a nothing. Report any oddities, particularly in regards to harmbatonning vs normal batonning. refactor: The method of adjusting item damage mid-attack has been refactored - some affected items include the Nullblade and knives. Report any strange happenings with damage numbers. refactor: A few objects have been moved to the new interaction chain - records consoles, mawed crucible, alien weeds and space vines, hedges, restaurant portals, and some mobs - to name a few. fix: Spears only deal bonus damage against secure lockers, not all closet types (including crates) /🆑
425 lines
14 KiB
Plaintext
425 lines
14 KiB
Plaintext
#define SCANGATE_NONE "Off"
|
|
#define SCANGATE_MINDSHIELD "Mindshield"
|
|
#define SCANGATE_DISEASE "Disease"
|
|
#define SCANGATE_GUNS "Guns"
|
|
#define SCANGATE_WANTED "Wanted"
|
|
#define SCANGATE_SPECIES "Species"
|
|
#define SCANGATE_NUTRITION "Nutrition"
|
|
#define SCANGATE_GENDER "Gender" // BUBBER EDIT ADDITION
|
|
#define SCANGATE_NANITES "Nanites" // BUBBER EDIT ADDITION
|
|
|
|
/obj/machinery/scanner_gate
|
|
name = "scanner gate"
|
|
desc = "A gate able to perform mid-depth scans on any organisms who pass under it."
|
|
icon = 'icons/obj/machines/scangate.dmi'
|
|
icon_state = "scangate"
|
|
layer = ABOVE_MOB_LAYER
|
|
circuit = /obj/item/circuitboard/machine/scanner_gate
|
|
COOLDOWN_DECLARE(next_beep)
|
|
|
|
var/scanline_timer
|
|
///Bool to check if the scanner's controls are locked by an ID.
|
|
var/locked = FALSE
|
|
///Which setting is the scanner checking for? See defines in scanner_gate.dm for the list.
|
|
var/scangate_mode = SCANGATE_NONE
|
|
///Is searching for a disease, what severity is enough to trigger the gate?
|
|
var/disease_threshold = DISEASE_SEVERITY_MINOR
|
|
///If scanning for a specific species, what species is it looking for?
|
|
var/detect_species_id = SPECIES_HUMAN
|
|
///Flips all scan results for inverse scanning. Signals if scan returns false.
|
|
var/reverse = FALSE
|
|
///If scanning for nutrition, what level of nutrition will trigger the scanner?
|
|
var/detect_nutrition = NUTRITION_LEVEL_FAT
|
|
///Will the assembly on the pass wire activate if the scanner resolves green (Pass) on crossing?
|
|
var/light_pass = FALSE
|
|
///Will the assembly on the pass wire activate if the scanner resolves red (fail) on crossing?
|
|
var/light_fail = FALSE
|
|
///Does the scanner ignore light_pass and light_fail for sending signals?
|
|
var/ignore_signals = FALSE
|
|
var/detect_gender = "male" //SKYRAT EDIT ADDITION - MORE SCANNER GATE OPTIONS
|
|
var/nanite_cloud = 1 // BUBBER EDIT ADDITION - NANITES
|
|
///Modifier to the chance of scanner being false positive/negative
|
|
var/minus_false_beep = 0
|
|
///Base false positive/negative chance
|
|
var/base_false_beep = 5
|
|
///List of species that can be scanned by the gate. Supports adding more species' IDs during in-game.
|
|
var/static/list/available_species = list(
|
|
SPECIES_HUMAN,
|
|
SPECIES_LIZARD,
|
|
SPECIES_FLYPERSON,
|
|
SPECIES_FELINE,
|
|
SPECIES_PLASMAMAN,
|
|
SPECIES_MOTH,
|
|
SPECIES_JELLYPERSON,
|
|
SPECIES_PODPERSON,
|
|
SPECIES_GOLEM,
|
|
SPECIES_ZOMBIE,
|
|
)
|
|
/// All scan modes available to the scanner
|
|
var/static/list/all_modes = list(
|
|
SCANGATE_NONE,
|
|
SCANGATE_MINDSHIELD,
|
|
SCANGATE_DISEASE,
|
|
SCANGATE_GUNS,
|
|
SCANGATE_WANTED,
|
|
SCANGATE_SPECIES,
|
|
SCANGATE_NUTRITION,
|
|
SCANGATE_GENDER, // BUBBER EDIT ADDITION
|
|
SCANGATE_NANITES, // BUBBER EDIT ADDITION
|
|
)
|
|
/// All disease severity thresholds available to the scanner
|
|
var/static/list/all_disease_thresholds = list(
|
|
DISEASE_SEVERITY_POSITIVE,
|
|
DISEASE_SEVERITY_NONTHREAT,
|
|
DISEASE_SEVERITY_MINOR,
|
|
DISEASE_SEVERITY_MEDIUM,
|
|
DISEASE_SEVERITY_HARMFUL,
|
|
DISEASE_SEVERITY_DANGEROUS,
|
|
DISEASE_SEVERITY_BIOHAZARD,
|
|
)
|
|
/// All nutrition levels available to the scanner
|
|
var/static/list/nutrition_modes = list(
|
|
"Starving",
|
|
"Obese",
|
|
)
|
|
/// Overlay object we're using for scanlines
|
|
var/obj/effect/overlay/scanline = null
|
|
|
|
/obj/machinery/scanner_gate/Initialize(mapload)
|
|
. = ..()
|
|
set_wires(new /datum/wires/scanner_gate(src))
|
|
set_scanline("passive")
|
|
var/static/list/loc_connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
|
)
|
|
AddElement(/datum/element/connect_loc, loc_connections)
|
|
AddComponent(/datum/component/simple_rotation, ROTATION_IGNORE_ANCHORED|ROTATION_REQUIRE_WRENCH|ROTATION_NEEDS_UNBLOCKED)
|
|
register_context()
|
|
|
|
/obj/machinery/scanner_gate/Destroy(force)
|
|
QDEL_NULL(scanline)
|
|
return ..()
|
|
|
|
/obj/machinery/scanner_gate/RefreshParts()
|
|
. = ..()
|
|
for(var/datum/stock_part/scanning_module/scanning_module in component_parts)
|
|
minus_false_beep = scanning_module.tier //The better are scanninning modules - the lower is chance of False Positives
|
|
|
|
/obj/machinery/scanner_gate/setDir(newdir)
|
|
. = ..()
|
|
scanline?.setDir(newdir)
|
|
|
|
/obj/machinery/scanner_gate/examine(mob/user)
|
|
. = ..()
|
|
|
|
. += span_notice("It's set to scan for [span_boldnotice(scangate_mode)].")
|
|
if(locked)
|
|
. += span_notice("The control panel is ID-locked. Swipe a valid ID to unlock it.")
|
|
else
|
|
. += span_notice("The control panel is unlocked. Swipe an ID to lock it.")
|
|
|
|
/obj/machinery/scanner_gate/proc/on_entered(datum/source, atom/movable/thing)
|
|
SIGNAL_HANDLER
|
|
INVOKE_ASYNC(src, PROC_REF(auto_scan), thing)
|
|
|
|
/obj/machinery/scanner_gate/proc/auto_scan(atom/movable/thing)
|
|
if(!(machine_stat & (BROKEN|NOPOWER)) && anchored && !panel_open)
|
|
perform_scan(thing)
|
|
|
|
/obj/machinery/scanner_gate/proc/set_scanline(scanline_type, duration)
|
|
if (!isnull(scanline))
|
|
vis_contents -= scanline
|
|
else
|
|
scanline = new(src)
|
|
scanline.icon = icon
|
|
scanline.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
scanline.layer = layer
|
|
deltimer(scanline_timer)
|
|
if (isnull(scanline_type))
|
|
if(duration)
|
|
scanline_timer = addtimer(CALLBACK(src, PROC_REF(set_scanline), "passive"), duration, TIMER_STOPPABLE)
|
|
return
|
|
scanline.icon_state = scanline_type
|
|
vis_contents += scanline
|
|
if(duration)
|
|
scanline_timer = addtimer(CALLBACK(src, PROC_REF(set_scanline), "passive"), duration, TIMER_STOPPABLE)
|
|
|
|
/obj/machinery/scanner_gate/power_change()
|
|
. = ..()
|
|
if (machine_stat & (NOPOWER | BROKEN))
|
|
set_scanline(null)
|
|
return
|
|
set_scanline("passive")
|
|
|
|
/obj/machinery/scanner_gate/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
|
|
var/obj/item/card/id/card = attacking_item.GetID()
|
|
if(card)
|
|
if(locked)
|
|
if(allowed(user))
|
|
locked = FALSE
|
|
req_access = list()
|
|
to_chat(user, span_notice("You unlock [src]."))
|
|
else if(!(obj_flags & EMAGGED))
|
|
to_chat(user, span_notice("You lock [src] with [attacking_item]."))
|
|
var/list/access = attacking_item.GetAccess()
|
|
req_access = access
|
|
locked = TRUE
|
|
else
|
|
to_chat(user, span_warning("You try to lock [src] with [attacking_item], but nothing happens."))
|
|
else
|
|
if(!locked && default_deconstruction_screwdriver(user, "[initial(icon_state)]_open", initial(icon_state), attacking_item))
|
|
return
|
|
if(panel_open && is_wire_tool(attacking_item))
|
|
wires.interact(user)
|
|
return ..()
|
|
|
|
/obj/machinery/scanner_gate/emag_act(mob/user, obj/item/card/emag/emag_card)
|
|
if(obj_flags & EMAGGED)
|
|
return FALSE
|
|
locked = FALSE
|
|
req_access = list()
|
|
obj_flags |= EMAGGED
|
|
balloon_alert(user, "id checker disabled")
|
|
return TRUE
|
|
|
|
/obj/machinery/scanner_gate/proc/perform_scan(atom/movable/thing)
|
|
var/beep = FALSE
|
|
var/color = null
|
|
var/detected_thing = null
|
|
var/bypassed = FALSE
|
|
playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE)
|
|
switch(scangate_mode)
|
|
if(SCANGATE_NONE)
|
|
return
|
|
if(SCANGATE_WANTED)
|
|
if(ishuman(thing))
|
|
detected_thing = "Warrant"
|
|
var/mob/living/carbon/human/scanned_human = thing
|
|
var/perpname = scanned_human.get_face_name(scanned_human.get_id_name())
|
|
var/datum/record/crew/target = find_record(perpname)
|
|
if(!target || (target.wanted_status == WANTED_ARREST))
|
|
beep = TRUE
|
|
if(SCANGATE_MINDSHIELD)
|
|
detected_thing = "Mindshield"
|
|
if(ishuman(thing))
|
|
var/mob/living/carbon/human/scanned_human = thing
|
|
if(HAS_TRAIT(scanned_human, TRAIT_MINDSHIELD))
|
|
beep = TRUE
|
|
if(SCANGATE_DISEASE)
|
|
detected_thing = "[disease_threshold] infection"
|
|
if(iscarbon(thing))
|
|
var/mob/living/carbon/scanned_carbon = thing
|
|
if(get_disease_severity_value(scanned_carbon.check_virus()) >= get_disease_severity_value(disease_threshold))
|
|
beep = TRUE
|
|
if(SCANGATE_SPECIES)
|
|
if(ishuman(thing))
|
|
var/mob/living/carbon/human/scanned_human = thing
|
|
var/datum/species/scan_species = /datum/species/human
|
|
if(detect_species_id && (detect_species_id in available_species))
|
|
scan_species = GLOB.species_list[detect_species_id]
|
|
detected_thing = scan_species.name
|
|
if(is_species(scanned_human, scan_species))
|
|
beep = TRUE
|
|
if(detect_species_id == SPECIES_ZOMBIE) //Can detect dormant zombies
|
|
detected_thing = "Romerol infection"
|
|
if(scanned_human.get_organ_slot(ORGAN_SLOT_ZOMBIE))
|
|
beep = TRUE
|
|
if(SCANGATE_GUNS)
|
|
detected_thing = "Weapons"
|
|
if(isgun(thing))
|
|
beep = TRUE
|
|
else if(ishuman(thing))
|
|
var/mob/living/carbon/human/scanned_human = thing
|
|
var/obj/item/card/id/idcard = scanned_human.get_idcard(hand_first = FALSE)
|
|
for(var/obj/item/scanned_item in scanned_human.get_all_contents_skipping_traits(TRAIT_CONTRABAND_BLOCKER))
|
|
if(isgun(scanned_item))
|
|
if((!HAS_TRAIT(scanned_human, TRAIT_MINDSHIELD)) && (isnull(idcard) || !(ACCESS_WEAPONS in idcard.access))) // mindshield or ID card with weapons access, like bartender
|
|
beep = TRUE
|
|
break
|
|
bypassed = TRUE
|
|
break
|
|
else
|
|
for(var/obj/item/content in thing.get_all_contents_skipping_traits(TRAIT_CONTRABAND_BLOCKER))
|
|
if(isgun(content))
|
|
beep = TRUE
|
|
break
|
|
if(SCANGATE_NUTRITION)
|
|
if(ishuman(thing))
|
|
var/mob/living/carbon/human/scanned_human = thing
|
|
if(scanned_human.nutrition <= detect_nutrition && detect_nutrition == NUTRITION_LEVEL_STARVING)
|
|
beep = TRUE
|
|
detected_thing = "Starvation"
|
|
if(scanned_human.nutrition >= detect_nutrition && detect_nutrition == NUTRITION_LEVEL_FAT)
|
|
beep = TRUE
|
|
detected_thing = "Obesity"
|
|
//SKYRAT EDIT BEGIN - MORE SCANNER GATE OPTIONS
|
|
if(SCANGATE_GENDER)
|
|
detected_thing = detect_gender
|
|
if(ishuman(thing))
|
|
var/mob/living/carbon/human/scanned_human = thing
|
|
if((scanned_human.gender in list("male", "female"))) //funny thing: nb people will always get by the scan B)
|
|
if(scanned_human.gender == detect_gender)
|
|
beep = TRUE
|
|
//SKYRAT EDIT END - MORE SCANNER GATE OPTIONS
|
|
// BUBBER EDIT ADDITION BEGIN - NANITES
|
|
if(SCANGATE_NANITES)
|
|
detected_thing = "Nanite cloud #[nanite_cloud]"
|
|
if(isliving(thing))
|
|
var/detected_cloud_id = SEND_SIGNAL(thing, COMSIG_NANITE_GET_CLOUD)
|
|
if(detected_cloud_id == nanite_cloud)
|
|
beep = TRUE
|
|
// BUBBER EDIT ADDITION END - NANITES
|
|
|
|
if(reverse)
|
|
beep = !beep
|
|
|
|
if(prob(base_false_beep - minus_false_beep)) //False positive/negative
|
|
beep = prob(50)
|
|
|
|
if(beep)
|
|
alarm_beep(detected_thing)
|
|
SEND_SIGNAL(src, COMSIG_SCANGATE_PASS_TRIGGER, thing)
|
|
if(!ignore_signals)
|
|
color = wires.get_color_of_wire(WIRE_ACCEPT)
|
|
var/obj/item/assembly/assembly = wires.get_attached(color)
|
|
assembly?.activate()
|
|
else
|
|
SEND_SIGNAL(src, COMSIG_SCANGATE_PASS_NO_TRIGGER, thing)
|
|
if(bypassed)
|
|
say("[detected_thing] detection bypassed.")
|
|
if(!ignore_signals)
|
|
color = wires.get_color_of_wire(WIRE_DENY)
|
|
var/obj/item/assembly/assembly = wires.get_attached(color)
|
|
assembly?.activate()
|
|
set_scanline("scanning", 1 SECONDS)
|
|
|
|
use_energy(active_power_usage)
|
|
|
|
/obj/machinery/scanner_gate/proc/alarm_beep(detected_thing)
|
|
if(!COOLDOWN_FINISHED(src, next_beep))
|
|
return
|
|
|
|
if(detected_thing)
|
|
say("[detected_thing][reverse ? " not " : " "]detected!!")
|
|
|
|
COOLDOWN_START(src, next_beep, 2 SECONDS)
|
|
playsound(source = src, soundin = 'sound/machines/scanner/scanbuzz.ogg', vol = 30, vary = FALSE, extrarange = MEDIUM_RANGE_SOUND_EXTRARANGE, falloff_distance = 4)
|
|
set_scanline("alarm", 2 SECONDS)
|
|
|
|
/obj/machinery/scanner_gate/can_interact(mob/user)
|
|
if(locked)
|
|
return FALSE
|
|
return ..()
|
|
|
|
/obj/machinery/scanner_gate/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "ScannerGate", name)
|
|
ui.open()
|
|
|
|
/obj/machinery/scanner_gate/ui_static_data(mob/user)
|
|
. = ..()
|
|
for(var/species_id in available_species)
|
|
var/datum/species/specie = GLOB.species_list[species_id]
|
|
.["available_species"] += list(list(
|
|
"specie_name" = capitalize(format_text(specie.name)),
|
|
"specie_id" = species_id,
|
|
))
|
|
// BUBBER EDIT ADDITION BEGIN - NANITES
|
|
.["min_cloud_id"] = NANITE_MIN_CLOUD_ID
|
|
.["max_cloud_id"] = NANITE_MAX_CLOUD_ID
|
|
// BUBBER EDIT ADDITION END - NANITES
|
|
|
|
/obj/machinery/scanner_gate/ui_data()
|
|
var/list/data = list()
|
|
data["locked"] = locked
|
|
data["scan_mode"] = scangate_mode
|
|
data["reverse"] = reverse
|
|
data["disease_threshold"] = disease_threshold
|
|
data["target_species_id"] = detect_species_id
|
|
data["target_nutrition"] = detect_nutrition
|
|
data["target_gender"] = detect_gender //SKYRAT EDIT - MORE SCANNER GATE OPTIONS
|
|
data["nanite_cloud"] = nanite_cloud // BUBBER EDIT ADDITION - NANITES
|
|
data["target_zombie"] = (detect_species_id == SPECIES_ZOMBIE)
|
|
return data
|
|
|
|
/obj/machinery/scanner_gate/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
switch(action)
|
|
if("set_mode")
|
|
var/new_mode = params["new_mode"]
|
|
if(!new_mode || !(new_mode in all_modes))
|
|
return
|
|
scangate_mode = new_mode
|
|
. = TRUE
|
|
if("toggle_reverse")
|
|
reverse = !reverse
|
|
. = TRUE
|
|
if("toggle_lock")
|
|
if(allowed(usr))
|
|
locked = !locked
|
|
. = TRUE
|
|
if("set_disease_threshold")
|
|
var/new_threshold = params["new_threshold"]
|
|
if(!new_threshold || !(new_threshold in all_disease_thresholds))
|
|
return
|
|
disease_threshold = new_threshold
|
|
. = TRUE
|
|
if("set_target_species")
|
|
var/new_specie_id = params["new_species_id"]
|
|
if(!new_specie_id || !(new_specie_id in available_species))
|
|
return
|
|
detect_species_id = new_specie_id
|
|
. = TRUE
|
|
if("set_target_nutrition")
|
|
var/new_nutrition = params["new_nutrition"]
|
|
if(!new_nutrition || !(new_nutrition in nutrition_modes))
|
|
return
|
|
switch(new_nutrition)
|
|
if("Starving")
|
|
detect_nutrition = NUTRITION_LEVEL_STARVING
|
|
if("Obese")
|
|
detect_nutrition = NUTRITION_LEVEL_FAT
|
|
. = TRUE
|
|
//SKYRAT EDIT BEGIN - MORE SCANNER GATE OPTIONS
|
|
if("set_target_gender")
|
|
var/new_gender = params["new_gender"]
|
|
var/gender_list = list(
|
|
"Male",
|
|
"Female"
|
|
)
|
|
if(new_gender && (new_gender in gender_list))
|
|
switch(new_gender)
|
|
if("Male")
|
|
detect_gender = "male"
|
|
if("Female")
|
|
detect_gender = "female"
|
|
. = TRUE
|
|
//SKYRAT EDIT END - MORE SCANNER GATE OPTIONS
|
|
// BUBBER EDIT ADDITION BEGIN - NANITES
|
|
if("set_nanite_cloud")
|
|
var/new_cloud_id = params["new_cloud"]
|
|
if(!isnum(new_cloud_id))
|
|
return
|
|
nanite_cloud = clamp(new_cloud_id, NANITE_MIN_CLOUD_ID+1, NANITE_MAX_CLOUD_ID)
|
|
. = TRUE
|
|
// BUBBER EDIT ADDITION END - NANITES
|
|
|
|
/obj/machinery/scanner_gate/preset_guns
|
|
locked = TRUE
|
|
req_access = list(ACCESS_SECURITY)
|
|
scangate_mode = SCANGATE_GUNS
|
|
|
|
#undef SCANGATE_NONE
|
|
#undef SCANGATE_MINDSHIELD
|
|
#undef SCANGATE_DISEASE
|
|
#undef SCANGATE_GUNS
|
|
#undef SCANGATE_WANTED
|
|
#undef SCANGATE_SPECIES
|
|
#undef SCANGATE_NUTRITION
|
|
#undef SCANGATE_GENDER //BUBBER EDIT
|
|
#undef SCANGATE_NANITES //BUBBER EDIT
|