From 1caba774316571d4ffae48ccfbd90267fe464836 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Tue, 29 Aug 2017 17:16:17 -0500 Subject: [PATCH 001/102] Server tools versioning and fix to displayed testmerges --- code/__DEFINES/server_tools.dm | 4 +++- code/datums/helper_datums/getrev.dm | 10 ++++++++-- code/modules/server_tools/server_tools.dm | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/code/__DEFINES/server_tools.dm b/code/__DEFINES/server_tools.dm index a4afa58a87..d2be3e578e 100644 --- a/code/__DEFINES/server_tools.dm +++ b/code/__DEFINES/server_tools.dm @@ -9,7 +9,9 @@ //keep these in sync with TGS3 #define SERVICE_WORLD_PARAM "server_service" -#define SERVICE_PR_TEST_JSON "..\\..\\prtestjob.json" +#define SERVICE_VERSION_PARAM "server_service_version" +#define SERVICE_PR_TEST_JSON "prtestjob.json" +#define SERVICE_PR_TEST_JSON_OLD "..\\..\\[SERVICE_PR_TEST_JSON]" #define SERVICE_CMD_HARD_REBOOT "hard_reboot" #define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown" diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 806f48a24f..c6958fa997 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -6,8 +6,14 @@ var/date /datum/getrev/New() - if(world.RunningService() && fexists(SERVICE_PR_TEST_JSON)) - testmerge = json_decode(file2text(SERVICE_PR_TEST_JSON)) + if(world.RunningService()) + var/file_name + if(ServiceVersion()) //will return null for versions < 3.0.91.0 + file_name = SERVICE_PR_TEST_JSON_OLD + else + file_name = SERVICE_PR_TEST_JSON + if(fexists(file_name)) + testmerge = json_decode(file2text(file_name)) #ifdef SERVERTOOLS else if(!world.RunningService() && fexists("../prtestjob.lk")) //tgs2 support var/list/tmp = world.file2list("..\\prtestjob.lk") diff --git a/code/modules/server_tools/server_tools.dm b/code/modules/server_tools/server_tools.dm index be8c80ac24..f16a56b2f9 100644 --- a/code/modules/server_tools/server_tools.dm +++ b/code/modules/server_tools/server_tools.dm @@ -4,6 +4,10 @@ GLOBAL_PROTECT(reboot_mode) /world/proc/RunningService() return params[SERVICE_WORLD_PARAM] +/proc/ServiceVersion() + if(world.RunningService()) + return world.params[SERVICE_VERSION_PARAM] + /world/proc/ExportService(command) return RunningService() && shell("python code/modules/server_tools/nudge.py \"[command]\"") == 0 From acd129ac37292a70ac03b43a1f91a90f7160e129 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Wed, 30 Aug 2017 08:01:27 -0500 Subject: [PATCH 002/102] Adds db connectivity check to jobban cache building --- code/modules/admin/banjob.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index 0128b719d7..a260746e66 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -22,6 +22,8 @@ return 0 /proc/jobban_buildcache(client/C) + if(!SSdbcore.Connect()) + return if(C && istype(C)) C.jobbancache = list() var/datum/DBQuery/query_jobban_build_cache = SSdbcore.NewQuery("SELECT job, reason FROM [format_table_name("ban")] WHERE ckey = '[sanitizeSQL(C.ckey)]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") From 50b88388da6413d1764dd4958b4aa6c757b69c22 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Wed, 30 Aug 2017 17:03:20 -0500 Subject: [PATCH 003/102] Crew monitoring rework part 1: crew pinpointers --- _maps/map_files/BoxStation/BoxStation.dmm | 2 +- .../map_files/Deltastation/DeltaStation2.dmm | 2 +- _maps/map_files/MetaStation/MetaStation.dmm | 2 +- _maps/map_files/OmegaStation/OmegaStation.dmm | 2 +- _maps/map_files/PubbyStation/PubbyStation.dmm | 2 +- code/__DEFINES/pinpointers.dm | 3 - .../gamemodes/malfunction/Malf_Modules.dm.rej | 11 ++ code/game/gamemodes/nuclear/nuclear.dm.rej | 10 ++ .../game/gamemodes/nuclear/nuclearbomb.dm.rej | 33 ++++ code/game/gamemodes/nuclear/pinpointer.dm | 6 - code/game/gamemodes/nuclear/pinpointer.dm.rej | 21 +++ code/game/gamemodes/objective_items.dm.rej | 10 ++ code/game/machinery/vending.dm | 2 +- code/game/objects/items/devices/pinpointer.dm | 152 ++++++++++++++++++ code/game/objects/items/pinpointer.dm | 150 +++++++++++++++++ .../crates_lockers/closets/secure/security.dm | 4 +- code/modules/admin/verbs/onlyone.dm | 4 +- code/modules/jobs/job_types/medical.dm | 1 + .../mob/living/silicon/ai/death.dm.rej | 13 ++ .../living/silicon/robot/robot_modules.dm.rej | 19 +++ code/modules/power/apc.dm.rej | 13 ++ icons/obj/device.dmi | Bin 38526 -> 37754 bytes tgstation.dme | 1 + tgstation.dme.rej | 20 +-- 24 files changed, 453 insertions(+), 30 deletions(-) create mode 100644 code/game/gamemodes/malfunction/Malf_Modules.dm.rej create mode 100644 code/game/gamemodes/nuclear/nuclear.dm.rej create mode 100644 code/game/gamemodes/nuclear/nuclearbomb.dm.rej create mode 100644 code/game/gamemodes/nuclear/pinpointer.dm.rej create mode 100644 code/game/gamemodes/objective_items.dm.rej create mode 100644 code/game/objects/items/devices/pinpointer.dm create mode 100644 code/game/objects/items/pinpointer.dm create mode 100644 code/modules/mob/living/silicon/ai/death.dm.rej create mode 100644 code/modules/mob/living/silicon/robot/robot_modules.dm.rej create mode 100644 code/modules/power/apc.dm.rej diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 95f1cb283c..27f366f7f8 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -24458,7 +24458,7 @@ /area/crew_quarters/heads/captain) "bfE" = ( /obj/structure/table/wood, -/obj/item/pinpointer, +/obj/item/pinpointer/nuke, /obj/item/disk/nuclear, /obj/item/storage/secure/safe{ pixel_x = 35; diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 5e0ded4416..0484d95b79 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -53210,7 +53210,7 @@ /area/tcommsat/server) "bYo" = ( /obj/structure/table/wood, -/obj/item/pinpointer, +/obj/item/pinpointer/nuke, /obj/item/disk/nuclear, /obj/item/device/radio/intercom{ name = "Station Intercom"; diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index ec76a564d5..a60e43dd83 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -29108,7 +29108,7 @@ }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/table/wood, -/obj/item/pinpointer, +/obj/item/pinpointer/nuke, /obj/item/disk/nuclear, /turf/open/floor/carpet, /area/crew_quarters/heads/captain/private) diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 9a3b2b9454..6b4f65c67e 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -1187,7 +1187,7 @@ pixel_x = 32; pixel_y = 24 }, -/obj/item/pinpointer, +/obj/item/pinpointer/nuke, /obj/item/disk/nuclear, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 10 diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 7f55c286c7..497bf0a4ce 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -13937,7 +13937,7 @@ /area/storage/primary) "aEx" = ( /obj/structure/table/wood, -/obj/item/pinpointer, +/obj/item/pinpointer/nuke, /obj/item/disk/nuclear, /obj/machinery/light{ dir = 8 diff --git a/code/__DEFINES/pinpointers.dm b/code/__DEFINES/pinpointers.dm index 80403e54de..75f0452ea9 100644 --- a/code/__DEFINES/pinpointers.dm +++ b/code/__DEFINES/pinpointers.dm @@ -2,6 +2,3 @@ #define TRACK_NUKE_DISK 1 //We track the nuclear authentication disk, either to protect it or steal it #define TRACK_MALF_AI 2 //We track the malfunctioning AI, so we can prevent it from blowing us all up #define TRACK_INFILTRATOR 3 //We track the Syndicate infiltrator, so we can get back to ship when the nuke's armed -#define TRACK_OPERATIVES 4 //We track the closest operative, so we can regroup when we need to -#define TRACK_ATOM 5 //We track a specified atom, so admins can make us function for events -#define TRACK_COORDINATES 6 //We point towards the specified coordinates on our z-level, so we can navigate diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm.rej b/code/game/gamemodes/malfunction/Malf_Modules.dm.rej new file mode 100644 index 0000000000..97dbe2bbdb --- /dev/null +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm.rej @@ -0,0 +1,11 @@ +diff a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm (rejected hunks) +@@ -309,8 +309,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( + owner_AI.nuking = TRUE + owner_AI.doomsday_device = DOOM + owner_AI.doomsday_device.start() +- for(var/pinpointer in GLOB.pinpointer_list) +- var/obj/item/weapon/pinpointer/P = pinpointer ++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list) + P.switch_mode_to(TRACK_MALF_AI) //Pinpointers start tracking the AI wherever it goes + qdel(src) + diff --git a/code/game/gamemodes/nuclear/nuclear.dm.rej b/code/game/gamemodes/nuclear/nuclear.dm.rej new file mode 100644 index 0000000000..19648547c7 --- /dev/null +++ b/code/game/gamemodes/nuclear/nuclear.dm.rej @@ -0,0 +1,10 @@ +diff a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm (rejected hunks) +@@ -325,7 +325,7 @@ + gloves = /obj/item/clothing/gloves/combat + back = /obj/item/weapon/storage/backpack + ears = /obj/item/device/radio/headset/syndicate/alt +- l_pocket = /obj/item/weapon/pinpointer/syndicate ++ l_pocket = /obj/item/weapon/pinpointer/nuke/syndicate + id = /obj/item/weapon/card/id/syndicate + belt = /obj/item/weapon/gun/ballistic/automatic/pistol + backpack_contents = list(/obj/item/weapon/storage/box/syndie=1) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm.rej b/code/game/gamemodes/nuclear/nuclearbomb.dm.rej new file mode 100644 index 0000000000..6a35e91cde --- /dev/null +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm.rej @@ -0,0 +1,33 @@ +diff a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm (rejected hunks) +@@ -362,9 +362,9 @@ + if(safety) + if(timing) + set_security_level(previous_level) +- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list) ++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) + S.switch_mode_to(initial(S.mode)) +- S.nuke_warning = FALSE ++ S.alert = FALSE + timing = FALSE + bomb_set = TRUE + detonation_timer = null +@@ -381,16 +381,16 @@ + bomb_set = TRUE + set_security_level("delta") + detonation_timer = world.time + (timer_set * 10) +- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list) ++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) + S.switch_mode_to(TRACK_INFILTRATOR) + countdown.start() + else + bomb_set = FALSE + detonation_timer = null + set_security_level(previous_level) +- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list) ++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) + S.switch_mode_to(initial(S.mode)) +- S.nuke_warning = FALSE ++ S.alert = FALSE + countdown.stop() + update_icon() + diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm index 9f63309643..342bcac090 100644 --- a/code/game/gamemodes/nuclear/pinpointer.dm +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -60,12 +60,6 @@ msg += "\"01000001 01001001\"." if(TRACK_INFILTRATOR) msg += "\"vasvygengbefuvc\"." - if(TRACK_OPERATIVES) - msg += "\"[target ? "Operative [target]" : "friends"]\"." - if(TRACK_ATOM) - msg += "\"[initial(constant_target.name)]\"." - if(TRACK_COORDINATES) - msg += "\"([target_x], [target_y])\"." else msg = "Its tracking indicator is blank." to_chat(user, msg) diff --git a/code/game/gamemodes/nuclear/pinpointer.dm.rej b/code/game/gamemodes/nuclear/pinpointer.dm.rej new file mode 100644 index 0000000000..79d652af9b --- /dev/null +++ b/code/game/gamemodes/nuclear/pinpointer.dm.rej @@ -0,0 +1,21 @@ +diff a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm (rejected hunks) +@@ -30,7 +30,6 @@ + var/mob/living/L = loc + to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.") + +- + /obj/item/pinpointer/nuke/scan_for_target() + target = null + switch(mode) +@@ -58,10 +57,10 @@ + mode = new_mode + scan_for_target() + +- + /obj/item/pinpointer/nuke/syndicate // Syndicate pinpointers automatically point towards the infiltrator once the nuke is active. + name = "syndicate pinpointer" + desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device." ++ icon_state = "pinpointer_syndicate" + + /obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative. + name = "cyborg syndicate pinpointer" diff --git a/code/game/gamemodes/objective_items.dm.rej b/code/game/gamemodes/objective_items.dm.rej new file mode 100644 index 0000000000..3770d7eea9 --- /dev/null +++ b/code/game/gamemodes/objective_items.dm.rej @@ -0,0 +1,10 @@ +diff a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm (rejected hunks) +@@ -158,7 +158,7 @@ + difficulty = 10 + + //Old ninja objectives. +-/datum/objective_item/special/pinpointer ++/datum/objective_item/special/pinpointer/nuke + name = "the captain's pinpointer." + targetitem = /obj/item/pinpointer + difficulty = 10 diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 427bc95253..bf879f84da 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -869,7 +869,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C products = list(/obj/item/reagent_containers/syringe = 12, /obj/item/reagent_containers/dropper = 3, /obj/item/stack/medical/gauze = 8, /obj/item/reagent_containers/pill/patch/styptic = 5, /obj/item/reagent_containers/pill/insulin = 10, /obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/glass/bottle/charcoal = 4, /obj/item/reagent_containers/spray/medical/sterilizer = 1, /obj/item/reagent_containers/glass/bottle/epinephrine = 4, /obj/item/reagent_containers/glass/bottle/morphine = 4, /obj/item/reagent_containers/glass/bottle/salglu_solution = 3, - /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2) + /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2, /obj/item/pinpointer/crew = 2) contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6) premium = list(/obj/item/storage/box/hug/medical = 1, /obj/item/reagent_containers/hypospray/medipen = 3, /obj/item/storage/belt/medical = 3, /obj/item/wrench/medical = 1) armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) diff --git a/code/game/objects/items/devices/pinpointer.dm b/code/game/objects/items/devices/pinpointer.dm new file mode 100644 index 0000000000..1d11f312a4 --- /dev/null +++ b/code/game/objects/items/devices/pinpointer.dm @@ -0,0 +1,152 @@ +//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk. +/obj/item/weapon/pinpointer + name = "pinpointer" + desc = "A handheld tracking device that locks onto certain signals." + icon = 'icons/obj/device.dmi' + icon_state = "pinpointer" + flags = CONDUCT + slot_flags = SLOT_BELT + w_class = WEIGHT_CLASS_SMALL + item_state = "electronic" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + throw_speed = 3 + throw_range = 7 + materials = list(MAT_METAL = 500, MAT_GLASS = 250) + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/active = FALSE + var/atom/movable/target = null //The thing we're searching for + var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination + var/alert = FALSE // TRUE to display things more seriously + +/obj/item/weapon/pinpointer/New() + ..() + GLOB.pinpointer_list += src + +/obj/item/weapon/pinpointer/Destroy() + STOP_PROCESSING(SSfastprocess, src) + GLOB.pinpointer_list -= src + return ..() + +/obj/item/weapon/pinpointer/attack_self(mob/living/user) + active = !active + user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.") + playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) + if(active) + START_PROCESSING(SSfastprocess, src) + else + target = null + STOP_PROCESSING(SSfastprocess, src) + update_pointer_overlay() + +/obj/item/weapon/pinpointer/process() + if(!active) + STOP_PROCESSING(SSfastprocess, src) + return + scan_for_target() + update_pointer_overlay() + +/obj/item/weapon/pinpointer/proc/scan_for_target() + return + +/obj/item/weapon/pinpointer/proc/update_pointer_overlay() + cut_overlays() + if(!active) + return + if(!target) + add_overlay("pinon[alert ? "alert" : ""]null") + var/turf/here = get_turf(src) + var/turf/there = get_turf(target) + if(here.z != there.z) + add_overlay("pinon[alert ? "alert" : ""]null") + return + if(get_dist_euclidian(here,there) <= minimum_range) + add_overlay("pinon[alert ? "alert" : ""]direct") + else + setDir(get_dir(here, there)) + switch(get_dist(here, there)) + if(1 to 8) + add_overlay("pinon[alert ? "alert" : "close"]") + if(9 to 16) + add_overlay("pinon[alert ? "alert" : "medium"]") + if(16 to INFINITY) + add_overlay("pinon[alert ? "alert" : "far"]") + +/obj/item/weapon/pinpointer/crew // A replacement for the old crew monitoring consoles + name = "crew pinpointer" + desc = "A handheld tracking device that points to crew suit sensors." + icon_state = "pinpointer_crew" + +/obj/item/weapon/pinpointer/crew/proc/trackable(mob/living/carbon/human/H) + var/turf/here = get_turf(src) + if((H.z == 0 || H.z == here.z) && istype(H.w_uniform, /obj/item/clothing/under)) + var/obj/item/clothing/under/U = H.w_uniform + + // Suit sensors must be on maximum. + if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS) + return FALSE + + var/turf/there = get_turf(H) + return (H.z != 0 || (there && there.z == H.z)) + + return FALSE + +/obj/item/weapon/pinpointer/crew/attack_self(mob/living/user) + if(active) + active = FALSE + user.visible_message("[user] deactivates their pinpointer.", "You deactivate your pinpointer.") + playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) + target = null //Restarting the pinpointer forces a target reset + STOP_PROCESSING(SSfastprocess, src) + update_pointer_overlay() + return + + var/list/name_counts = list() + var/list/names = list() + + for(var/mob/living/carbon/human/H in GLOB.mob_list) + if(!trackable(H)) + continue + + var/name = "Unknown" + if(H.wear_id) + var/obj/item/weapon/card/id/I = H.wear_id.GetID() + name = I.registered_name + + while(name in name_counts) + name_counts[name]++ + name = text("[] ([])", name, name_counts[name]) + names[name] = H + name_counts[name] = 1 + + if(!names.len) + user.visible_message("[user]'s pinpointer fails to detect a signal.", "Your pinpointer fails to detect a signal.") + return + + var/A = input(user, "Person to track", "Pinpoint") in names + if(!src || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !A) + return + + target = names[A] + active = TRUE + user.visible_message("[user] activates their pinpointer.", "You activate your pinpointer.") + playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) + START_PROCESSING(SSfastprocess, src) + update_pointer_overlay() + +/obj/item/weapon/pinpointer/crew/scan_for_target() + if(target) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(!trackable(H)) + target = null + if(!target) + active = FALSE + +/obj/item/weapon/pinpointer/process() + if(!active) + STOP_PROCESSING(SSfastprocess, src) + return + scan_for_target() + update_pointer_overlay() + diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm new file mode 100644 index 0000000000..28488a231f --- /dev/null +++ b/code/game/objects/items/pinpointer.dm @@ -0,0 +1,150 @@ +//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk. +/obj/item/pinpointer + name = "pinpointer" + desc = "A handheld tracking device that locks onto certain signals." + icon = 'icons/obj/device.dmi' + icon_state = "pinpointer" + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + w_class = WEIGHT_CLASS_SMALL + item_state = "electronic" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + throw_speed = 3 + throw_range = 7 + materials = list(MAT_METAL = 500, MAT_GLASS = 250) + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/active = FALSE + var/atom/movable/target //The thing we're searching for + var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination + var/alert = FALSE // TRUE to display things more seriously + +/obj/item/pinpointer/Initialize() + . = ..() + GLOB.pinpointer_list += src + +/obj/item/pinpointer/Destroy() + STOP_PROCESSING(SSfastprocess, src) + GLOB.pinpointer_list -= src + return ..() + +/obj/item/pinpointer/attack_self(mob/living/user) + active = !active + user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.") + playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) + if(active) + START_PROCESSING(SSfastprocess, src) + else + target = null + STOP_PROCESSING(SSfastprocess, src) + update_icon() + +/obj/item/pinpointer/process() + if(!active) + return PROCESS_KILL + scan_for_target() + update_icon() + +/obj/item/pinpointer/proc/scan_for_target() + return + +/obj/item/pinpointer/update_icon() + cut_overlays() + if(!active) + return + if(!target) + add_overlay("pinon[alert ? "alert" : ""]null") + var/turf/here = get_turf(src) + var/turf/there = get_turf(target) + if(here.z != there.z) + add_overlay("pinon[alert ? "alert" : ""]null") + return + if(get_dist_euclidian(here,there) <= minimum_range) + add_overlay("pinon[alert ? "alert" : ""]direct") + else + setDir(get_dir(here, there)) + switch(get_dist(here, there)) + if(1 to 8) + add_overlay("pinon[alert ? "alert" : "close"]") + if(9 to 16) + add_overlay("pinon[alert ? "alert" : "medium"]") + if(16 to INFINITY) + add_overlay("pinon[alert ? "alert" : "far"]") + +/obj/item/pinpointer/crew // A replacement for the old crew monitoring consoles + name = "crew pinpointer" + desc = "A handheld tracking device that points to crew suit sensors." + icon_state = "pinpointer_crew" + +/obj/item/pinpointer/crew/proc/trackable(mob/living/carbon/human/H) + var/turf/here = get_turf(src) + if((H.z == 0 || H.z == here.z) && istype(H.w_uniform, /obj/item/clothing/under)) + var/obj/item/clothing/under/U = H.w_uniform + + // Suit sensors must be on maximum. + if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS) + return FALSE + + var/turf/there = get_turf(H) + return (H.z != 0 || (there && there.z == H.z)) + + return FALSE + +/obj/item/pinpointer/crew/attack_self(mob/living/user) + if(active) + active = FALSE + user.visible_message("[user] deactivates their pinpointer.", "You deactivate your pinpointer.") + playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) + target = null //Restarting the pinpointer forces a target reset + STOP_PROCESSING(SSfastprocess, src) + update_icon() + return + + var/list/name_counts = list() + var/list/names = list() + + for(var/mob/living/carbon/human/H in GLOB.mob_list) + if(!trackable(H)) + continue + + var/crewmember_name = "Unknown" + if(H.wear_id) + var/obj/item/card/id/I = H.wear_id.GetID() + crewmember_name = I.registered_name + + while(crewmember_name in name_counts) + name_counts[crewmember_name]++ + crewmember_name = text("[] ([])", crewmember_name, name_counts[crewmember_name]) + names[crewmember_name] = H + name_counts[crewmember_name] = 1 + + if(!names.len) + user.visible_message("[user]'s pinpointer fails to detect a signal.", "Your pinpointer fails to detect a signal.") + return + + var/A = input(user, "Person to track", "Pinpoint") in names + if(!A || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated()) + return + + target = names[A] + active = TRUE + user.visible_message("[user] activates their pinpointer.", "You activate your pinpointer.") + playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) + START_PROCESSING(SSfastprocess, src) + update_icon() + +/obj/item/pinpointer/crew/scan_for_target() + if(target) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(!trackable(H)) + target = null + if(!target) //target can be set to null from above code, or elsewhere + active = FALSE + +/obj/item/pinpointer/process() + if(!active) + return PROCESS_KILL + scan_for_target() + update_icon() + diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 6327d2d3ff..f13eaf73c4 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -83,7 +83,7 @@ new /obj/item/storage/belt/security/full(src) new /obj/item/gun/energy/e_gun/hos(src) new /obj/item/device/flashlight/seclite(src) - new /obj/item/pinpointer(src) + new /obj/item/pinpointer/nuke(src) /obj/structure/closet/secure_closet/warden name = "\proper warden's locker" @@ -108,6 +108,7 @@ new /obj/item/clothing/gloves/krav_maga/sec(src) new /obj/item/door_remote/head_of_security(src) new /obj/item/gun/ballistic/shotgun/automatic/combat/compact(src) + new /obj/item/pinpointer/crew(src) /obj/structure/closet/secure_closet/security name = "security officer's locker" @@ -183,6 +184,7 @@ new /obj/item/reagent_containers/spray/pepper(src) new /obj/item/clothing/suit/armor/vest/det_suit(src) new /obj/item/storage/belt/holster/full(src) + new /obj/item/pinpointer/crew(src) /obj/structure/closet/secure_closet/injection name = "lethal injections" diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm index 7301724eb6..abb87a4235 100644 --- a/code/modules/admin/verbs/onlyone.dm +++ b/code/modules/admin/verbs/onlyone.dm @@ -50,8 +50,8 @@ GLOBAL_VAR_INIT(highlander, FALSE) equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(src), slot_ears) equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(src), slot_head) equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(src), slot_shoes) - equip_to_slot_or_del(new /obj/item/pinpointer(src), slot_l_store) - for(var/obj/item/pinpointer/P in src) + equip_to_slot_or_del(new /obj/item/pinpointer/nuke(src), slot_l_store) + for(var/obj/item/pinpointer/nuke/P in src) P.attack_self(src) var/obj/item/card/id/W = new(src) W.icon_state = "centcom" diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm index 5f22e1886a..3d9f857dbf 100644 --- a/code/modules/jobs/job_types/medical.dm +++ b/code/modules/jobs/job_types/medical.dm @@ -30,6 +30,7 @@ Chief Medical Officer id = /obj/item/card/id/silver belt = /obj/item/device/pda/heads/cmo + l_pocket = /obj/item/pinpointer/crew ears = /obj/item/device/radio/headset/heads/cmo uniform = /obj/item/clothing/under/rank/chief_medical_officer shoes = /obj/item/clothing/shoes/sneakers/brown diff --git a/code/modules/mob/living/silicon/ai/death.dm.rej b/code/modules/mob/living/silicon/ai/death.dm.rej new file mode 100644 index 0000000000..40b5625e8c --- /dev/null +++ b/code/modules/mob/living/silicon/ai/death.dm.rej @@ -0,0 +1,13 @@ +diff a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm (rejected hunks) +@@ -35,9 +35,9 @@ + if(nuking) + set_security_level("red") + nuking = FALSE +- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list) ++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list) + P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone +- P.nuke_warning = FALSE ++ P.alert = FALSE + + if(doomsday_device) + doomsday_device.timing = FALSE diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm.rej b/code/modules/mob/living/silicon/robot/robot_modules.dm.rej new file mode 100644 index 0000000000..b0f0812dc4 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm.rej @@ -0,0 +1,19 @@ +diff a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm (rejected hunks) +@@ -519,7 +519,7 @@ + /obj/item/weapon/gun/ballistic/revolver/grenadelauncher/cyborg, + /obj/item/weapon/card/emag, + /obj/item/weapon/crowbar/cyborg, +- /obj/item/weapon/pinpointer/syndicate/cyborg) ++ /obj/item/weapon/pinpointer/syndicate_cyborg) + + ratvar_modules = list( + /obj/item/clockwork/slab/cyborg/security, +@@ -545,7 +545,7 @@ + /obj/item/roller/robo, + /obj/item/weapon/card/emag, + /obj/item/weapon/crowbar/cyborg, +- /obj/item/weapon/pinpointer/syndicate/cyborg, ++ /obj/item/weapon/pinpointer/syndicate_cyborg, + /obj/item/stack/medical/gauze/cyborg, + /obj/item/weapon/gun/medbeam) + ratvar_modules = list( diff --git a/code/modules/power/apc.dm.rej b/code/modules/power/apc.dm.rej new file mode 100644 index 0000000000..9e432f503c --- /dev/null +++ b/code/modules/power/apc.dm.rej @@ -0,0 +1,13 @@ +diff a/code/modules/power/apc.dm b/code/modules/power/apc.dm (rejected hunks) +@@ -867,9 +867,9 @@ + occupier.loc = src.loc + occupier.death() + occupier.gib() +- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list) ++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list) + P.switch_mode_to(TRACK_NUKE_DISK) //Pinpointers go back to tracking the nuke disk +- P.nuke_warning = FALSE ++ P.alert = FALSE + + /obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card) + if(card.AI) diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 808de6944665734cb96d96dbd42c08aeefa1452e..79f0a207d41d802e2e87d718157c7a5ca1983ffd 100644 GIT binary patch literal 37754 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 aH-6%}!&bucoQ)y~JeO=8ZK`qJNq+-{0&jQ# literal 38526 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 diff --git a/tgstation.dme b/tgstation.dme index 1e1c153493..4c2da1f48b 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -793,6 +793,7 @@ #include "code\game\objects\items\mop.dm" #include "code\game\objects\items\paint.dm" #include "code\game\objects\items\paiwire.dm" +#include "code\game\objects\items\pinpointer.dm" #include "code\game\objects\items\pneumaticCannon.dm" #include "code\game\objects\items\powerfist.dm" #include "code\game\objects\items\RCD.dm" diff --git a/tgstation.dme.rej b/tgstation.dme.rej index a5ff4dc3cb..82c613607a 100644 --- a/tgstation.dme.rej +++ b/tgstation.dme.rej @@ -1,13 +1,9 @@ diff a/tgstation.dme b/tgstation.dme (rejected hunks) -@@ -1746,6 +1745,11 @@ - #include "code\modules\mob\living\simple_animal\hostile\gorilla\emotes.dm" - #include "code\modules\mob\living\simple_animal\hostile\gorilla\gorilla.dm" - #include "code\modules\mob\living\simple_animal\hostile\gorilla\visuals_icons.dm" -+#include "code\modules\mob\living\simple_animal\hostile\jungle\_jungle_mobs.dm" -+#include "code\modules\mob\living\simple_animal\hostile\jungle\leaper.dm" -+#include "code\modules\mob\living\simple_animal\hostile\jungle\mega_arachnid.dm" -+#include "code\modules\mob\living\simple_animal\hostile\jungle\mook.dm" -+#include "code\modules\mob\living\simple_animal\hostile\jungle\seedling.dm" - #include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm" - #include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm" - #include "code\modules\mob\living\simple_animal\hostile\megafauna\colossus.dm" +@@ -793,7 +794,6 @@ + #include "code\game\objects\items\devices\megaphone.dm" + #include "code\game\objects\items\devices\multitool.dm" + #include "code\game\objects\items\devices\paicard.dm" +-#include "code\game\objects\items\devices\pinpointer.dm" + #include "code\game\objects\items\devices\pipe_painter.dm" + #include "code\game\objects\items\devices\powersink.dm" + #include "code\game\objects\items\devices\pressureplates.dm" From 64b94e93934f2a972dc331b58c4c911f54fa678a Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 4 Sep 2017 11:07:47 -0500 Subject: [PATCH 004/102] disables the lisp that lizard tongues have --- code/modules/surgery/organs/tongue.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index b69c1f4c5c..0113166d86 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -47,6 +47,7 @@ say_mod = "hisses" taste_sensitivity = 10 // combined nose + tongue, extra sensitive +/* /obj/item/organ/tongue/lizard/TongueSpeech(var/message) var/regex/lizard_hiss = new("s+", "g") var/regex/lizard_hiSS = new("S+", "g") @@ -54,6 +55,7 @@ message = lizard_hiss.Replace(message, "sss") message = lizard_hiSS.Replace(message, "SSS") return message + */ /obj/item/organ/tongue/fly name = "proboscis" From d73b82cf1140157d5280108c542b2a13fdfb7b83 Mon Sep 17 00:00:00 2001 From: tortellinitony <22010639+tortellinitony@users.noreply.github.com> Date: Thu, 7 Sep 2017 00:38:24 -0400 Subject: [PATCH 005/102] Gets rid of manual overlay manipulation --- .../clock_structures/prolonging_prism.dm | 2 +- code/game/objects/items/devices/flashlight.dm | 2 +- .../objects/items/devices/pressureplates.dm | 2 +- code/game/objects/items/tools.dm | 793 ++++++++++++++++++ code/game/turfs/turf.dm | 4 +- code/modules/hydroponics/hydroponics.dm | 2 +- 6 files changed, 799 insertions(+), 6 deletions(-) diff --git a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm index cf730189e3..a6bc9a7f38 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm @@ -126,7 +126,7 @@ if(!hex_combo) hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER) else - hex_combo.overlays += mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER) + hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)) if(hex_combo) //YOU BUILT A HEXAGON hex_combo.pixel_x = -16 hex_combo.pixel_y = -16 diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index b41438451c..9c19f37f3f 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -428,7 +428,7 @@ /obj/item/device/flashlight/glowstick/update_icon() item_state = "glowstick" - overlays.Cut() + cut_overlays() if(!fuel) icon_state = "glowstick-empty" cut_overlays() diff --git a/code/game/objects/items/devices/pressureplates.dm b/code/game/objects/items/devices/pressureplates.dm index bab40edb29..b8b4884db7 100644 --- a/code/game/objects/items/devices/pressureplates.dm +++ b/code/game/objects/items/devices/pressureplates.dm @@ -86,7 +86,7 @@ icon_state = null active = TRUE if(tile_overlay) - loc.overlays += tile_overlay + loc.add_overlay(tile_overlay) else if(crossed) trigger() //no cheesing. diff --git a/code/game/objects/items/tools.dm b/code/game/objects/items/tools.dm index 23f68ca93c..0e557497c0 100644 --- a/code/game/objects/items/tools.dm +++ b/code/game/objects/items/tools.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD #define WELDER_FUEL_BURN_INTERVAL 13 /* Tools! @@ -788,3 +789,795 @@ user.put_in_active_hand(cutjaws) #undef WELDER_FUEL_BURN_INTERVAL +======= +#define WELDER_FUEL_BURN_INTERVAL 13 + +/* Tools! + * Note: Multitools are /obj/item/device + * + * Contains: + * Wrench + * Screwdriver + * Wirecutters + * Welding Tool + * Crowbar + */ + +/* + * Wrench + */ +/obj/item/wrench + name = "wrench" + desc = "A wrench with common uses. Can be found in your hand." + icon = 'icons/obj/tools.dmi' + icon_state = "wrench" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + usesound = 'sound/items/ratchet.ogg' + materials = list(MAT_METAL=150) + origin_tech = "materials=1;engineering=1" + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/wrench/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wrench/cyborg + name = "automatic wrench" + desc = "An advanced robotic wrench. Can be found in construction cyborgs." + toolspeed = 0.5 + +/obj/item/wrench/brass + name = "brass wrench" + desc = "A brass wrench. It's faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "wrench_brass" + toolspeed = 0.5 + +/obj/item/wrench/abductor + name = "alien wrench" + desc = "A polarized wrench. It causes anything placed between the jaws to turn." + icon = 'icons/obj/abductor.dmi' + icon_state = "wrench" + usesound = 'sound/effects/empulse.ogg' + toolspeed = 0.1 + origin_tech = "materials=5;engineering=5;abductor=3" + +/obj/item/wrench/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a bolt bit." + icon_state = "drill_bolt" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/drill_use.ogg' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + attack_verb = list("drilled", "screwed", "jabbed") + toolspeed = 0.25 + +/obj/item/wrench/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power + to_chat(user, "You attach the screw driver bit to [src].") + qdel(src) + user.put_in_active_hand(s_drill) + +/obj/item/wrench/power/suicide_act(mob/user) + user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/wrench/medical + name = "medical wrench" + desc = "A medical wrench with common(medical?) uses. Can be found in your hand." + icon_state = "wrench_medical" + force = 2 //MEDICAL + throwforce = 4 + origin_tech = "materials=1;engineering=1;biotech=3" + attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") + +/obj/item/wrench/medical/suicide_act(mob/living/user) + user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") + // TODO Make them glow with the power of the M E D I C A L W R E N C H + // during their ascension + + // Stun stops them from wandering off + user.Stun(100, ignore_canstun = TRUE) + playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) + + // Let the sound effect finish playing + sleep(20) + + if(!user) + return + + for(var/obj/item/W in user) + user.dropItemToGround(W) + + var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) + W.add_fingerprint(user) + W.desc += " For some reason, it reminds you of [user.name]." + + if(!user) + return + + user.dust() + + return OXYLOSS + +/* + * Screwdriver + */ +/obj/item/screwdriver + name = "screwdriver" + desc = "You can be totally screwy with this." + icon = 'icons/obj/tools.dmi' + icon_state = "screwdriver" + item_state = "screwdriver" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + w_class = WEIGHT_CLASS_TINY + throwforce = 5 + throw_speed = 3 + throw_range = 5 + materials = list(MAT_METAL=75) + attack_verb = list("stabbed") + hitsound = 'sound/weapons/bladeslice.ogg' + usesound = 'sound/items/screwdriver.ogg' + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + var/random_color = TRUE //if the screwdriver uses random coloring + var/static/list/screwdriver_colors = list(\ + "blue" = rgb(24, 97, 213), \ + "red" = rgb(149, 23, 16), \ + "pink" = rgb(213, 24, 141), \ + "brown" = rgb(160, 82, 18), \ + "green" = rgb(14, 127, 27), \ + "cyan" = rgb(24, 162, 213), \ + "yellow" = rgb(213, 140, 24), \ + ) + +/obj/item/screwdriver/suicide_act(mob/user) + user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/Initialize() + . = ..() + if(random_color) //random colors! + var/our_color = pick(screwdriver_colors) + add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) + update_icon() + if(prob(75)) + pixel_y = rand(0, 16) + +/obj/item/screwdriver/update_icon() + if(!random_color) //icon override + return + cut_overlays() + var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") + base_overlay.appearance_flags = RESET_COLOR + add_overlay(base_overlay) + +/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) + . = list() + if(isinhands && random_color) + var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") + M.appearance_flags = RESET_COLOR + . += M + +/obj/item/screwdriver/get_belt_overlay() + if(random_color) + var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") + var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") + body.color = color + head.add_overlay(body) + return head + else + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) + +/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) + if(!istype(M)) + return ..() + if(user.zone_selected != "eyes" && user.zone_selected != "head") + return ..() + if(user.disabilities & CLUMSY && prob(50)) + M = user + return eyestab(M,user) + +/obj/item/screwdriver/brass + name = "brass screwdriver" + desc = "A screwdriver made of brass. The handle feels freezing cold." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "screwdriver_brass" + item_state = "screwdriver_brass" + toolspeed = 0.5 + random_color = FALSE + +/obj/item/screwdriver/abductor + name = "alien screwdriver" + desc = "An ultrasonic screwdriver." + icon = 'icons/obj/abductor.dmi' + icon_state = "screwdriver_a" + item_state = "screwdriver_nuke" + usesound = 'sound/items/pshoom.ogg' + toolspeed = 0.1 + random_color = FALSE + +/obj/item/screwdriver/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a screw bit." + icon_state = "drill_screw" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + throw_speed = 2 + throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far + attack_verb = list("drilled", "screwed", "jabbed","whacked") + hitsound = 'sound/items/drill_hit.ogg' + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.25 + random_color = FALSE + +/obj/item/screwdriver/power/suicide_act(mob/user) + user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power + to_chat(user, "You attach the bolt driver bit to [src].") + qdel(src) + user.put_in_active_hand(b_drill) + +/obj/item/screwdriver/cyborg + name = "powered screwdriver" + desc = "An electrical screwdriver, designed to be both precise and quick." + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.5 + +/* + * Wirecutters + */ +/obj/item/wirecutters + name = "wirecutters" + desc = "This cuts wires." + icon = 'icons/obj/tools.dmi' + icon_state = null + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 6 + throw_speed = 3 + throw_range = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=80) + attack_verb = list("pinched", "nipped") + hitsound = 'sound/items/wirecutter.ogg' + usesound = 'sound/items/wirecutter.ogg' + origin_tech = "materials=1;engineering=1" + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + + +/obj/item/wirecutters/New(loc, var/param_color = null) + ..() + if(!icon_state) + if(!param_color) + param_color = pick("yellow","red") + icon_state = "cutters_[param_color]" + +/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) + if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) + user.visible_message("[user] cuts [C]'s restraints with [src]!") + qdel(C.handcuffed) + C.handcuffed = null + if(C.buckled && C.buckled.buckle_requires_restraints) + C.buckled.unbuckle_mob(C) + C.update_handcuffed() + return + else + ..() + +/obj/item/wirecutters/suicide_act(mob/user) + user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, usesound, 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/brass + name = "brass wirecutters" + desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "cutters_brass" + toolspeed = 0.5 + +/obj/item/wirecutters/abductor + name = "alien wirecutters" + desc = "Extremely sharp wirecutters, made out of a silvery-green metal." + icon = 'icons/obj/abductor.dmi' + icon_state = "cutters" + toolspeed = 0.1 + origin_tech = "materials=5;engineering=4;abductor=3" + +/obj/item/wirecutters/cyborg + name = "wirecutters" + desc = "This cuts wires." + toolspeed = 0.5 + +/obj/item/wirecutters/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." + icon_state = "jaws_cutter" + item_state = "jawsoflife" + origin_tech = "materials=2;engineering=2" + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + usesound = 'sound/items/jaws_cut.ogg' + toolspeed = 0.25 + +/obj/item/wirecutters/power/suicide_act(mob/user) + user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") + playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/obj/item/bodypart/BP = C.get_bodypart("head") + if(BP) + BP.drop_limb() + playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power + to_chat(user, "You attach the pry jaws to [src].") + qdel(src) + user.put_in_active_hand(pryjaws) +/* + * Welding Tool + */ +/obj/item/weldingtool + name = "welding tool" + desc = "A standard edition welder provided by Nanotrasen." + icon = 'icons/obj/tools.dmi' + icon_state = "welder" + item_state = "welder" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 3 + throwforce = 5 + hitsound = "swing_hit" + usesound = 'sound/items/welder.ogg' + var/acti_sound = 'sound/items/welderactivate.ogg' + var/deac_sound = 'sound/items/welderdeactivate.ogg' + throw_speed = 3 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) + resistance_flags = FIRE_PROOF + + materials = list(MAT_METAL=70, MAT_GLASS=30) + origin_tech = "engineering=1;plasmatech=1" + var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) + var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) + var/max_fuel = 20 //The max amount of fuel the welder can hold + var/change_icons = 1 + var/can_off_process = 0 + var/light_intensity = 2 //how powerful the emitted light is when used. + var/burned_fuel_for = 0 //when fuel was last removed + heat = 3800 + toolspeed = 1 + +/obj/item/weldingtool/Initialize() + . = ..() + create_reagents(max_fuel) + reagents.add_reagent("welding_fuel", max_fuel) + update_icon() + + +/obj/item/weldingtool/proc/update_torch() + if(welding) + add_overlay("[initial(icon_state)]-on") + item_state = "[initial(item_state)]1" + else + item_state = "[initial(item_state)]" + + +/obj/item/weldingtool/update_icon() + cut_overlays() + if(change_icons) + var/ratio = get_fuel() / max_fuel + ratio = Ceiling(ratio*4) * 25 + add_overlay("[initial(icon_state)][ratio]") + update_torch() + return + + +/obj/item/weldingtool/process() + switch(welding) + if(0) + force = 3 + damtype = "brute" + update_icon() + if(!can_off_process) + STOP_PROCESSING(SSobj, src) + return + //Welders left on now use up fuel, but lets not have them run out quite that fast + if(1) + force = 15 + damtype = "fire" + ++burned_fuel_for + if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) + remove_fuel(1) + update_icon() + + //This is to start fires. process() is only called if the welder is on. + open_flame() + + +/obj/item/weldingtool/suicide_act(mob/user) + user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") + return (FIRELOSS) + + +/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/screwdriver)) + flamethrower_screwdriver(I, user) + else if(istype(I, /obj/item/stack/rods)) + flamethrower_rods(I, user) + else + return ..() + + +/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return ..() + + var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) + + if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) + if(src.remove_fuel(1)) + playsound(loc, usesound, 50, 1) + if(user == H) + user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") + if(!do_mob(user, H, 50)) + return + item_heal_robotic(H, user, 15, 0) + else + return ..() + + +/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) + if(!proximity) return + + if(welding) + remove_fuel(1) + var/turf/location = get_turf(user) + location.hotspot_expose(700, 50, 1) + if(get_fuel() <= 0) + set_light(0) + + if(isliving(O)) + var/mob/living/L = O + if(L.IgniteMob()) + message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") + log_game("[key_name(user)] set [key_name(L)] on fire") + + +/obj/item/weldingtool/attack_self(mob/user) + switched_on(user) + if(welding) + set_light(light_intensity) + + update_icon() + + +//Returns the amount of fuel in the welder +/obj/item/weldingtool/proc/get_fuel() + return reagents.get_reagent_amount("welding_fuel") + + +//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() +/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) + if(!welding || !check_fuel()) + return 0 + if(amount) + burned_fuel_for = 0 + if(get_fuel() >= amount) + reagents.remove_reagent("welding_fuel", amount) + check_fuel() + if(M) + M.flash_act(light_intensity) + return TRUE + else + if(M) + to_chat(M, "You need more welding fuel to complete this task!") + return FALSE + + +//Turns off the welder if there is no more fuel (does this really need to be its own proc?) +/obj/item/weldingtool/proc/check_fuel(mob/user) + if(get_fuel() <= 0 && welding) + switched_on(user) + update_icon() + //mob icon update + if(ismob(loc)) + var/mob/M = loc + M.update_inv_hands(0) + + return 0 + return 1 + +//Switches the welder on +/obj/item/weldingtool/proc/switched_on(mob/user) + if(!status) + to_chat(user, "[src] can't be turned on while unsecured!") + return + welding = !welding + if(welding) + if(get_fuel() >= 1) + to_chat(user, "You switch [src] on.") + playsound(loc, acti_sound, 50, 1) + force = 15 + damtype = "fire" + hitsound = 'sound/items/welder.ogg' + update_icon() + START_PROCESSING(SSobj, src) + else + to_chat(user, "You need more fuel!") + switched_off(user) + else + to_chat(user, "You switch [src] off.") + playsound(loc, deac_sound, 50, 1) + switched_off(user) + +//Switches the welder off +/obj/item/weldingtool/proc/switched_off(mob/user) + welding = 0 + set_light(0) + + force = 3 + damtype = "brute" + hitsound = "swing_hit" + update_icon() + + +/obj/item/weldingtool/examine(mob/user) + ..() + to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") + +/obj/item/weldingtool/is_hot() + return welding * heat + +//Returns whether or not the welding tool is currently on. +/obj/item/weldingtool/proc/isOn() + return welding + + +/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) + if(welding) + to_chat(user, "Turn it off first!") + return + status = !status + if(status) + to_chat(user, "You resecure [src].") + else + to_chat(user, "[src] can now be attached and modified.") + add_fingerprint(user) + +/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) + if(!status) + var/obj/item/stack/rods/R = I + if (R.use(1)) + var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) + if(!remove_item_from_storage(F)) + user.transferItemToLoc(src, F, TRUE) + F.weldtool = src + add_fingerprint(user) + to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") + user.put_in_hands(F) + else + to_chat(user, "You need one rod to start building a flamethrower!") + +/obj/item/weldingtool/ignition_effect(atom/A, mob/user) + if(welding && remove_fuel(1, user)) + . = "[user] casually lights [A] with [src], what a badass." + else + . = "" + +/obj/item/weldingtool/largetank + name = "industrial welding tool" + desc = "A slightly larger welder with a larger tank." + icon_state = "indwelder" + max_fuel = 40 + materials = list(MAT_GLASS=60) + origin_tech = "engineering=2;plasmatech=2" + +/obj/item/weldingtool/largetank/cyborg + name = "integrated welding tool" + desc = "An advanced welder designed to be used in robotic systems." + toolspeed = 0.5 + +/obj/item/weldingtool/largetank/flamethrower_screwdriver() + return + + +/obj/item/weldingtool/mini + name = "emergency welding tool" + desc = "A miniature welder used during emergencies." + icon_state = "miniwelder" + max_fuel = 10 + w_class = WEIGHT_CLASS_TINY + materials = list(MAT_METAL=30, MAT_GLASS=10) + change_icons = 0 + +/obj/item/weldingtool/mini/flamethrower_screwdriver() + return + +/obj/item/weldingtool/abductor + name = "alien welding tool" + desc = "An alien welding tool. Whatever fuel it uses, it never runs out." + icon = 'icons/obj/abductor.dmi' + icon_state = "welder" + toolspeed = 0.1 + light_intensity = 0 + change_icons = 0 + origin_tech = "plasmatech=5;engineering=5;abductor=3" + +/obj/item/weldingtool/abductor/process() + if(get_fuel() <= max_fuel) + reagents.add_reagent("welding_fuel", 1) + ..() + +/obj/item/weldingtool/hugetank + name = "upgraded industrial welding tool" + desc = "An upgraded welder based of the industrial welder." + icon_state = "upindwelder" + item_state = "upindwelder" + max_fuel = 80 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "engineering=3;plasmatech=2" + +/obj/item/weldingtool/experimental + name = "experimental welding tool" + desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." + icon_state = "exwelder" + item_state = "exwelder" + max_fuel = 40 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" + var/last_gen = 0 + change_icons = 0 + can_off_process = 1 + light_intensity = 1 + toolspeed = 0.5 + var/nextrefueltick = 0 + +/obj/item/weldingtool/experimental/brass + name = "brass welding tool" + desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "brasswelder" + item_state = "brasswelder" + + +/obj/item/weldingtool/experimental/process() + ..() + if(get_fuel() < max_fuel && nextrefueltick < world.time) + nextrefueltick = world.time + 10 + reagents.add_reagent("welding_fuel", 1) + + +/* + * Crowbar + */ + +/obj/item/crowbar + name = "pocket crowbar" + desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." + icon = 'icons/obj/tools.dmi' + icon_state = "crowbar" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/crowbar.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + origin_tech = "engineering=1;combat=1" + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/crowbar/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/red + icon_state = "crowbar_red" + force = 8 + +/obj/item/crowbar/brass + name = "brass crowbar" + desc = "A brass crowbar. It feels faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "crowbar_brass" + toolspeed = 0.5 + +/obj/item/crowbar/abductor + name = "alien crowbar" + desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." + icon = 'icons/obj/abductor.dmi' + usesound = 'sound/weapons/sonic_jackhammer.ogg' + icon_state = "crowbar" + toolspeed = 0.1 + origin_tech = "combat=4;engineering=4;abductor=3" + +/obj/item/crowbar/large + name = "crowbar" + desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." + force = 12 + w_class = WEIGHT_CLASS_NORMAL + throw_speed = 3 + throw_range = 3 + materials = list(MAT_METAL=70) + icon_state = "crowbar_large" + item_state = "crowbar" + toolspeed = 0.5 + +/obj/item/crowbar/cyborg + name = "hydraulic crowbar" + desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." + usesound = 'sound/items/jaws_pry.ogg' + force = 10 + toolspeed = 0.5 + +/obj/item/crowbar/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." + icon_state = "jaws_pry" + item_state = "jawsoflife" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" + usesound = 'sound/items/jaws_pry.ogg' + force = 15 + toolspeed = 0.25 + +/obj/item/crowbar/power/suicide_act(mob/user) + user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power + to_chat(user, "You attach the cutting jaws to [src].") + qdel(src) + user.put_in_active_hand(cutjaws) + +#undef WELDER_FUEL_BURN_INTERVAL +>>>>>>> 2240756... Gets rid of manual overlay manipulation (#30454) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index e6314861b6..c8be2aa28a 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -524,12 +524,12 @@ /turf/proc/photograph(limit=20) var/image/I = new() - I.overlays += src + I.add_overlay(src) for(var/V in contents) var/atom/A = V if(A.invisibility) continue - I.overlays += A + I.add_overlay(A) if(limit) limit-- else diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 66a15ac705..52f5e4e138 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -248,7 +248,7 @@ if(istype(src, /obj/machinery/hydroponics/soil)) add_atom_colour(rgb(255, 175, 0), FIXED_COLOUR_PRIORITY) else - overlays += mutable_appearance('icons/obj/hydroponics/equipment.dmi', "gaia_blessing") + add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "gaia_blessing")) set_light(3) update_icon_hoses() From d8a3b87719be4d429bccd12d6f13a4d531318d76 Mon Sep 17 00:00:00 2001 From: ShizCalev Date: Thu, 7 Sep 2017 06:14:17 -0400 Subject: [PATCH 006/102] Fixes brains counting towards highlander killstreaks --- code/game/objects/items/weaponry.dm | 569 ++++++++++++++++++++++++++++ 1 file changed, 569 insertions(+) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 13acf7e990..fe9c9485cd 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -23,6 +23,7 @@ else M.visible_message("[M] has been banned FOR NO REISIN by [user]", "You have been banned FOR NO REISIN by [user]", "you hear a banhammer banning someone") +<<<<<<< HEAD playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much /obj/item/sord @@ -589,4 +590,572 @@ /obj/item/proc/can_trigger_gun(mob/living/user) if(!user.can_use_guns(src)) return FALSE +======= + playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much + +/obj/item/sord + name = "\improper SORD" + desc = "This thing is so unspeakably shitty you are having a hard time even holding it." + icon_state = "sord" + item_state = "sord" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + slot_flags = SLOT_BELT + force = 2 + throwforce = 1 + w_class = WEIGHT_CLASS_NORMAL + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/sord/suicide_act(mob/user) + user.visible_message("[user] is trying to impale [user.p_them()]self with [src]! It might be a suicide attempt if it weren't so shitty.", \ + "You try to impale yourself with [src], but it's USELESS...") + return SHAME + +/obj/item/claymore + name = "claymore" + desc = "What are you standing around staring at this for? Get to killing!" + icon_state = "claymore" + item_state = "claymore" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + hitsound = 'sound/weapons/bladeslice.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT | SLOT_BACK + force = 40 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + block_chance = 50 + sharpness = IS_SHARP + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/item/claymore/suicide_act(mob/user) + user.visible_message("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS + desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." + flags_1 = CONDUCT_1 | NODROP_1 | DROPDEL_1 + slot_flags = null + block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY + luminosity = 3 + attack_verb = list("brutalized", "eviscerated", "disemboweled", "hacked", "carved", "cleaved") //ONLY THE MOST VISCERAL ATTACK VERBS + var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE + var/obj/item/disk/nuclear/nuke_disk //OUR STORED NUKE DISK + +/obj/item/claymore/highlander/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/claymore/highlander/Destroy() + if(nuke_disk) + nuke_disk.forceMove(get_turf(src)) + nuke_disk.visible_message("The nuke disk is vulnerable!") + nuke_disk = null + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/claymore/highlander/process() + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS) + H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS + else + if(!admin_spawned) + qdel(src) + + +/obj/item/claymore/highlander/pickup(mob/living/user) + to_chat(user, "The power of Scotland protects you! You are shielded from all stuns and knockdowns.") + user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!") + user.status_flags += IGNORESLOWDOWN + +/obj/item/claymore/highlander/dropped(mob/living/user) + user.status_flags -= IGNORESLOWDOWN + qdel(src) //If this ever happens, it's because you lost an arm + +/obj/item/claymore/highlander/examine(mob/user) + ..() + to_chat(user, "It has [!notches ? "nothing" : "[notches] notches"] scratched into the blade.") + if(nuke_disk) + to_chat(user, "It's holding the nuke disk!") + +/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) + . = ..() + if(!QDELETED(target) && iscarbon(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") + user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES + add_notch(user) + target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") + target.dust() + +/obj/item/claymore/highlander/attack_self(mob/living/user) + var/closest_victim + var/closest_distance = 255 + for(var/mob/living/carbon/human/H in GLOB.player_list - user) + if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) + closest_victim = H + if(!closest_victim) + to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") + return + to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].") + +/obj/item/claymore/highlander/IsReflect() + return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME? + +/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE + notches++ + force++ + var/new_name = name + switch(notches) + if(1) + to_chat(user, "Your first kill - hopefully one of many. You scratch a notch into [src]'s blade.") + to_chat(user, "You feel your fallen foe's soul entering your blade, restoring your wounds!") + new_name = "notched claymore" + if(2) + to_chat(user, "Another falls before you. Another soul fuses with your own. Another notch in the blade.") + new_name = "double-notched claymore" + add_atom_colour(rgb(255, 235, 235), ADMIN_COLOUR_PRIORITY) + if(3) + to_chat(user, "You're beginning to relish the thrill of battle.") + new_name = "triple-notched claymore" + add_atom_colour(rgb(255, 215, 215), ADMIN_COLOUR_PRIORITY) + if(4) + to_chat(user, "You've lost count of how many you've killed.") + new_name = "many-notched claymore" + add_atom_colour(rgb(255, 195, 195), ADMIN_COLOUR_PRIORITY) + if(5) + to_chat(user, "Five voices now echo in your mind, cheering the slaughter.") + new_name = "battle-tested claymore" + add_atom_colour(rgb(255, 175, 175), ADMIN_COLOUR_PRIORITY) + if(6) + to_chat(user, "Is this what the vikings felt like? Visions of glory fill your head as you slay your sixth foe.") + new_name = "battle-scarred claymore" + add_atom_colour(rgb(255, 155, 155), ADMIN_COLOUR_PRIORITY) + if(7) + to_chat(user, "Kill. Butcher. Conquer.") + new_name = "vicious claymore" + add_atom_colour(rgb(255, 135, 135), ADMIN_COLOUR_PRIORITY) + if(8) + to_chat(user, "IT NEVER GETS OLD. THE SCREAMING. THE BLOOD AS IT SPRAYS ACROSS YOUR FACE.") + new_name = "bloodthirsty claymore" + add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY) + if(9) + to_chat(user, "ANOTHER ONE FALLS TO YOUR BLOWS. ANOTHER WEAKLING UNFIT TO LIVE.") + new_name = "gore-stained claymore" + add_atom_colour(rgb(255, 95, 95), ADMIN_COLOUR_PRIORITY) + if(10) + user.visible_message("[user]'s eyes light up with a vengeful fire!", \ + "YOU FEEL THE POWER OF VALHALLA FLOWING THROUGH YOU! THERE CAN BE ONLY ONE!!!") + user.update_icons() + new_name = "GORE-DRENCHED CLAYMORE OF [pick("THE WHIMSICAL SLAUGHTER", "A THOUSAND SLAUGHTERED CATTLE", "GLORY AND VALHALLA", "ANNIHILATION", "OBLITERATION")]" + icon_state = "claymore_valhalla" + item_state = "cultblade" + remove_atom_colour(ADMIN_COLOUR_PRIORITY) + + name = new_name + playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) + +/obj/item/katana + name = "katana" + desc = "Woefully underpowered in D20" + icon_state = "katana" + item_state = "katana" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT | SLOT_BACK + force = 40 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + block_chance = 50 + sharpness = IS_SHARP + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/item/katana/cursed + slot_flags = null + +/obj/item/katana/suicide_act(mob/user) + user.visible_message("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!") + return(BRUTELOSS) + +/obj/item/wirerod + name = "wired rod" + desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." + icon_state = "wiredrod" + item_state = "rods" + flags_1 = CONDUCT_1 + force = 9 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + materials = list(MAT_METAL=1150, MAT_GLASS=75) + attack_verb = list("hit", "bludgeoned", "whacked", "bonked") + +/obj/item/wirerod/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/shard)) + var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear + + remove_item_from_storage(user) + qdel(I) + qdel(src) + + user.put_in_hands(S) + to_chat(user, "You fasten the glass shard to the top of the rod with the cable.") + + else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags_1 & NODROP_1)) + var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod + + remove_item_from_storage(user) + + to_chat(user, "You fasten [I] to the top of the rod with the cable.") + + qdel(I) + qdel(src) + + user.put_in_hands(P) + else + return ..() + + +/obj/item/throwing_star + name = "throwing star" + desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" + icon_state = "throwingstar" + item_state = "eshield0" + lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + force = 2 + throwforce = 20 //This is never used on mobs since this has a 100% embed chance. + throw_speed = 4 + embedded_pain_multiplier = 4 + w_class = WEIGHT_CLASS_SMALL + embed_chance = 100 + embedded_fall_chance = 0 //Hahaha! + sharpness = IS_SHARP + materials = list(MAT_METAL=500, MAT_GLASS=500) + resistance_flags = FIRE_PROOF + + +/obj/item/switchblade + name = "switchblade" + icon_state = "switchblade" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + desc = "A sharp, concealable, spring-loaded knife." + flags_1 = CONDUCT_1 + force = 3 + w_class = WEIGHT_CLASS_SMALL + throwforce = 5 + throw_speed = 3 + throw_range = 6 + materials = list(MAT_METAL=12000) + origin_tech = "engineering=3;combat=2" + hitsound = 'sound/weapons/genhit.ogg' + attack_verb = list("stubbed", "poked") + resistance_flags = FIRE_PROOF + var/extended = 0 + +/obj/item/switchblade/attack_self(mob/user) + extended = !extended + playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1) + if(extended) + force = 20 + w_class = WEIGHT_CLASS_NORMAL + throwforce = 23 + icon_state = "switchblade_ext" + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + sharpness = IS_SHARP + else + force = 3 + w_class = WEIGHT_CLASS_SMALL + throwforce = 5 + icon_state = "switchblade" + attack_verb = list("stubbed", "poked") + hitsound = 'sound/weapons/genhit.ogg' + sharpness = IS_BLUNT + +/obj/item/switchblade/suicide_act(mob/user) + user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/phone + name = "red phone" + desc = "Should anything ever go wrong..." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "red_phone" + force = 3 + throwforce = 2 + throw_speed = 3 + throw_range = 4 + w_class = WEIGHT_CLASS_SMALL + attack_verb = list("called", "rang") + hitsound = 'sound/weapons/ring.ogg' + +/obj/item/phone/suicide_act(mob/user) + if(locate(/obj/structure/chair/stool) in user.loc) + user.visible_message("[user] begins to tie a noose with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") + else + user.visible_message("[user] is strangling [user.p_them()]self with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") + return(OXYLOSS) + +/obj/item/cane + name = "cane" + desc = "A cane used by a true gentleman. Or a clown." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "cane" + item_state = "stick" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 5 + throwforce = 5 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") + +/obj/item/staff + name = "wizard staff" + desc = "Apparently a staff used by the wizard." + icon = 'icons/obj/wizard.dmi' + icon_state = "staff" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + force = 3 + throwforce = 5 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armour_penetration = 100 + attack_verb = list("bludgeoned", "whacked", "disciplined") + resistance_flags = FLAMMABLE + +/obj/item/staff/broom + name = "broom" + desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." + icon = 'icons/obj/wizard.dmi' + icon_state = "broom" + resistance_flags = FLAMMABLE + +/obj/item/staff/stick + name = "stick" + desc = "A great tool to drag someone else's drinks across the bar." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "stick" + item_state = "stick" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 3 + throwforce = 5 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + +/obj/item/ectoplasm + name = "ectoplasm" + desc = "spooky" + gender = PLURAL + icon = 'icons/obj/wizard.dmi' + icon_state = "ectoplasm" + +/obj/item/ectoplasm/suicide_act(mob/user) + user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") + return (OXYLOSS) + +/obj/item/mounted_chainsaw + name = "mounted chainsaw" + desc = "A chainsaw that has replaced your arm." + icon_state = "chainsaw_on" + item_state = "mounted_chainsaw" + lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' + flags_1 = NODROP_1 | ABSTRACT_1 | DROPDEL_1 + w_class = WEIGHT_CLASS_HUGE + force = 21 + throwforce = 0 + throw_range = 0 + throw_speed = 0 + sharpness = IS_SHARP + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsawhit.ogg' + +/obj/item/mounted_chainsaw/Destroy() + var/obj/item/bodypart/part + new /obj/item/twohanded/required/chainsaw(get_turf(src)) + if(iscarbon(loc)) + var/mob/living/carbon/holder = loc + var/index = holder.get_held_index_of_item(src) + if(index) + part = holder.hand_bodyparts[index] + . = ..() + if(part) + part.drop_limb() + +/obj/item/statuebust + name = "bust" + desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it + icon = 'icons/obj/statue.dmi' + icon_state = "bust" + force = 15 + throwforce = 10 + throw_speed = 5 + throw_range = 2 + attack_verb = list("busted") + +/obj/item/tailclub + name = "tail club" + desc = "For the beating to death of lizards with their own tails." + icon_state = "tailclub" + force = 14 + throwforce = 1 // why are you throwing a club do you even weapon + throw_speed = 1 + throw_range = 1 + attack_verb = list("clubbed", "bludgeoned") + +/obj/item/melee/chainofcommand/tailwhip + name = "liz o' nine tails" + desc = "A whip fashioned from the severed tails of lizards." + icon_state = "tailwhip" + origin_tech = "engineering=3;combat=3;biotech=3" + needs_permit = 0 + +/obj/item/melee/chainofcommand/tailwhip/kitty + name = "cat o' nine tails" + desc = "A whip fashioned from the severed tails of cats." + icon_state = "catwhip" + +/obj/item/melee/skateboard + name = "skateboard" + desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon." + icon_state = "skateboard" + item_state = "skateboard" + force = 12 + throwforce = 4 + w_class = WEIGHT_CLASS_HUGE + attack_verb = list("smacked", "whacked", "slammed", "smashed") + +/obj/item/melee/skateboard/attack_self(mob/user) + new /obj/vehicle/scooter/skateboard(get_turf(user)) + qdel(src) + +/obj/item/melee/baseball_bat + name = "baseball bat" + desc = "There ain't a skull in the league that can withstand a swatter." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "baseball_bat" + item_state = "baseball_bat" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 10 + throwforce = 12 + attack_verb = list("beat", "smacked") + w_class = WEIGHT_CLASS_HUGE + var/homerun_ready = 0 + var/homerun_able = 0 + +/obj/item/melee/baseball_bat/homerun + name = "home run bat" + desc = "This thing looks dangerous... Dangerously good at baseball, that is." + homerun_able = 1 + +/obj/item/melee/baseball_bat/attack_self(mob/user) + if(!homerun_able) + ..() + return + if(homerun_ready) + to_chat(user, "You're already ready to do a home run!") + ..() + return + to_chat(user, "You begin gathering strength...") + playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1) + if(do_after(user, 90, target = src)) + to_chat(user, "You gather power! Time for a home run!") + homerun_ready = 1 + ..() + +/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user) + . = ..() + var/atom/throw_target = get_edge_target_turf(target, user.dir) + if(homerun_ready) + user.visible_message("It's a home run!") + target.throw_at(throw_target, rand(8,10), 14, user) + target.ex_act(EXPLODE_HEAVY) + playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) + homerun_ready = 0 + return + else if(!target.anchored) + target.throw_at(throw_target, rand(1,2), 7, user) + +/obj/item/melee/baseball_bat/ablative + name = "metal baseball bat" + desc = "This bat is made of highly reflective, highly armored material." + icon_state = "baseball_bat_metal" + item_state = "baseball_bat_metal" + force = 12 + throwforce = 15 + +/obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers + var/picksound = rand(1,2) + var/turf = get_turf(src) + if(picksound == 1) + playsound(turf, 'sound/weapons/effects/batreflect1.ogg', 50, 1) + if(picksound == 2) + playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) + return 1 + +/obj/item/melee/flyswatter + name = "flyswatter" + desc = "Useful for killing insects of all sizes." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "flyswatter" + item_state = "flyswatter" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 1 + throwforce = 1 + attack_verb = list("swatted", "smacked") + hitsound = 'sound/effects/snap.ogg' + w_class = WEIGHT_CLASS_SMALL + //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. + var/list/strong_against + +/obj/item/melee/flyswatter/Initialize() + . = ..() + strong_against = typecacheof(list( + /mob/living/simple_animal/hostile/poison/bees/, + /mob/living/simple_animal/butterfly, + /mob/living/simple_animal/cockroach, + /obj/item/queen_bee + )) + + +/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag) + if(proximity_flag) + if(is_type_in_typecache(target, strong_against)) + new /obj/effect/decal/cleanable/deadcockroach(get_turf(target)) + to_chat(user, "You easily splat the [target].") + if(istype(target, /mob/living/)) + var/mob/living/bug = target + bug.death(1) + else + qdel(target) + +/obj/item/circlegame + name = "circled hand" + desc = "If somebody looks at this while it's below your waist, you get to bop them." + icon_state = "madeyoulook" + force = 0 + throwforce = 0 + flags_1 = DROPDEL_1 | ABSTRACT_1 + attack_verb = list("bopped") + +/obj/item/proc/can_trigger_gun(mob/living/user) + if(!user.can_use_guns(src)) + return FALSE +>>>>>>> 129a7b9... Fixes brains counting towards highlander killstreaks (#30396) return TRUE From 3f025582f285a0e5a39c48d9a0c8762aa3ecaa0b Mon Sep 17 00:00:00 2001 From: Kyle Spier-Swenson Date: Thu, 7 Sep 2017 08:01:26 -0700 Subject: [PATCH 007/102] Gives admins the ability to show a read only vv window to a player --- code/datums/datumvars.dm | 506 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 87c6ad7334..cb9be25f05 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -22,6 +22,7 @@ //please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down //add separaters by doing . += "---" +<<<<<<< HEAD /datum/proc/vv_get_dropdown() . = list() . += "---" @@ -485,6 +486,472 @@ if(!check_rights(0)) return +======= +/datum/proc/vv_get_dropdown() + . = list() + . += "---" + .["Call Proc"] = "?_src_=vars;proc_call=\ref[src]" + .["Mark Object"] = "?_src_=vars;mark_object=\ref[src]" + .["Delete"] = "?_src_=vars;delete=\ref[src]" + .["Show VV To Player"] = "?_src_=vars;expose=\ref[src]" + + +/datum/proc/on_reagent_change() + return + + +/client/proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + //set src in world + var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. + + if(!usr.client || !usr.client.holder) //The usr vs src abuse in this proc is intentional and must not be changed + to_chat(usr, "You need to be an administrator to access this.") + return + + if(!D) + return + + var/islist = islist(D) + if (!islist && !istype(D)) + return + + var/title = "" + var/refid = "\ref[D]" + var/icon/sprite + var/hash + + var/type = /list + if (!islist) + type = D.type + + + + if(istype(D, /atom)) + var/atom/AT = D + if(AT.icon && AT.icon_state) + sprite = new /icon(AT.icon, AT.icon_state) + hash = md5(AT.icon) + hash = md5(hash + AT.icon_state) + src << browse_rsc(sprite, "vv[hash].png") + + title = "[D] (\ref[D]) = [type]" + + var/sprite_text + if(sprite) + sprite_text = "" + var/list/atomsnowflake = list() + + if(istype(D, /atom)) + var/atom/A = D + if(isliving(A)) + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
<< [dir2text(A.dir)] >>" + var/mob/living/M = A + atomsnowflake += {" +
[M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"] +
+ BRUTE:[M.getBruteLoss()] + FIRE:[M.getFireLoss()] + TOXIN:[M.getToxLoss()] + OXY:[M.getOxyLoss()] + CLONE:[M.getCloneLoss()] + BRAIN:[M.getBrainLoss()] + STAMINA:[M.getStaminaLoss()] + + "} + else + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
<< [dir2text(A.dir)] >>" + else + atomsnowflake += "[D]" + + var/formatted_type = "[type]" + if(length(formatted_type) > 25) + var/middle_point = length(formatted_type) / 2 + var/splitpoint = findtext(formatted_type,"/",middle_point) + if(splitpoint) + formatted_type = "[copytext(formatted_type,1,splitpoint)]
[copytext(formatted_type,splitpoint)]" + else + formatted_type = "Type too long" //No suitable splitpoint (/) found. + + var/marked + if(holder && holder.marked_datum && holder.marked_datum == D) + marked = "
Marked Object" + var/varedited_line = "" + if(!islist && D.var_edited) + varedited_line = "
Var Edited" + + var/list/dropdownoptions = list() + if (islist) + dropdownoptions = list( + "---", + "Add Item" = "?_src_=vars;listadd=[refid]", + "Remove Nulls" = "?_src_=vars;listnulls=[refid]", + "Remove Dupes" = "?_src_=vars;listdupes=[refid]", + "Set len" = "?_src_=vars;listlen=[refid]", + "Shuffle" = "?_src_=vars;listshuffle=[refid]", + "Show VV To Player" = "?_src_=vars;expose=[refid]" + ) + else + dropdownoptions = D.vv_get_dropdown() + var/list/dropdownoptions_html = list() + + for (var/name in dropdownoptions) + var/link = dropdownoptions[name] + if (link) + dropdownoptions_html += "" + else + dropdownoptions_html += "" + + var/list/names = list() + if (!islist) + for (var/V in D.vars) + names += V + sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. + + var/list/variable_html = list() + if (islist) + var/list/L = D + for (var/i in 1 to L.len) + var/key = L[i] + var/value + if (IS_NORMAL_LIST(L) && !isnum(key)) + value = L[key] + variable_html += debug_variable(i, value, 0, D) + else + + names = sortList(names) + for (var/V in names) + if(D.can_vv_get(V)) + variable_html += D.vv_get_var(V) + + var/html = {" + + + [title] + + + + +
+ + + + + +
+ + + + +
+ [sprite_text] +
+ [atomsnowflake.Join()] +
+
+
+ [formatted_type] + [marked] + [varedited_line] +
+
+
+ Refresh +
+ +
+
+
+
+
+ + E - Edit, tries to determine the variable type by itself.
+ C - Change, asks you for the var type first.
+ M - Mass modify: changes this variable for all objects of this type.
+
+
+ + + + + +
+
+ Search: +
+
+ +
+
+
    + [variable_html.Join()] +
+ + + +"} + src << browse(html, "window=variables[refid];size=475x650") + + +#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) +/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) + var/header + if(DA) + if (islist(DA)) + var/index = name + if (value) + name = DA[name] //name is really the index until this line + else + value = DA[name] + header = "
  • (E) (C) (-) " + else + header = "
  • (E) (C) (M) " + else + header = "
  • " + + var/item + if (isnull(value)) + item = "[VV_HTML_ENCODE(name)] = null" + + else if (istext(value)) + item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" + + else if (isicon(value)) + #ifdef VARSICON + var/icon/I = new/icon(value) + var/rnd = rand(1,10000) + var/rname = "tmp\ref[I][rnd].png" + usr << browse_rsc(I, rname) + item = "[VV_HTML_ENCODE(name)] = ([value]) " + #else + item = "[VV_HTML_ENCODE(name)] = /icon ([value])" + #endif + +/* else if (istype(value, /image)) + #ifdef VARSICON + var/rnd = rand(1, 10000) + var/image/I = value + + src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") + html += "[name] = " + #else + html += "[name] = /image ([value])" + #endif +*/ + else if (isfile(value)) + item = "[VV_HTML_ENCODE(name)] = '[value]'" + + //else if (istype(value, /client)) + // var/client/C = value + // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" + + else if (istype(value, /datum)) + var/datum/D = value + if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" + else + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" + + else if (islist(value)) + var/list/L = value + var/list/items = list() + + if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) + for (var/i in 1 to L.len) + var/key = L[i] + var/val + if (IS_NORMAL_LIST(L) && !isnum(key)) + val = L[key] + if (!val) + val = key + key = i + + items += debug_variable(key, val, level + 1, sanitize = sanitize) + + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " + else + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + + else + item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" + + return "[header][item]
  • " + +#undef VV_HTML_ENCODE + +/client/proc/view_var_Topic(href, href_list, hsrc) + if( (usr.client != src) || !src.holder ) + return + if(href_list["Vars"]) + debug_variables(locate(href_list["Vars"])) + + else if(href_list["datumrefresh"]) + var/datum/DAT = locate(href_list["datumrefresh"]) + if(!DAT) //can't be an istype() because /client etc aren't datums + return + src.debug_variables(DAT) + + else if(href_list["mob_player_panel"]) + if(!check_rights(0)) + return + +>>>>>>> 6656ce6... Gives admins the ability to show a read only vv window to a player (#30463) var/mob/M = locate(href_list["mob_player_panel"]) in GLOB.mob_list if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob") @@ -541,6 +1008,7 @@ return var/mob/M = locate(href_list["regenerateicons"]) in GLOB.mob_list +<<<<<<< HEAD if(!ismob(M)) to_chat(usr, "This can only be done to instances of type /mob") return @@ -557,6 +1025,44 @@ if(!check_rights(0)) return +======= + if(!ismob(M)) + to_chat(usr, "This can only be done to instances of type /mob") + return + M.regenerate_icons() + else if(href_list["expose"]) + if(!check_rights(R_ADMIN, FALSE)) + return + var/thing = locate(href_list["expose"]) + if (!thing) + return + var/value = vv_get_value(VV_CLIENT) + if (value["class"] != VV_CLIENT) + return + var/client/C = value["value"] + if (!C) + return + var/prompt = alert("Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anything nor open nested vv windows unless they themselves are an admin)", "Confirm", "Yes", "No") + if (prompt != "Yes" || !usr.client) + return + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") + log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [thing]") + to_chat(C, "[usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") + C.debug_variables(thing) + + +//Needs +VAREDIT past this point + + else if(check_rights(R_VAREDIT)) + + + //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). + + if(href_list["rename"]) + if(!check_rights(0)) + return + +>>>>>>> 6656ce6... Gives admins the ability to show a read only vv window to a player (#30463) var/mob/M = locate(href_list["rename"]) in GLOB.mob_list if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob") From c2c69d359f1255e1869d9a9b69bc8633cee9dd38 Mon Sep 17 00:00:00 2001 From: AnturK Date: Wed, 6 Sep 2017 10:44:38 +0200 Subject: [PATCH 008/102] Fixes shuttle name on ramming. --- code/modules/shuttle/on_move.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 59a0a46ae8..e80b690737 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -14,7 +14,12 @@ All ShuttleMove procs go here // Called from the new turf before anything has been moved // Only gets called if fromShuttleMove returns true first // returns the new move_mode (based on the old) +<<<<<<< HEAD /turf/proc/toShuttleMove(turf/oldT, shuttle_dir, move_mode) +======= +/turf/proc/toShuttleMove(turf/oldT, move_mode, obj/docking_port/mobile/shuttle) + var/shuttle_dir = shuttle.dir +>>>>>>> 9ac60a8... Typo for(var/i in contents) var/atom/movable/thing = i if(ismob(thing)) From cf07ead653fbc0cfd3b3195e69b133e0c17185b6 Mon Sep 17 00:00:00 2001 From: kingofkosmos Date: Fri, 8 Sep 2017 17:57:51 +0300 Subject: [PATCH 010/102] Regularizes resisting out of containers --- .../abduction/machinery/experiment.dm | 22 +- code/game/machinery/cloning.dm | 3 + code/game/machinery/dna_scanner.dm | 24 +- code/game/machinery/gulag_teleporter.dm | 23 +- code/game/machinery/suit_storage_unit.dm | 278 ++++++++++++++++++ .../objects/items/implants/implantchair.dm | 191 ++++++++++++ .../structures/crates_lockers/closets.dm | 25 +- code/game/objects/structures/morgue.dm | 26 +- .../transit_tubes/transit_tube_pod.dm | 3 + code/modules/VR/vr_sleeper.dm | 4 + .../components/unary_devices/cryo.dm | 27 +- .../kitchen_machinery/gibber.dm | 5 +- 12 files changed, 567 insertions(+), 64 deletions(-) diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm index 58ca8bbea9..182b7e2756 100644 --- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm +++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm @@ -12,6 +12,8 @@ var/list/abductee_minds var/flash = " - || - " var/obj/machinery/abductor/console/console + var/message_cooldown = 0 + var/breakout_time = 0.75 /obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user) if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target)) @@ -40,25 +42,23 @@ /obj/machinery/abductor/experiment/relaymove(mob/user) if(user.stat != CONSCIOUS) return - container_resist(user) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") /obj/machinery/abductor/experiment/container_resist(mob/living/user) - var/breakout_time = 600 user.changeNext_move(CLICK_CD_BREAKOUT) user.last_special = world.time + CLICK_CD_BREAKOUT - to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about a minute.)") - user.visible_message("You hear a metallic creaking from [src]!") - - if(do_after(user,(breakout_time), target = src)) + user.visible_message("You see [user] kicking against the door of [src]!", \ + "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a metallic creaking from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) return - - visible_message("[user] successfully broke out of [src]!") - to_chat(user, "You successfully break out of [src]!") - + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") open_machine() - /obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H) var/icon/photo = null var/g = (H.gender == FEMALE) ? "f" : "m" diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 7ea954a671..2276b5154b 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -392,6 +392,9 @@ QDEL_IN(mob_occupant, 40) /obj/machinery/clonepod/relaymove(mob/user) + container_resist() + +/obj/machinery/clonepod/container_resist(mob/living/user) if(user.stat == CONSCIOUS) go_out() diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index 65a6088721..4085b4edb4 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -14,6 +14,8 @@ var/damage_coeff var/scan_level var/precision_coeff + var/message_cooldown + var/breakout_time = 2 /obj/machinery/dna_scannernew/RefreshParts() scan_level = 0 @@ -65,23 +67,20 @@ open_machine() /obj/machinery/dna_scannernew/container_resist(mob/living/user) - var/breakout_time = 2 - if(state_open || !locked) //Open and unlocked, no need to escape - state_open = TRUE + if(!locked) + open_machine() return user.changeNext_move(CLICK_CD_BREAKOUT) user.last_special = world.time + CLICK_CD_BREAKOUT - to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about [breakout_time] minutes.)") - user.visible_message("You hear a metallic creaking from [src]!") - + user.visible_message("You see [user] kicking against the door of [src]!", \ + "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a metallic creaking from [src].") if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked) return - locked = FALSE - visible_message("[user] successfully broke out of [src]!") - to_chat(user, "You successfully break out of [src]!") - + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") open_machine() /obj/machinery/dna_scannernew/proc/locate_computer(type_) @@ -122,10 +121,11 @@ /obj/machinery/dna_scannernew/relaymove(mob/user as mob) if(user.stat || locked) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") return - open_machine() - return /obj/machinery/dna_scannernew/attackby(obj/item/I, mob/user, params) diff --git a/code/game/machinery/gulag_teleporter.dm b/code/game/machinery/gulag_teleporter.dm index b37c5a10a7..d77e91af90 100644 --- a/code/game/machinery/gulag_teleporter.dm +++ b/code/game/machinery/gulag_teleporter.dm @@ -19,6 +19,8 @@ The console is located at computer/gulag_teleporter.dm active_power_usage = 5000 circuit = /obj/item/circuitboard/machine/gulag_teleporter var/locked = FALSE + var/message_cooldown + var/breakout_time = 1 var/jumpsuit_type = /obj/item/clothing/under/rank/prisoner var/shoes_type = /obj/item/clothing/shoes/sneakers/orange var/obj/machinery/gulag_item_reclaimer/linked_reclaimer @@ -46,7 +48,7 @@ The console is located at computer/gulag_teleporter.dm /obj/machinery/gulag_teleporter/interact(mob/user) if(locked) - to_chat(user, "[src] is locked.") + to_chat(user, "[src] is locked!") return toggle_open() @@ -89,28 +91,27 @@ The console is located at computer/gulag_teleporter.dm if(user.stat != CONSCIOUS) return if(locked) - to_chat(user, "[src] is locked!") + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") return open_machine() /obj/machinery/gulag_teleporter/container_resist(mob/living/user) - var/breakout_time = 600 if(!locked) open_machine() return user.changeNext_move(CLICK_CD_BREAKOUT) user.last_special = world.time + CLICK_CD_BREAKOUT - to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about a minute.)") - user.visible_message("You hear a metallic creaking from [src]!") - - if(do_after(user,(breakout_time), target = src)) + user.visible_message("You see [user] kicking against the door of [src]!", \ + "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a metallic creaking from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked) return - locked = FALSE - visible_message("[user] successfully broke out of [src]!") - to_chat(user, "You successfully break out of [src]!") - + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") open_machine() /obj/machinery/gulag_teleporter/proc/locate_reclaimer() diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index cd2a5bd3b5..6ab0cbf17b 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -6,6 +6,7 @@ icon_state = "close" anchored = TRUE density = TRUE +<<<<<<< HEAD max_integrity = 250 var/obj/item/clothing/suit/space/suit = null @@ -101,6 +102,105 @@ mask_type = /obj/item/clothing/mask/breath storage_type = /obj/item/tank/internals/emergency_oxygen/double +======= + max_integrity = 250 + + var/obj/item/clothing/suit/space/suit = null + var/obj/item/clothing/head/helmet/space/helmet = null + var/obj/item/clothing/mask/mask = null + var/obj/item/storage = null + + var/suit_type = null + var/helmet_type = null + var/mask_type = null + var/storage_type = null + + state_open = FALSE + var/locked = FALSE + panel_open = FALSE + var/safeties = TRUE + + var/uv = FALSE + var/uv_super = FALSE + var/uv_cycles = 6 + var/message_cooldown + var/breakout_time = 0.5 + +/obj/machinery/suit_storage_unit/standard_unit + suit_type = /obj/item/clothing/suit/space/eva + helmet_type = /obj/item/clothing/head/helmet/space/eva + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/captain + suit_type = /obj/item/clothing/suit/space/hardsuit/captain + mask_type = /obj/item/clothing/mask/gas/sechailer + storage_type = /obj/item/tank/jetpack/oxygen/captain + +/obj/machinery/suit_storage_unit/engine + suit_type = /obj/item/clothing/suit/space/hardsuit/engine + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/ce + suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite + mask_type = /obj/item/clothing/mask/breath + storage_type= /obj/item/clothing/shoes/magboots/advance + +/obj/machinery/suit_storage_unit/security + suit_type = /obj/item/clothing/suit/space/hardsuit/security + mask_type = /obj/item/clothing/mask/gas/sechailer + +/obj/machinery/suit_storage_unit/hos + suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos + mask_type = /obj/item/clothing/mask/gas/sechailer + storage_type = /obj/item/tank/internals/oxygen + +/obj/machinery/suit_storage_unit/atmos + suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos + mask_type = /obj/item/clothing/mask/gas + storage_type = /obj/item/watertank/atmos + +/obj/machinery/suit_storage_unit/mining + suit_type = /obj/item/clothing/suit/hooded/explorer + mask_type = /obj/item/clothing/mask/gas/explorer + +/obj/machinery/suit_storage_unit/mining/eva + suit_type = /obj/item/clothing/suit/space/hardsuit/mining + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/cmo + suit_type = /obj/item/clothing/suit/space/hardsuit/medical + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/rd + suit_type = /obj/item/clothing/suit/space/hardsuit/rd + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/syndicate + suit_type = /obj/item/clothing/suit/space/hardsuit/syndi + mask_type = /obj/item/clothing/mask/gas/syndicate + storage_type = /obj/item/tank/jetpack/oxygen/harness + +/obj/machinery/suit_storage_unit/ert/command + suit_type = /obj/item/clothing/suit/space/hardsuit/ert + mask_type = /obj/item/clothing/mask/breath + storage_type = /obj/item/tank/internals/emergency_oxygen/double + +/obj/machinery/suit_storage_unit/ert/security + suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec + mask_type = /obj/item/clothing/mask/breath + storage_type = /obj/item/tank/internals/emergency_oxygen/double + +/obj/machinery/suit_storage_unit/ert/engineer + suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi + mask_type = /obj/item/clothing/mask/breath + storage_type = /obj/item/tank/internals/emergency_oxygen/double + +/obj/machinery/suit_storage_unit/ert/medical + suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med + mask_type = /obj/item/clothing/mask/breath + storage_type = /obj/item/tank/internals/emergency_oxygen/double + +>>>>>>> d4d898f... Regularizes resisting out of containers (#30412) /obj/machinery/suit_storage_unit/Initialize() . = ..() wires = new /datum/wires/suit_storage_unit(src) @@ -162,6 +262,7 @@ /obj/machinery/suit_storage_unit/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) +<<<<<<< HEAD open_machine() dump_contents() new /obj/item/stack/sheet/metal (loc, 2) @@ -312,6 +413,183 @@ return ..() +======= + open_machine() + dump_contents() + new /obj/item/stack/sheet/metal (loc, 2) + qdel(src) + +/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user) + if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A)) + return + var/mob/living/target = A + if(!state_open) + to_chat(user, "The unit's doors are shut!") + return + if(!is_operational()) + to_chat(user, "The unit is not operational!") + return + if(occupant || helmet || suit || storage) + to_chat(user, "It's too cluttered inside to fit in!") + return + + if(target == user) + user.visible_message("[user] starts squeezing into [src]!", "You start working your way into [src]...") + else + target.visible_message("[user] starts shoving [target] into [src]!", "[user] starts shoving you into [src]!") + + if(do_mob(user, target, 30)) + if(occupant || helmet || suit || storage) + return + if(target == user) + user.visible_message("[user] slips into [src] and closes the door behind them!", "You slip into [src]'s cramped space and shut its door.") + else + target.visible_message("[user] pushes [target] into [src] and shuts its door!", "[user] shoves you into [src] and shuts the door!") + close_machine(target) + add_fingerprint(user) + +/obj/machinery/suit_storage_unit/proc/cook() + if(uv_cycles) + uv_cycles-- + uv = TRUE + locked = TRUE + update_icon() + if(occupant) + var/mob/living/mob_occupant = occupant + if(uv_super) + mob_occupant.adjustFireLoss(rand(20, 36)) + else + mob_occupant.adjustFireLoss(rand(10, 16)) + mob_occupant.emote("scream") + addtimer(CALLBACK(src, .proc/cook), 50) + else + uv_cycles = initial(uv_cycles) + uv = FALSE + locked = FALSE + if(uv_super) + visible_message("[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.") + playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, 1) + helmet = null + qdel(helmet) + suit = null + qdel(suit) // Delete everything but the occupant. + mask = null + qdel(mask) + storage = null + qdel(storage) + // The wires get damaged too. + wires.cut_all() + else + if(!occupant) + visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.") + else + visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.") + playsound(src, 'sound/machines/airlockclose.ogg', 25, 1) + for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected + I.clean_blood() + I.fingerprints = list() + open_machine(FALSE) + if(occupant) + dump_contents() + +/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb) + if(!prob(prb)) + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(5, 1, src) + s.start() + if(electrocute_mob(user, src, src, 1, TRUE)) + return 1 + +/obj/machinery/suit_storage_unit/relaymove(mob/user) + if(locked) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") + return + open_machine() + dump_contents() + +/obj/machinery/suit_storage_unit/container_resist(mob/living/user) + if(!locked) + open_machine() + dump_contents() + return + user.changeNext_move(CLICK_CD_BREAKOUT) + user.last_special = world.time + CLICK_CD_BREAKOUT + user.visible_message("You see [user] kicking against the doors of [src]!", \ + "You start kicking against the doors... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a thump from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds + if(!user || user.stat != CONSCIOUS || user.loc != src ) + return + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") + open_machine() + dump_contents() + + add_fingerprint(user) + if(locked) + visible_message("You see [user] kicking against the doors of [src]!", \ + "You start kicking against the doors...") + addtimer(CALLBACK(src, .proc/resist_open, user), 300) + else + open_machine() + dump_contents() + +/obj/machinery/suit_storage_unit/proc/resist_open(mob/user) + if(!state_open && occupant && (user in src) && user.stat == 0) // Check they're still here. + visible_message("You see [user] bursts out of [src]!", \ + "You escape the cramped confines of [src]!") + open_machine() + +/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params) + if(state_open && is_operational()) + if(istype(I, /obj/item/clothing/suit/space)) + if(suit) + to_chat(user, "The unit already contains a suit!.") + return + if(!user.drop_item()) + return + suit = I + else if(istype(I, /obj/item/clothing/head/helmet)) + if(helmet) + to_chat(user, "The unit already contains a helmet!") + return + if(!user.drop_item()) + return + helmet = I + else if(istype(I, /obj/item/clothing/mask)) + if(mask) + to_chat(user, "The unit already contains a mask!") + return + if(!user.drop_item()) + return + mask = I + else + if(storage) + to_chat(user, "The auxiliary storage compartment is full!") + return + if(!user.drop_item()) + return + storage = I + + I.loc = src + visible_message("[user] inserts [I] into [src]", "You load [I] into [src].") + update_icon() + return + + if(panel_open && is_wire_tool(I)) + wires.interact(user) + if(!state_open) + if(default_deconstruction_screwdriver(user, "panel", "close", I)) + return + if(default_pry_open(I)) + dump_contents() + return + + return ..() + +>>>>>>> d4d898f... Regularizes resisting out of containers (#30412) /obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) diff --git a/code/game/objects/items/implants/implantchair.dm b/code/game/objects/items/implants/implantchair.dm index 55a35960cf..c7035f748e 100644 --- a/code/game/objects/items/implants/implantchair.dm +++ b/code/game/objects/items/implants/implantchair.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /obj/machinery/implantchair name = "mindshield implanter" desc = "Used to implant occupants with mindshield implants." @@ -185,3 +186,193 @@ log_game("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.") return 1 +======= +/obj/machinery/implantchair + name = "mindshield implanter" + desc = "Used to implant occupants with mindshield implants." + icon = 'icons/obj/machines/implantchair.dmi' + icon_state = "implantchair" + density = TRUE + opacity = 0 + anchored = TRUE + + var/ready = TRUE + var/replenishing = FALSE + + var/ready_implants = 5 + var/max_implants = 5 + var/injection_cooldown = 600 + var/replenish_cooldown = 6000 + var/implant_type = /obj/item/implant/mindshield + var/auto_inject = FALSE + var/auto_replenish = TRUE + var/special = FALSE + var/special_name = "special function" + var/message_cooldown + var/breakout_time = 1 + +/obj/machinery/implantchair/Initialize() + . = ..() + open_machine() + update_icon() + + +/obj/machinery/implantchair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "implantchair", name, 375, 280, master_ui, state) + ui.open() + + +/obj/machinery/implantchair/ui_data() + var/list/data = list() + data["occupied"] = occupant ? 1 : 0 + data["open"] = state_open + + data["occupant"] = list() + if(occupant) + var/mob/living/mob_occupant = occupant + data["occupant"]["name"] = mob_occupant.name + data["occupant"]["stat"] = mob_occupant.stat + + data["special_name"] = special ? special_name : null + data["ready_implants"] = ready_implants + data["ready"] = ready + data["replenishing"] = replenishing + + return data + +/obj/machinery/implantchair/ui_act(action, params) + if(..()) + return + switch(action) + if("door") + if(state_open) + close_machine() + else + open_machine() + . = TRUE + if("implant") + implant(occupant,usr) + . = TRUE + +/obj/machinery/implantchair/proc/implant(mob/living/M,mob/user) + if (!istype(M)) + return + if(!ready_implants || !ready) + return + if(implant_action(M,user)) + ready_implants-- + if(!replenishing && auto_replenish) + replenishing = TRUE + addtimer(CALLBACK(src,"replenish"),replenish_cooldown) + if(injection_cooldown > 0) + ready = FALSE + addtimer(CALLBACK(src,"set_ready"),injection_cooldown) + else + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, 1) + update_icon() + +/obj/machinery/implantchair/proc/implant_action(mob/living/M) + var/obj/item/implant/I = new implant_type + if(I.implant(M)) + visible_message("[M] has been implanted by the [name].") + return 1 + +/obj/machinery/implantchair/update_icon() + icon_state = initial(icon_state) + if(state_open) + icon_state += "_open" + if(occupant) + icon_state += "_occupied" + if(ready) + add_overlay("ready") + else + cut_overlays() + +/obj/machinery/implantchair/proc/replenish() + if(ready_implants < max_implants) + ready_implants++ + if(ready_implants < max_implants) + addtimer(CALLBACK(src,"replenish"),replenish_cooldown) + else + replenishing = FALSE + +/obj/machinery/implantchair/proc/set_ready() + ready = TRUE + update_icon() + +/obj/machinery/implantchair/container_resist(mob/living/user) + user.changeNext_move(CLICK_CD_BREAKOUT) + user.last_special = world.time + CLICK_CD_BREAKOUT + user.visible_message("You see [user] kicking against the door of [src]!", \ + "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a metallic creaking from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds + if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) + return + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") + open_machine() + +/obj/machinery/implantchair/relaymove(mob/user) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") + +/obj/machinery/implantchair/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !isliving(target) || !user.IsAdvancedToolUser()) + return + close_machine(target) + +/obj/machinery/implantchair/close_machine(mob/living/user) + if((isnull(user) || istype(user)) && state_open) + ..(user) + if(auto_inject && ready && ready_implants > 0) + implant(user,null) + +/obj/machinery/implantchair/genepurge + name = "Genetic purifier" + desc = "Used to purge human genome of foreign influences" + special = TRUE + special_name = "Purge genome" + injection_cooldown = 0 + replenish_cooldown = 300 + +/obj/machinery/implantchair/genepurge/implant_action(mob/living/carbon/human/H,mob/user) + if(!istype(H)) + return 0 + H.set_species(/datum/species/human, 1)//lizards go home + purrbation_remove(H)//remove cats + H.dna.remove_all_mutations()//hulks out + return 1 + + +/obj/machinery/implantchair/brainwash + name = "Neural Imprinter" + desc = "Used to indoctrinate rehabilitate hardened recidivists." + special_name = "Imprint" + injection_cooldown = 3000 + auto_inject = FALSE + auto_replenish = FALSE + special = TRUE + var/objective = "Obey the law. Praise Nanotrasen." + var/custom = FALSE + +/obj/machinery/implantchair/brainwash/implant_action(mob/living/C,mob/user) + if(!istype(C) || !C.mind) // I don't know how this makes any sense for silicons but laws trump objectives anyway. + return 0 + if(custom) + if(!user || !user.Adjacent(src)) + return 0 + objective = stripped_input(usr,"What order do you want to imprint on [C]?","Enter the order","",120) + message_admins("[key_name_admin(user)] set brainwash machine objective to '[objective]'.") + log_game("[key_name_admin(user)] set brainwash machine objective to '[objective]'.") + var/datum/objective/custom_objective = new/datum/objective(objective) + custom_objective.owner = C.mind + C.mind.objectives += custom_objective + C.mind.announce_objectives() + message_admins("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.") + log_game("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.") + return 1 +>>>>>>> d4d898f... Regularizes resisting out of containers (#30412) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 78e672e49d..4f8705aa71 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -16,7 +16,7 @@ integrity_failure = 50 armor = list(melee = 20, bullet = 10, laser = 10, energy = 0, bomb = 10, bio = 0, rad = 0, fire = 70, acid = 60) var/breakout_time = 2 - var/lastbang + var/message_cooldown var/can_weld_shut = TRUE var/horizontal = FALSE var/allow_objects = FALSE @@ -300,14 +300,12 @@ /obj/structure/closet/relaymove(mob/user) if(user.stat || !isturf(loc) || !isliving(user)) return - var/mob/living/L = user - if(!open()) - if(L.last_special <= world.time) - container_resist(L) - if(world.time > lastbang+5) - lastbang = world.time - for(var/mob/M in get_hearers_in_view(src, null)) - M.show_message("BANG, bang!", 2) + if(locked) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") + return + container_resist() /obj/structure/closet/attack_hand(mob/user) ..() @@ -367,9 +365,10 @@ //okay, so the closet is either welded or locked... resist!!! user.changeNext_move(CLICK_CD_BREAKOUT) user.last_special = world.time + CLICK_CD_BREAKOUT - to_chat(user, "You lean on the back of [src] and start pushing the door open.") - visible_message("[src] begins to shake violently!") - if(do_after(user,(breakout_time * 60 * 10), target = src)) //minutes * 60seconds * 10deciseconds + user.visible_message("[src] begins to shake violently!", \ + "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear banging from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) ) return //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting @@ -388,7 +387,7 @@ /obj/structure/closet/AltClick(mob/user) ..() - if(!user.canUseTopic(src, be_close=TRUE)) + if(!user.canUseTopic(src, be_close=TRUE) || isturf(loc)) to_chat(user, "You can't do that right now!") return if(opened || !secure) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 600e15201d..f4a98811c0 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -23,6 +23,8 @@ var/obj/structure/tray/connected = null var/locked = FALSE var/opendir = SOUTH + var/message_cooldown + var/breakout_time = 1 /obj/structure/bodycontainer/Destroy() open() @@ -41,6 +43,11 @@ /obj/structure/bodycontainer/relaymove(mob/user) if(user.stat || !isturf(loc)) return + if(locked) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") + return open() /obj/structure/bodycontainer/attack_paw(mob/user) @@ -84,11 +91,20 @@ qdel(src) /obj/structure/bodycontainer/container_resist(mob/living/user) - open() - -/obj/structure/bodycontainer/relay_container_resist(mob/living/user, obj/O) - to_chat(user, "You slam yourself into the side of [O].") - container_resist(user) + if(!locked) + open() + return + user.changeNext_move(CLICK_CD_BREAKOUT) + user.last_special = world.time + CLICK_CD_BREAKOUT + user.visible_message(null, \ + "You lean on the back of [src] and start pushing the tray open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a metallic creaking from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds + if(!user || user.stat != CONSCIOUS || user.loc != src ) + return + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") + open() /obj/structure/bodycontainer/proc/open() playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index 89f02b13af..fcd9ead2a7 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -66,6 +66,9 @@ deconstruct(FALSE) /obj/structure/transit_tube_pod/container_resist(mob/living/user) + if(!user.incapacitated()) + empty_pod() + return if(!moving) user.changeNext_move(CLICK_CD_BREAKOUT) user.last_special = world.time + CLICK_CD_BREAKOUT diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm index a83ced850e..f447b2f3e9 100644 --- a/code/modules/VR/vr_sleeper.dm +++ b/code/modules/VR/vr_sleeper.dm @@ -49,6 +49,10 @@ open_machine() +/obj/machinery/vr_sleeper/container_resist(mob/living/user) + open_machine() + + /obj/machinery/vr_sleeper/Destroy() open_machine() cleanup_vr_human() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index f0f41e375a..89e6538b07 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -32,6 +32,8 @@ var/running_bob_anim = FALSE var/escape_in_progress = FALSE + var/message_cooldown + var/breakout_time = 0.5 /obj/machinery/atmospherics/components/unary/cryo_cell/Initialize() . = ..() @@ -219,7 +221,9 @@ update_icon() /obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/user) - container_resist(user) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, "[src]'s door won't budge!") /obj/machinery/atmospherics/components/unary/cryo_cell/open_machine(drop = 0) if(!state_open && !panel_open) @@ -239,16 +243,17 @@ return occupant /obj/machinery/atmospherics/components/unary/cryo_cell/container_resist(mob/living/user) - if(escape_in_progress) - to_chat(user, "You are already trying to exit (This will take around 30 seconds)") - return - escape_in_progress = TRUE - to_chat(user, "You struggle inside the cryotube, kicking the release with your foot... (This will take around 30 seconds.)") - audible_message("You hear a thump from [src].") - if(do_after(user, 300)) - if(occupant == user) // Check they're still here. - open_machine() - escape_in_progress = FALSE + user.changeNext_move(CLICK_CD_BREAKOUT) + user.last_special = world.time + CLICK_CD_BREAKOUT + user.visible_message("You see [user] kicking against the glass of [src]!", \ + "You struggle inside [src], kicking the release with your foot... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \ + "You hear a thump from [src].") + if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds + if(!user || user.stat != CONSCIOUS || user.loc != src ) + return + user.visible_message("[user] successfully broke out of [src]!", \ + "You successfully break out of [src]!") + open_machine() /obj/machinery/atmospherics/components/unary/cryo_cell/examine(mob/user) ..() diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm index d9f70160a4..978e8af62d 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm @@ -51,6 +51,9 @@ /obj/machinery/gibber/container_resist(mob/living/user) go_out() +/obj/machinery/gibber/relaymove(mob/living/user) + go_out() + /obj/machinery/gibber/attack_hand(mob/user) if(stat & (NOPOWER|BROKEN)) return @@ -225,4 +228,4 @@ if(M.loc == input_plate) M.forceMove(src) - M.gib() \ No newline at end of file + M.gib() From 0dfe72d77ed5a9a5d37c23736c88ab3d255753f0 Mon Sep 17 00:00:00 2001 From: Armhulen Date: Fri, 8 Sep 2017 08:00:34 -0700 Subject: [PATCH 011/102] chainsaws rebalance, but working this time :) --- code/game/objects/items/twohanded.dm | 2 +- code/game/objects/items/weaponry.dm | 569 +++++++++++++++++++++++++++ code/modules/crafting/recipes.dm | 4 +- 3 files changed, 572 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index 323527fc88..6c19b49073 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -487,7 +487,7 @@ righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' flags_1 = CONDUCT_1 force = 13 - var/force_on = 21 + var/force_on = 24 w_class = WEIGHT_CLASS_HUGE throwforce = 13 throw_speed = 2 diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 13acf7e990..1c5a409dd3 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -23,6 +23,7 @@ else M.visible_message("[M] has been banned FOR NO REISIN by [user]", "You have been banned FOR NO REISIN by [user]", "you hear a banhammer banning someone") +<<<<<<< HEAD playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much /obj/item/sord @@ -589,4 +590,572 @@ /obj/item/proc/can_trigger_gun(mob/living/user) if(!user.can_use_guns(src)) return FALSE +======= + playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much + +/obj/item/sord + name = "\improper SORD" + desc = "This thing is so unspeakably shitty you are having a hard time even holding it." + icon_state = "sord" + item_state = "sord" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + slot_flags = SLOT_BELT + force = 2 + throwforce = 1 + w_class = WEIGHT_CLASS_NORMAL + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/sord/suicide_act(mob/user) + user.visible_message("[user] is trying to impale [user.p_them()]self with [src]! It might be a suicide attempt if it weren't so shitty.", \ + "You try to impale yourself with [src], but it's USELESS...") + return SHAME + +/obj/item/claymore + name = "claymore" + desc = "What are you standing around staring at this for? Get to killing!" + icon_state = "claymore" + item_state = "claymore" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + hitsound = 'sound/weapons/bladeslice.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT | SLOT_BACK + force = 40 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + block_chance = 50 + sharpness = IS_SHARP + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/item/claymore/suicide_act(mob/user) + user.visible_message("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS + desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." + flags_1 = CONDUCT_1 | NODROP_1 | DROPDEL_1 + slot_flags = null + block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY + luminosity = 3 + attack_verb = list("brutalized", "eviscerated", "disemboweled", "hacked", "carved", "cleaved") //ONLY THE MOST VISCERAL ATTACK VERBS + var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE + var/obj/item/disk/nuclear/nuke_disk //OUR STORED NUKE DISK + +/obj/item/claymore/highlander/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/claymore/highlander/Destroy() + if(nuke_disk) + nuke_disk.forceMove(get_turf(src)) + nuke_disk.visible_message("The nuke disk is vulnerable!") + nuke_disk = null + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/claymore/highlander/process() + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS) + H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS + else + if(!admin_spawned) + qdel(src) + + +/obj/item/claymore/highlander/pickup(mob/living/user) + to_chat(user, "The power of Scotland protects you! You are shielded from all stuns and knockdowns.") + user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!") + user.status_flags += IGNORESLOWDOWN + +/obj/item/claymore/highlander/dropped(mob/living/user) + user.status_flags -= IGNORESLOWDOWN + qdel(src) //If this ever happens, it's because you lost an arm + +/obj/item/claymore/highlander/examine(mob/user) + ..() + to_chat(user, "It has [!notches ? "nothing" : "[notches] notches"] scratched into the blade.") + if(nuke_disk) + to_chat(user, "It's holding the nuke disk!") + +/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) + . = ..() + if(!QDELETED(target) && iscarbon(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") + user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES + add_notch(user) + target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") + target.dust() + +/obj/item/claymore/highlander/attack_self(mob/living/user) + var/closest_victim + var/closest_distance = 255 + for(var/mob/living/carbon/human/H in GLOB.player_list - user) + if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) + closest_victim = H + if(!closest_victim) + to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") + return + to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].") + +/obj/item/claymore/highlander/IsReflect() + return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME? + +/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE + notches++ + force++ + var/new_name = name + switch(notches) + if(1) + to_chat(user, "Your first kill - hopefully one of many. You scratch a notch into [src]'s blade.") + to_chat(user, "You feel your fallen foe's soul entering your blade, restoring your wounds!") + new_name = "notched claymore" + if(2) + to_chat(user, "Another falls before you. Another soul fuses with your own. Another notch in the blade.") + new_name = "double-notched claymore" + add_atom_colour(rgb(255, 235, 235), ADMIN_COLOUR_PRIORITY) + if(3) + to_chat(user, "You're beginning to relish the thrill of battle.") + new_name = "triple-notched claymore" + add_atom_colour(rgb(255, 215, 215), ADMIN_COLOUR_PRIORITY) + if(4) + to_chat(user, "You've lost count of how many you've killed.") + new_name = "many-notched claymore" + add_atom_colour(rgb(255, 195, 195), ADMIN_COLOUR_PRIORITY) + if(5) + to_chat(user, "Five voices now echo in your mind, cheering the slaughter.") + new_name = "battle-tested claymore" + add_atom_colour(rgb(255, 175, 175), ADMIN_COLOUR_PRIORITY) + if(6) + to_chat(user, "Is this what the vikings felt like? Visions of glory fill your head as you slay your sixth foe.") + new_name = "battle-scarred claymore" + add_atom_colour(rgb(255, 155, 155), ADMIN_COLOUR_PRIORITY) + if(7) + to_chat(user, "Kill. Butcher. Conquer.") + new_name = "vicious claymore" + add_atom_colour(rgb(255, 135, 135), ADMIN_COLOUR_PRIORITY) + if(8) + to_chat(user, "IT NEVER GETS OLD. THE SCREAMING. THE BLOOD AS IT SPRAYS ACROSS YOUR FACE.") + new_name = "bloodthirsty claymore" + add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY) + if(9) + to_chat(user, "ANOTHER ONE FALLS TO YOUR BLOWS. ANOTHER WEAKLING UNFIT TO LIVE.") + new_name = "gore-stained claymore" + add_atom_colour(rgb(255, 95, 95), ADMIN_COLOUR_PRIORITY) + if(10) + user.visible_message("[user]'s eyes light up with a vengeful fire!", \ + "YOU FEEL THE POWER OF VALHALLA FLOWING THROUGH YOU! THERE CAN BE ONLY ONE!!!") + user.update_icons() + new_name = "GORE-DRENCHED CLAYMORE OF [pick("THE WHIMSICAL SLAUGHTER", "A THOUSAND SLAUGHTERED CATTLE", "GLORY AND VALHALLA", "ANNIHILATION", "OBLITERATION")]" + icon_state = "claymore_valhalla" + item_state = "cultblade" + remove_atom_colour(ADMIN_COLOUR_PRIORITY) + + name = new_name + playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) + +/obj/item/katana + name = "katana" + desc = "Woefully underpowered in D20" + icon_state = "katana" + item_state = "katana" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT | SLOT_BACK + force = 40 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + block_chance = 50 + sharpness = IS_SHARP + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/item/katana/cursed + slot_flags = null + +/obj/item/katana/suicide_act(mob/user) + user.visible_message("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!") + return(BRUTELOSS) + +/obj/item/wirerod + name = "wired rod" + desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." + icon_state = "wiredrod" + item_state = "rods" + flags_1 = CONDUCT_1 + force = 9 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + materials = list(MAT_METAL=1150, MAT_GLASS=75) + attack_verb = list("hit", "bludgeoned", "whacked", "bonked") + +/obj/item/wirerod/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/shard)) + var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear + + remove_item_from_storage(user) + qdel(I) + qdel(src) + + user.put_in_hands(S) + to_chat(user, "You fasten the glass shard to the top of the rod with the cable.") + + else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags_1 & NODROP_1)) + var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod + + remove_item_from_storage(user) + + to_chat(user, "You fasten [I] to the top of the rod with the cable.") + + qdel(I) + qdel(src) + + user.put_in_hands(P) + else + return ..() + + +/obj/item/throwing_star + name = "throwing star" + desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" + icon_state = "throwingstar" + item_state = "eshield0" + lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + force = 2 + throwforce = 20 //This is never used on mobs since this has a 100% embed chance. + throw_speed = 4 + embedded_pain_multiplier = 4 + w_class = WEIGHT_CLASS_SMALL + embed_chance = 100 + embedded_fall_chance = 0 //Hahaha! + sharpness = IS_SHARP + materials = list(MAT_METAL=500, MAT_GLASS=500) + resistance_flags = FIRE_PROOF + + +/obj/item/switchblade + name = "switchblade" + icon_state = "switchblade" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + desc = "A sharp, concealable, spring-loaded knife." + flags_1 = CONDUCT_1 + force = 3 + w_class = WEIGHT_CLASS_SMALL + throwforce = 5 + throw_speed = 3 + throw_range = 6 + materials = list(MAT_METAL=12000) + origin_tech = "engineering=3;combat=2" + hitsound = 'sound/weapons/genhit.ogg' + attack_verb = list("stubbed", "poked") + resistance_flags = FIRE_PROOF + var/extended = 0 + +/obj/item/switchblade/attack_self(mob/user) + extended = !extended + playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1) + if(extended) + force = 20 + w_class = WEIGHT_CLASS_NORMAL + throwforce = 23 + icon_state = "switchblade_ext" + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + sharpness = IS_SHARP + else + force = 3 + w_class = WEIGHT_CLASS_SMALL + throwforce = 5 + icon_state = "switchblade" + attack_verb = list("stubbed", "poked") + hitsound = 'sound/weapons/genhit.ogg' + sharpness = IS_BLUNT + +/obj/item/switchblade/suicide_act(mob/user) + user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/phone + name = "red phone" + desc = "Should anything ever go wrong..." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "red_phone" + force = 3 + throwforce = 2 + throw_speed = 3 + throw_range = 4 + w_class = WEIGHT_CLASS_SMALL + attack_verb = list("called", "rang") + hitsound = 'sound/weapons/ring.ogg' + +/obj/item/phone/suicide_act(mob/user) + if(locate(/obj/structure/chair/stool) in user.loc) + user.visible_message("[user] begins to tie a noose with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") + else + user.visible_message("[user] is strangling [user.p_them()]self with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") + return(OXYLOSS) + +/obj/item/cane + name = "cane" + desc = "A cane used by a true gentleman. Or a clown." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "cane" + item_state = "stick" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 5 + throwforce = 5 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") + +/obj/item/staff + name = "wizard staff" + desc = "Apparently a staff used by the wizard." + icon = 'icons/obj/wizard.dmi' + icon_state = "staff" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + force = 3 + throwforce = 5 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armour_penetration = 100 + attack_verb = list("bludgeoned", "whacked", "disciplined") + resistance_flags = FLAMMABLE + +/obj/item/staff/broom + name = "broom" + desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." + icon = 'icons/obj/wizard.dmi' + icon_state = "broom" + resistance_flags = FLAMMABLE + +/obj/item/staff/stick + name = "stick" + desc = "A great tool to drag someone else's drinks across the bar." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "stick" + item_state = "stick" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 3 + throwforce = 5 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + +/obj/item/ectoplasm + name = "ectoplasm" + desc = "spooky" + gender = PLURAL + icon = 'icons/obj/wizard.dmi' + icon_state = "ectoplasm" + +/obj/item/ectoplasm/suicide_act(mob/user) + user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") + return (OXYLOSS) + +/obj/item/mounted_chainsaw + name = "mounted chainsaw" + desc = "A chainsaw that has replaced your arm." + icon_state = "chainsaw_on" + item_state = "mounted_chainsaw" + lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' + flags_1 = NODROP_1 | ABSTRACT_1 | DROPDEL_1 + w_class = WEIGHT_CLASS_HUGE + force = 24 + throwforce = 0 + throw_range = 0 + throw_speed = 0 + sharpness = IS_SHARP + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsawhit.ogg' + +/obj/item/mounted_chainsaw/Destroy() + var/obj/item/bodypart/part + new /obj/item/twohanded/required/chainsaw(get_turf(src)) + if(iscarbon(loc)) + var/mob/living/carbon/holder = loc + var/index = holder.get_held_index_of_item(src) + if(index) + part = holder.hand_bodyparts[index] + . = ..() + if(part) + part.drop_limb() + +/obj/item/statuebust + name = "bust" + desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it + icon = 'icons/obj/statue.dmi' + icon_state = "bust" + force = 15 + throwforce = 10 + throw_speed = 5 + throw_range = 2 + attack_verb = list("busted") + +/obj/item/tailclub + name = "tail club" + desc = "For the beating to death of lizards with their own tails." + icon_state = "tailclub" + force = 14 + throwforce = 1 // why are you throwing a club do you even weapon + throw_speed = 1 + throw_range = 1 + attack_verb = list("clubbed", "bludgeoned") + +/obj/item/melee/chainofcommand/tailwhip + name = "liz o' nine tails" + desc = "A whip fashioned from the severed tails of lizards." + icon_state = "tailwhip" + origin_tech = "engineering=3;combat=3;biotech=3" + needs_permit = 0 + +/obj/item/melee/chainofcommand/tailwhip/kitty + name = "cat o' nine tails" + desc = "A whip fashioned from the severed tails of cats." + icon_state = "catwhip" + +/obj/item/melee/skateboard + name = "skateboard" + desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon." + icon_state = "skateboard" + item_state = "skateboard" + force = 12 + throwforce = 4 + w_class = WEIGHT_CLASS_HUGE + attack_verb = list("smacked", "whacked", "slammed", "smashed") + +/obj/item/melee/skateboard/attack_self(mob/user) + new /obj/vehicle/scooter/skateboard(get_turf(user)) + qdel(src) + +/obj/item/melee/baseball_bat + name = "baseball bat" + desc = "There ain't a skull in the league that can withstand a swatter." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "baseball_bat" + item_state = "baseball_bat" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 10 + throwforce = 12 + attack_verb = list("beat", "smacked") + w_class = WEIGHT_CLASS_HUGE + var/homerun_ready = 0 + var/homerun_able = 0 + +/obj/item/melee/baseball_bat/homerun + name = "home run bat" + desc = "This thing looks dangerous... Dangerously good at baseball, that is." + homerun_able = 1 + +/obj/item/melee/baseball_bat/attack_self(mob/user) + if(!homerun_able) + ..() + return + if(homerun_ready) + to_chat(user, "You're already ready to do a home run!") + ..() + return + to_chat(user, "You begin gathering strength...") + playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1) + if(do_after(user, 90, target = src)) + to_chat(user, "You gather power! Time for a home run!") + homerun_ready = 1 + ..() + +/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user) + . = ..() + var/atom/throw_target = get_edge_target_turf(target, user.dir) + if(homerun_ready) + user.visible_message("It's a home run!") + target.throw_at(throw_target, rand(8,10), 14, user) + target.ex_act(EXPLODE_HEAVY) + playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) + homerun_ready = 0 + return + else if(!target.anchored) + target.throw_at(throw_target, rand(1,2), 7, user) + +/obj/item/melee/baseball_bat/ablative + name = "metal baseball bat" + desc = "This bat is made of highly reflective, highly armored material." + icon_state = "baseball_bat_metal" + item_state = "baseball_bat_metal" + force = 12 + throwforce = 15 + +/obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers + var/picksound = rand(1,2) + var/turf = get_turf(src) + if(picksound == 1) + playsound(turf, 'sound/weapons/effects/batreflect1.ogg', 50, 1) + if(picksound == 2) + playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) + return 1 + +/obj/item/melee/flyswatter + name = "flyswatter" + desc = "Useful for killing insects of all sizes." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "flyswatter" + item_state = "flyswatter" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 1 + throwforce = 1 + attack_verb = list("swatted", "smacked") + hitsound = 'sound/effects/snap.ogg' + w_class = WEIGHT_CLASS_SMALL + //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. + var/list/strong_against + +/obj/item/melee/flyswatter/Initialize() + . = ..() + strong_against = typecacheof(list( + /mob/living/simple_animal/hostile/poison/bees/, + /mob/living/simple_animal/butterfly, + /mob/living/simple_animal/cockroach, + /obj/item/queen_bee + )) + + +/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag) + if(proximity_flag) + if(is_type_in_typecache(target, strong_against)) + new /obj/effect/decal/cleanable/deadcockroach(get_turf(target)) + to_chat(user, "You easily splat the [target].") + if(istype(target, /mob/living/)) + var/mob/living/bug = target + bug.death(1) + else + qdel(target) + +/obj/item/circlegame + name = "circled hand" + desc = "If somebody looks at this while it's below your waist, you get to bop them." + icon_state = "madeyoulook" + force = 0 + throwforce = 0 + flags_1 = DROPDEL_1 | ABSTRACT_1 + attack_verb = list("bopped") + +/obj/item/proc/can_trigger_gun(mob/living/user) + if(!user.can_use_guns(src)) + return FALSE +>>>>>>> bcbc166... chainsaws rebalance, but working this time :) (#30399) return TRUE diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 1f12e671ec..d3b53d3a41 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -308,8 +308,8 @@ name = "Chainsaw" result = /obj/item/twohanded/required/chainsaw reqs = list(/obj/item/circular_saw = 1, - /obj/item/stack/cable_coil = 1, - /obj/item/stack/sheet/plasteel = 1) + /obj/item/stack/cable_coil = 3, + /obj/item/stack/sheet/plasteel = 5) tools = list(/obj/item/weldingtool) time = 50 category = CAT_WEAPONRY From 33f36fd0de5d8dfa880ca0380f3f329ed5da6c9a Mon Sep 17 00:00:00 2001 From: ExcessiveUseOfCobblestone <11748095+ExcessiveUseOfCobblestone@users.noreply.github.com> Date: Fri, 8 Sep 2017 11:01:30 -0400 Subject: [PATCH 012/102] Adds Archaeology Component --- code/__DEFINES/components.dm | 11 ++- code/__DEFINES/is_helpers.dm | 2 + code/datums/components/archaeology.dm | 92 +++++++++++++++++++ code/game/atoms.dm | 5 +- .../mecha/equipment/tools/mining_tools.dm | 4 +- code/game/objects/items.dm | 3 +- code/game/objects/objs.dm | 1 + code/game/objects/structures/lattice.dm | 1 + .../structures/transit_tubes/transit_tube.dm | 1 + .../transit_tubes/transit_tube_pod.dm | 1 + code/game/objects/structures/window.dm | 1 + code/game/turfs/open.dm | 3 + code/game/turfs/simulated/floor.dm | 1 + code/game/turfs/simulated/floor/misc_floor.dm | 1 + .../turfs/simulated/floor/plating/asteroid.dm | 83 +++-------------- .../game/turfs/simulated/floor/reinf_floor.dm | 1 + code/game/turfs/simulated/wall/reinf_walls.dm | 1 + code/game/turfs/simulated/walls.dm | 1 + .../atmospherics/machinery/atmosmachinery.dm | 1 + .../atmospherics/machinery/other/meter.dm | 1 + code/modules/mob/living/carbon/human/human.dm | 2 +- code/modules/mob/living/living.dm | 1 + code/modules/power/cable.dm | 1 + code/modules/recycling/disposal-structures.dm | 1 + code/modules/recycling/disposal-unit.dm | 1 + tgstation.dme | 1 + 26 files changed, 146 insertions(+), 76 deletions(-) create mode 100644 code/datums/components/archaeology.dm diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 0225dad669..37af346a88 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -5,7 +5,7 @@ // How multiple components of the exact same type are handled in the same datum #define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default) -#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed +#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed #define COMPONENT_DUPE_UNIQUE 2 //new component is deleted // All signals. Format: @@ -14,5 +14,14 @@ #define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (datum/component) #define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (datum/component) #define COMSIG_PARENT_QDELETED "parent_qdeleted" //before a datum's Destroy() is called: () +<<<<<<< HEAD #define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable, atom) #define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (atom/movable) +======= +#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from the base of atom/attackby: (obj/item, mob/living, params) +#define COMSIG_PARENT_EXAMINE "atom_examine" //from the base of atom/examine: (mob) +#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable, atom) +#define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target) +#define COMSIG_ATOM_SING_PULL "atom_sing_pull" //from base of atom/singularity_pull(): (S, current_size) +#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (atom/movable) +>>>>>>> 1e17bb7... Adds Archaeology Component (#30220) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 16b2a8f4fb..2c18e51f01 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -25,6 +25,8 @@ #define islava(A) (istype(A, /turf/open/lava)) +#define isplatingturf(A) (istype(A, /turf/open/floor/plating)) + //Mobs #define isliving(A) (istype(A, /mob/living)) diff --git a/code/datums/components/archaeology.dm b/code/datums/components/archaeology.dm new file mode 100644 index 0000000000..22a6b24bc4 --- /dev/null +++ b/code/datums/components/archaeology.dm @@ -0,0 +1,92 @@ +/datum/component/archaeology + dupe_type = COMPONENT_DUPE_UNIQUE + var/list/archdrops + var/prob2drop + var/dug + +/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list()) + prob2drop = Clamp(_prob2drop, 0, 100) + archdrops = _archdrops + RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig) + RegisterSignal(COMSIG_ATOM_EX_ACT, .proc/BombDig) + RegisterSignal(COMSIG_ATOM_SING_PULL, .proc/SingDig) + +/datum/component/archaeology/InheritComponent(datum/component/archaeology/A, i_am_original) + var/list/other_archdrops = A.archdrops + var/list/_archdrops = archdrops + for(var/I in other_archdrops) + _archdrops[I] += other_archdrops[I] + +/datum/component/archaeology/proc/Dig(mob/user, obj/item/W) + if(dug) + to_chat(user, "Looks like someone has dug here already.") + return FALSE + else + var/digging_speed + if (istype(W, /obj/item/shovel)) + var/obj/item/shovel/S = W + digging_speed = S.digspeed + else if (istype(W, /obj/item/pickaxe)) + var/obj/item/pickaxe/P = W + digging_speed = P.digspeed + + if (digging_speed && isturf(user.loc)) + to_chat(user, "You start digging...") + playsound(parent, 'sound/effects/shovel_dig.ogg', 50, 1) + + if(do_after(user, digging_speed, target = parent)) + to_chat(user, "You dig a hole.") + gets_dug() + dug = TRUE + SSblackbox.add_details("pick_used_mining",W.type) + return TRUE + return FALSE + +/datum/component/archaeology/proc/gets_dug() + if(dug) + return + else + var/turf/open/OT = get_turf(parent) + for(var/thing in archdrops) + var/maxtodrop = archdrops[thing] + for(var/i in 1 to maxtodrop) + if(prob(prob2drop)) // can't win them all! + new thing(OT) + + if(isopenturf(OT)) + if(OT.postdig_icon_change) + if(istype(OT, /turf/open/floor/plating/asteroid/) && !OT.postdig_icon) + var/turf/open/floor/plating/asteroid/AOT = parent + AOT.icon_plating = "[AOT.environment_type]_dug" + AOT.icon_state = "[AOT.environment_type]_dug" + else + if(isplatingturf(OT)) + var/turf/open/floor/plating/POT = parent + POT.icon_plating = "[POT.postdig_icon]" + OT.icon_state = "[OT.postdig_icon]" + + if(OT.slowdown) //Things like snow slow you down until you dig them. + OT.slowdown = 0 + dug = TRUE + +/datum/component/archaeology/proc/SingDig(S, current_size) + switch(current_size) + if(STAGE_THREE) + if(prob(30)) + gets_dug() + if(STAGE_FOUR) + if(prob(50)) + gets_dug() + else + if(current_size >= STAGE_FIVE && prob(70)) + gets_dug() + +/datum/component/archaeology/proc/BombDig(severity, target) + switch(severity) + if(3) + return + if(2) + if(prob(20)) + gets_dug() + if(1) + gets_dug() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 77bcefeddf..1e8ef4c5e2 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -304,6 +304,7 @@ /atom/proc/ex_act(severity, target) set waitfor = FALSE contents_explosion(severity, target) + SendSignal(COMSIG_ATOM_EX_ACT, severity, target) /atom/proc/blob_act(obj/structure/blob/B) return @@ -468,8 +469,8 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) /atom/proc/singularity_act() return -/atom/proc/singularity_pull() - return +/atom/proc/singularity_pull(obj/singularity/S, current_size) + SendSignal(COMSIG_ATOM_SING_PULL, S, current_size) /atom/proc/acid_act(acidpwr, acid_volume) return diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index 6d15716941..d0a1310e8e 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -58,7 +58,9 @@ /turf/open/floor/plating/asteroid/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) for(var/turf/open/floor/plating/asteroid/M in range(1, drill.chassis)) if(get_dir(drill.chassis,M)&drill.chassis.dir) - M.gets_dug() + for(var/I in GetComponents(/datum/component/archaeology)) + var/datum/component/archaeology/archy = I + archy.gets_dug() drill.log_message("Drilled through [src]") drill.move_ores() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 96dcba36cf..f640e0f90b 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -549,9 +549,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) transfer_blood = 0 /obj/item/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FOUR) throw_at(S,14,3, spin=0) - else ..() + else return /obj/item/throw_impact(atom/A) if(A && !QDELETED(A)) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 1f3668f283..c8f105dfbe 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -169,6 +169,7 @@ return /obj/singularity_pull(S, current_size) + ..() if(!anchored || current_size >= STAGE_FIVE) step_towards(src,S) diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 8a24b0271f..081cf186a3 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -45,6 +45,7 @@ qdel(src) /obj/structure/lattice/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FOUR) deconstruct() diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm index 7b86cdffcc..10d883d392 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube.dm @@ -30,6 +30,7 @@ return ..() /obj/structure/transit_tube/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct(FALSE) diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index 89f02b13af..b885f980a2 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -62,6 +62,7 @@ AM.ex_act(severity, target) /obj/structure/transit_tube_pod/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct(FALSE) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index e70d5d3ddb..170a651315 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -105,6 +105,7 @@ qdel(src) /obj/structure/window/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct(FALSE) diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 2622a4e74c..f97f79068d 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -4,6 +4,9 @@ var/wet = 0 var/wet_time = 0 // Time in seconds that this floor will be wet for. var/mutable_appearance/wet_overlay + var/postdig_icon_change = FALSE + var/postdig_icon + var/list/archdrops /turf/open/indestructible name = "floor" diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index cfc834037d..df3d2aba86 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -170,6 +170,7 @@ return make_plating() /turf/open/floor/singularity_pull(S, current_size) + ..() if(current_size == STAGE_THREE) if(prob(30)) if(floor_tile) diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index f8d6c1da71..f2475cf997 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -269,6 +269,7 @@ narsie_act(force, ignore_mobs, probability) /turf/open/floor/vines/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) if(prob(50)) ChangeTurf(src.baseturf) diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm index b24b758d73..c6dd8cb2eb 100644 --- a/code/game/turfs/simulated/floor/plating/asteroid.dm +++ b/code/game/turfs/simulated/floor/plating/asteroid.dm @@ -9,11 +9,11 @@ icon = 'icons/turf/floors.dmi' icon_state = "asteroid" icon_plating = "asteroid" + postdig_icon_change = TRUE var/environment_type = "asteroid" var/turf_type = /turf/open/floor/plating/asteroid //Because caves do whacky shit to revert to normal - var/dug = 0 //0 = has not yet been dug, 1 = has already been dug - var/sand_type = /obj/item/ore/glass var/floor_variance = 20 //probability floor has a different icon state + archdrops = list(/obj/item/ore/glass = 5) /turf/open/floor/plating/asteroid/Initialize() var/proper_name = name @@ -22,6 +22,9 @@ if(prob(floor_variance)) icon_state = "[environment_type][rand(0,12)]" + if(LAZYLEN(archdrops)) + AddComponent(/datum/component/archaeology, 100, archdrops) + /turf/open/floor/plating/asteroid/burn_tile() return @@ -31,46 +34,7 @@ /turf/open/floor/plating/asteroid/MakeDry(wet_setting = TURF_WET_WATER) return -/turf/open/floor/plating/asteroid/ex_act(severity, target) - contents_explosion(severity, target) - switch(severity) - if(3) - return - if(2) - if(prob(20)) - src.gets_dug() - if(1) - src.gets_dug() - /turf/open/floor/plating/asteroid/attackby(obj/item/W, mob/user, params) - //note that this proc does not call ..() - if(!W || !user) - return 0 - var/digging_speed = 0 - if (istype(W, /obj/item/shovel)) - var/obj/item/shovel/S = W - digging_speed = S.digspeed - else if (istype(W, /obj/item/pickaxe)) - var/obj/item/pickaxe/P = W - digging_speed = P.digspeed - if (digging_speed) - var/turf/T = user.loc - if(!isturf(T)) - return - - if (dug) - to_chat(user, "This area has already been dug!") - return - - to_chat(user, "You start digging...") - playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) - - if(do_after(user, digging_speed, target = src)) - if(istype(src, /turf/open/floor/plating/asteroid)) - to_chat(user, "You dig a hole.") - gets_dug() - SSblackbox.add_details("pick_used_mining","[W.type]") - if(istype(W, /obj/item/storage/bag/ore)) var/obj/item/storage/bag/ore/S = W if(S.collection_mode == 1) @@ -88,37 +52,16 @@ var/turf/open/floor/light/F = T F.state = L.state playsound(src, 'sound/weapons/genhit.ogg', 50, 1) - -/turf/open/floor/plating/asteroid/proc/gets_dug() - if(dug) return - for(var/i in 1 to 5) - new sand_type(src) - dug = 1 - icon_plating = "[environment_type]_dug" - icon_state = "[environment_type]_dug" - slowdown = 0 - return + + return ..() + /turf/open/floor/plating/asteroid/singularity_act() if(turf_z_is_planet(src)) return ..() ChangeTurf(/turf/open/space) -/turf/open/floor/plating/asteroid/singularity_pull(S, current_size) - if(dug) - return - switch(current_size) - if(STAGE_THREE) - if(!prob(30)) - gets_dug() - if(STAGE_FOUR) - if(prob(50)) - gets_dug() - else - if(current_size >= STAGE_FIVE && prob(70)) - gets_dug() - /turf/open/floor/plating/asteroid/basalt name = "volcanic floor" @@ -127,7 +70,7 @@ icon_state = "basalt" icon_plating = "basalt" environment_type = "basalt" - sand_type = /obj/item/ore/glass/basalt + archdrops = list(/obj/item/ore/glass/basalt = 5) floor_variance = 15 /turf/open/floor/plating/asteroid/basalt/lava //lava underneath @@ -147,10 +90,10 @@ if("basalt5", "basalt9") B.set_light(1.4, 0.6, LIGHT_COLOR_LAVA) //barely anything! -/turf/open/floor/plating/asteroid/basalt/gets_dug() - if(!dug) - set_light(0) +/turf/open/floor/plating/asteroid/basalt/ComponentActivated(datum/component/C) ..() + if(istype(C, /datum/component/archaeology)) + set_light(0) ///////Surface. The surface is warm, but survivable without a suit. Internals are required. The floors break to chasms, which drop you into the underground. @@ -340,8 +283,8 @@ initial_gas_mix = "TEMP=180" slowdown = 2 environment_type = "snow" - sand_type = /obj/item/stack/sheet/mineral/snow flags_1 = NONE + archdrops = list(/obj/item/stack/sheet/mineral/snow = 5) /turf/open/floor/plating/asteroid/snow/airless initial_gas_mix = "TEMP=2.7" diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index df353653d7..eaf0e512f7 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -58,6 +58,7 @@ make_plating(1) /turf/open/floor/engine/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) if(floor_tile) if(prob(30)) diff --git a/code/game/turfs/simulated/wall/reinf_walls.dm b/code/game/turfs/simulated/wall/reinf_walls.dm index 261e856629..5ebe1d632a 100644 --- a/code/game/turfs/simulated/wall/reinf_walls.dm +++ b/code/game/turfs/simulated/wall/reinf_walls.dm @@ -247,6 +247,7 @@ icon_state = "r_wall" /turf/closed/wall/r_wall/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) if(prob(30)) dismantle_wall() diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 57774a5754..9171c7f54c 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -245,6 +245,7 @@ QDEL_IN(O, 50) /turf/closed/wall/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) if(prob(50)) dismantle_wall() diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index e22da2f1b1..977d48fbd7 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -222,6 +222,7 @@ Pipelines + Other Objects -> Pipe network build_network() /obj/machinery/atmospherics/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct(FALSE) diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm index 89f8b8d2cb..b73fd986f8 100644 --- a/code/modules/atmospherics/machinery/other/meter.dm +++ b/code/modules/atmospherics/machinery/other/meter.dm @@ -120,6 +120,7 @@ return 1 /obj/machinery/meter/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) new /obj/item/pipe_meter(loc) qdel(src) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 304a745220..f93b1cc2f1 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -643,6 +643,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) update_hair() /mob/living/carbon/human/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_THREE) for(var/obj/item/hand in held_items) if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && dropItemToGround(hand)) @@ -651,7 +652,6 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) rad_act(current_size * 3) if(mob_negates_gravity()) return - ..() /mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C) CHECK_DNA_AND_SPECIES(C) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 70a8474165..522bf5cf57 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -690,6 +690,7 @@ who.equip_to_slot(what, where, TRUE) /mob/living/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_SIX) throw_at(S,14,3, spin=1) else diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ebe478a7bf..a24c0d7c57 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -170,6 +170,7 @@ By design, d1 is the smallest direction and d2 is the highest return 0 /obj/structure/cable/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct() diff --git a/code/modules/recycling/disposal-structures.dm b/code/modules/recycling/disposal-structures.dm index efe730d1c2..9015320c56 100644 --- a/code/modules/recycling/disposal-structures.dm +++ b/code/modules/recycling/disposal-structures.dm @@ -335,6 +335,7 @@ /obj/structure/disposalpipe/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct() diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm index 14ebec8128..4c82605673 100644 --- a/code/modules/recycling/disposal-unit.dm +++ b/code/modules/recycling/disposal-unit.dm @@ -58,6 +58,7 @@ return ..() /obj/machinery/disposal/singularity_pull(S, current_size) + ..() if(current_size >= STAGE_FIVE) deconstruct() diff --git a/tgstation.dme b/tgstation.dme index df879e0b4d..4ecd700891 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -281,6 +281,7 @@ #include "code\datums\antagonists\datum_traitor.dm" #include "code\datums\antagonists\devil.dm" #include "code\datums\antagonists\ninja.dm" +#include "code\datums\components\archaeology.dm" #include "code\datums\components\component.dm" #include "code\datums\components\slippery.dm" #include "code\datums\diseases\_disease.dm" From 71e87d851c9a943a4d864a219a0d0c715c84ae05 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 8 Sep 2017 11:27:53 -0400 Subject: [PATCH 013/102] Adds Features per Fix tracking --- tools/github_webhook_processor.php | 128 ++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/tools/github_webhook_processor.php b/tools/github_webhook_processor.php index 6113714566..75cb3562b6 100644 --- a/tools/github_webhook_processor.php +++ b/tools/github_webhook_processor.php @@ -23,6 +23,12 @@ //This is required as otherwise somebody could trick the script into leaking the api key. $hookSecret = '08ajh0qj93209qj90jfq932j32r'; +$trackPRBalance = true; //set this to false to disable PR balance tracking +$prBalanceJson = ''; //Set this to the path you'd like the writable pr balance file to be stored, not setting it writes it to the working directory +$startingPRBalance = 3; //Starting balance for never before seen users +//team 133041: tgstation/commit-access +$maintainer_team_id = 133041; //org team id that is exempt from PR balance system, setting this to null will use anyone with write access to the repo. Get from https://api.github.com/orgs/:org/teams + //Api key for pushing changelogs. $apiKey = '209ab8d879c0f987d06a09b9d879c0f987d06a09b9d8787d0a089c'; @@ -168,7 +174,7 @@ function tag_pr($payload, $opened) { if(strpos($lowertitle, '[wip]') !== FALSE) $tags[] = 'Work In Progress'; - $url = $payload['pull_request']['base']['repo']['url'] . '/issues/' . $payload['pull_request']['number'] . '/labels'; + $url = $payload['pull_request']['issue_url'] . '/labels'; $existing_labels = file_get_contents($url, false, stream_context_create($scontext)); $existing_labels = json_decode($existing_labels, true); @@ -195,6 +201,12 @@ function handle_pr($payload) { switch ($payload["action"]) { case 'opened': tag_pr($payload, true); + if(get_pr_code_friendliness($payload) < 0){ + $balances = pr_balances(); + $author = $payload['pull_request']['user']['login']; + if(isset($balances[$author]) && $balances[$author] < 0) + create_comment($payload, 'You currently have a negative Fix/Feature pull request delta of ' . $balances[$author] . '. Maintainers may close this PR at will. Fixing issues or improving the codebase will improve this score.'); + } break; case 'edited': case 'synchronize': @@ -210,6 +222,11 @@ function handle_pr($payload) { else { $action = 'merged'; checkchangelog($payload, true, true); +<<<<<<< HEAD +======= + update_pr_balance($payload); + $validated = TRUE; //pr merged events always get announced. +>>>>>>> af44a7a... Adds Features per Fix tracking (#29897) } break; default: @@ -223,7 +240,116 @@ function handle_pr($payload) { $msg = '['.$payload['pull_request']['base']['repo']['full_name'].'] Pull Request '.$action.' by '.htmlSpecialChars($payload['sender']['login']).': '.htmlSpecialChars('#'.$payload['pull_request']['number'].' '.$payload['pull_request']['user']['login'].' - '.$payload['pull_request']['title']).''; sendtoallservers('?announce='.urlencode($msg), $payload); +} +//creates a comment on the payload issue +function create_comment($payload, $comment){ + apisend($payload['pull_request']['comments_url'], 'POST', json_encode(array('body' => $comment))); +} + +//returns the payload issue's labels as a flat array +function get_pr_labels_array($payload){ + $url = $payload['pull_request']['issue_url'] . '/labels'; + $issue = json_decode(apisend($url), true); + $result = array(); + foreach($issue as $l) + $result[] = $l['name']; + return $result; +} + +//helper for getting the path the the balance json file +function pr_balance_json_path(){ + global $prBalanceJson; + return $prBalanceJson != '' ? $prBalanceJson : 'pr_balances.json'; +} + +//return the assoc array of login -> balance for prs +function pr_balances(){ + $path = pr_balance_json_path(); + if(file_exists($path)) + return json_decode(file_get_contents($path), true); + else + return array(); +} + +//returns the difference in PR balance a pull request would cause +function get_pr_code_friendliness($payload, $oldbalance = null){ + global $startingPRBalance; + if($oldbalance == null) + $oldbalance = $startingPRBalance; + $labels = get_pr_labels_array($payload); + //anything not in this list defaults to 0 + $label_values = array( + 'Fix' => 2, + 'Refactor' => 2, + 'Code Improvement' => 1, + 'Priority: High' => 4, + 'Priority: CRITICAL' => 5, + 'Atmospherics' => 4, + 'Logging' => 1, + 'Feedback' => 1, + 'Performance' => 3, + 'Feature' => -1, + 'Balance/Rebalance' => -1, + 'Tweak' => -1, + 'PRB: Reset' => $startingPRBalance - $oldbalance, + ); + + $affecting = 0; + $is_neutral = FALSE; + $found_something_positive = false; + foreach($labels as $l){ + if($l == 'PRB: No Update') { //no effect on balance + $affecting = 0; + break; + } + else if(isset($label_values[$l])) { + $friendliness = $label_values[$l]; + if($friendliness > 0) + $found_something_positive = true; + $affecting = $found_something_positive ? max($affecting, $friendliness) : $friendliness; + } + } + return $affecting; +} + +function is_maintainer($payload, $author){ + global $maintainer_team_id; + $repo_is_org = $payload['pull_request']['base']['repo']['owner']['type'] == 'Organization'; + if($maintainer_team_id == null || !$repo_is_org) { + $collaburl = $payload['pull_request']['base']['repo']['collaborators_url'] . '/' . $author . '/permissions'; + $perms = json_decode(apisend($collaburl), true); + $permlevel = $perms['permission']; + return $permlevel == 'admin' || $permlevel == 'write'; + } + else { + $check_url = 'https://api.github.com/teams/' . $maintainer_team_id . '/memberships/' . $author; + $result = json_decode(apisend($check_url), true); + return isset($result['state']); //this field won't be here if they aren't a member + } +} + +//payload is a merged pull request, updates the pr balances file with the correct positive or negative balance based on comments +function update_pr_balance($payload) { + global $startingPRBalance; + global $trackPRBalance; + if(!$trackPRBalance) + return; + $author = $payload['pull_request']['user']['login']; + if(is_maintainer($payload, $author)) //immune + return; + $balances = pr_balances(); + if(!isset($balances[$author])) + $balances[$author] = $startingPRBalance; + $friendliness = get_pr_code_friendliness($payload, $balances[$author]); + $balances[$author] += $friendliness; + if($balances[$author] < 0 && $friendliness < 0) + create_comment($payload, 'Your Fix/Feature pull request delta is currently below zero (' . $balances[$author] . '). Maintainers may close future Feature/Tweak/Balance PRs. Fixing issues or helping to improve the codebase will raise this score.'); + else if($balances[$author] >= 0 && ($balances[$author] - $friendliness) < 0) + create_comment($payload, 'Your Fix/Feature pull request delta is now above zero (' . $balances[$author] . '). Feel free to make Feature/Tweak/Balance PRs.'); + $balances_file = fopen(pr_balance_json_path(), 'w'); + fwrite($balances_file, json_encode($balances)); + fclose($balances_file); } function has_tree_been_edited($payload, $tree){ From 770c6a8e5449b9bc5bf8e6716de32b10efcb43f5 Mon Sep 17 00:00:00 2001 From: Lexorion Date: Sat, 9 Sep 2017 03:52:35 +0200 Subject: [PATCH 014/102] New blackbox sprites (#30242) * New blackbox sprites * Changes the blackbox sprite again --- icons/obj/stationobjs.dmi | Bin 56174 -> 58072 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi index 28dd158ff78d6a0992bce25ffdb91cf9c604d449..0f4cda5d8bf11c5a952d56492728c4c463c82224 100644 GIT binary patch delta 15857 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 Date: Fri, 8 Sep 2017 22:15:53 -0400 Subject: [PATCH 016/102] [s] Adds a security token to all admin hrefs --- code/__DEFINES/admin.dm | 77 +++ code/controllers/configuration.dm | 4 + code/controllers/subsystem/events.dm | 4 +- code/datums/datumvars.dm | 493 ++++++++++++++++++ code/game/atoms.dm | 8 +- code/game/atoms_movable.dm | 2 +- code/game/objects/objs.dm | 2 +- code/modules/admin/DB_ban/functions.dm | 12 +- code/modules/admin/admin.dm | 258 +++++---- code/modules/admin/create_mob.dm | 28 + code/modules/admin/create_object.dm | 31 +- code/modules/admin/create_turf.dm | 12 + code/modules/admin/holder2.dm | 128 +++++ .../admin/permissionverbs/permissionedit.dm | 10 +- code/modules/admin/player_panel.dm | 144 ++--- code/modules/admin/secrets.dm | 80 ++- code/modules/admin/sql_message_system.dm | 49 +- code/modules/admin/stickyban.dm | 10 +- code/modules/admin/topic.dm | 17 + code/modules/admin/verbs/SDQL2/SDQL_2.dm | 2 +- code/modules/admin/verbs/adminhelp.dm | 18 +- code/modules/admin/verbs/adminsay.dm | 2 +- .../modules/admin/verbs/individual_logging.dm | 12 +- code/modules/admin/verbs/one_click_antag.dm | 14 + code/modules/admin/verbs/randomverbs.dm | 8 +- code/modules/error_handler/error_viewer.dm | 12 +- code/modules/events/spacevine.dm | 4 +- code/modules/mob/living/carbon/carbon.dm | 8 +- code/modules/mob/living/carbon/human/human.dm | 12 +- code/modules/mob/mob.dm | 24 +- code/modules/station_goals/station_goal.dm | 2 +- config/config.txt | 6 + 32 files changed, 1166 insertions(+), 327 deletions(-) diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 26a1535e33..00d81fe7c7 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD //A set of constants used to determine which type of mute an admin wishes to apply: //Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) //Therefore there needs to be a gap between the flags_1 for the automute flags_1 @@ -72,3 +73,79 @@ #define AHELP_ACTIVE 1 #define AHELP_CLOSED 2 #define AHELP_RESOLVED 3 +======= +//A set of constants used to determine which type of mute an admin wishes to apply: +//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) +//Therefore there needs to be a gap between the flags for the automute flags +#define MUTE_IC 1 +#define MUTE_OOC 2 +#define MUTE_PRAY 4 +#define MUTE_ADMINHELP 8 +#define MUTE_DEADCHAT 16 +#define MUTE_ALL 31 + +//Some constants for DB_Ban +#define BANTYPE_PERMA 1 +#define BANTYPE_TEMP 2 +#define BANTYPE_JOB_PERMA 3 +#define BANTYPE_JOB_TEMP 4 +#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban. + +#define BANTYPE_ADMIN_PERMA 7 +#define BANTYPE_ADMIN_TEMP 8 +#define BANTYPE_ANY_JOB 9 //used to remove jobbans + +//Please don't edit these values without speaking to Errorage first ~Carn +//Admin Permissions +#define R_BUILDMODE 1 +#define R_ADMIN 2 +#define R_BAN 4 +#define R_FUN 8 +#define R_SERVER 16 +#define R_DEBUG 32 +#define R_POSSESS 64 +#define R_PERMISSIONS 128 +#define R_STEALTH 256 +#define R_POLL 512 +#define R_VAREDIT 1024 +#define R_SOUNDS 2048 +#define R_SPAWN 4096 + +#if DM_VERSION > 512 +#error Remove the flag below , its been long enough +#endif +//legacy , remove post 512, it was replaced by R_POLL +#define R_REJUVINATE 2 + +#define R_MAXPERMISSION 4096 //This holds the maximum value for a permission. It is used in iteration, so keep it updated. + +#define ADMIN_QUE(user) "(?)" +#define ADMIN_FLW(user) "(FLW)" +#define ADMIN_PP(user) "(PP)" +#define ADMIN_VV(atom) "(VV)" +#define ADMIN_SM(user) "(SM)" +#define ADMIN_TP(user) "(TP)" +#define ADMIN_KICK(user) "(KICK)" +#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" +#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" +#define ADMIN_SC(user) "(SC)" +#define ADMIN_SMITE(user) "(SMITE)" +#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" +#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" +#define ADMIN_SET_SD_CODE "(SETCODE)" +#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" +#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" +#define ADMIN_JMP(src) "(JMP)" +#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" +#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" +#define ADMIN_INDIVIDUALLOG(user) "(LOGS)" + +#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt" +#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage" +#define ADMIN_PUNISHMENT_GIB "Gib" +#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device" + +#define AHELP_ACTIVE 1 +#define AHELP_CLOSED 2 +#define AHELP_RESOLVED 3 +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 1d853c332b..e430ecb337 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -278,6 +278,8 @@ GLOBAL_PROTECT(config_dir) var/list/policies = list() + var/debug_admin_hrefs = FALSE //turns off admin href token protection for debugging purposes + /datum/configuration/New() gamemode_cache = typecacheof(/datum/game_mode,TRUE) for(var/T in gamemode_cache) @@ -559,6 +561,8 @@ GLOBAL_PROTECT(config_dir) error_msg_delay = text2num(value) if("irc_announce_new_game") irc_announce_new_game = TRUE + if("debug_admin_hrefs") + debug_admin_hrefs = TRUE else #if DM_VERSION > 511 #error Replace the line below with WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'") diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index c41f422575..7816a6bdf8 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -116,6 +116,8 @@ SUBSYSTEM_DEF(events) //allows a client to trigger an event //aka Badmin Central +// > Not in modules/admin +// REEEEEEEEE /client/proc/forceEvent() set name = "Trigger Event" set category = "Fun" @@ -131,7 +133,7 @@ SUBSYSTEM_DEF(events) var/magic = "" var/holiday = "" for(var/datum/round_event_control/E in SSevents.control) - dat = "
    [E]" + dat = "
    [E]" if(E.holidayID) holiday += dat else if(E.wizardevent) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 87c6ad7334..44661316ab 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -22,6 +22,7 @@ //please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down //add separaters by doing . += "---" +<<<<<<< HEAD /datum/proc/vv_get_dropdown() . = list() . += "---" @@ -62,6 +63,49 @@ +======= +/datum/proc/vv_get_dropdown() + . = list() + . += "---" + .["Call Proc"] = "?_src_=vars;[HrefToken()];proc_call=\ref[src]" + .["Mark Object"] = "?_src_=vars;[HrefToken()];mark_object=\ref[src]" + .["Delete"] = "?_src_=vars;[HrefToken()];delete=\ref[src]" + .["Show VV To Player"] = "?_src_=vars;[HrefToken(TRUE)];expose=\ref[src]" + + +/datum/proc/on_reagent_change() + return + + +/client/proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + //set src in world + var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. + + if(!usr.client || !usr.client.holder) //The usr vs src abuse in this proc is intentional and must not be changed + to_chat(usr, "You need to be an administrator to access this.") + return + + if(!D) + return + + var/islist = islist(D) + if (!islist && !istype(D)) + return + + var/title = "" + var/refid = "\ref[D]" + var/icon/sprite + var/hash + + var/type = /list + if (!islist) + type = D.type + + + +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) if(istype(D, /atom)) var/atom/AT = D if(AT.icon && AT.icon_state) @@ -78,6 +122,7 @@ var/list/atomsnowflake = list() if(istype(D, /atom)) +<<<<<<< HEAD var/atom/A = D if(isliving(A)) atomsnowflake += "[D]" @@ -485,6 +530,415 @@ if(!check_rights(0)) return +======= + var/atom/A = D + if(isliving(A)) + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
    << [dir2text(A.dir)] >>" + var/mob/living/M = A + atomsnowflake += {" +
    [M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"] +
    + BRUTE:[M.getBruteLoss()] + FIRE:[M.getFireLoss()] + TOXIN:[M.getToxLoss()] + OXY:[M.getOxyLoss()] + CLONE:[M.getCloneLoss()] + BRAIN:[M.getBrainLoss()] + STAMINA:[M.getStaminaLoss()] + + "} + else + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
    << [dir2text(A.dir)] >>" + else + atomsnowflake += "[D]" + + var/formatted_type = "[type]" + if(length(formatted_type) > 25) + var/middle_point = length(formatted_type) / 2 + var/splitpoint = findtext(formatted_type,"/",middle_point) + if(splitpoint) + formatted_type = "[copytext(formatted_type,1,splitpoint)]
    [copytext(formatted_type,splitpoint)]" + else + formatted_type = "Type too long" //No suitable splitpoint (/) found. + + var/marked + if(holder && holder.marked_datum && holder.marked_datum == D) + marked = "
    Marked Object" + var/varedited_line = "" + if(!islist && D.var_edited) + varedited_line = "
    Var Edited" + + var/list/dropdownoptions = list() + if (islist) + dropdownoptions = list( + "---", + "Add Item" = "?_src_=vars;[HrefToken()];listadd=[refid]", + "Remove Nulls" = "?_src_=vars;[HrefToken()];listnulls=[refid]", + "Remove Dupes" = "?_src_=vars;[HrefToken()];listdupes=[refid]", + "Set len" = "?_src_=vars;[HrefToken()];listlen=[refid]", + "Shuffle" = "?_src_=vars;[HrefToken()];listshuffle=[refid]", + "Show VV To Player" = "?_src_=vars;[HrefToken()];expose=[refid]" + ) + else + dropdownoptions = D.vv_get_dropdown() + var/list/dropdownoptions_html = list() + + for (var/name in dropdownoptions) + var/link = dropdownoptions[name] + if (link) + dropdownoptions_html += "" + else + dropdownoptions_html += "" + + var/list/names = list() + if (!islist) + for (var/V in D.vars) + names += V + sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. + + var/list/variable_html = list() + if (islist) + var/list/L = D + for (var/i in 1 to L.len) + var/key = L[i] + var/value + if (IS_NORMAL_LIST(L) && !isnum(key)) + value = L[key] + variable_html += debug_variable(i, value, 0, D) + else + + names = sortList(names) + for (var/V in names) + if(D.can_vv_get(V)) + variable_html += D.vv_get_var(V) + + var/html = {" + + + [title] + + + + +
    + + + + + +
    + + + + +
    + [sprite_text] +
    + [atomsnowflake.Join()] +
    +
    +
    + [formatted_type] + [marked] + [varedited_line] +
    +
    +
    + Refresh +
    + +
    +
    +
    +
    +
    + + E - Edit, tries to determine the variable type by itself.
    + C - Change, asks you for the var type first.
    + M - Mass modify: changes this variable for all objects of this type.
    +
    +
    + + + + + +
    +
    + Search: +
    +
    + +
    +
    +
      + [variable_html.Join()] +
    + + + +"} + src << browse(html, "window=variables[refid];size=475x650") + + +#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) +/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) + var/header + if(DA) + if (islist(DA)) + var/index = name + if (value) + name = DA[name] //name is really the index until this line + else + value = DA[name] + header = "
  • (E) (C) (-) " + else + header = "
  • (E) (C) (M) " + else + header = "
  • " + + var/item + if (isnull(value)) + item = "[VV_HTML_ENCODE(name)] = null" + + else if (istext(value)) + item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" + + else if (isicon(value)) + #ifdef VARSICON + var/icon/I = new/icon(value) + var/rnd = rand(1,10000) + var/rname = "tmp\ref[I][rnd].png" + usr << browse_rsc(I, rname) + item = "[VV_HTML_ENCODE(name)] = ([value]) " + #else + item = "[VV_HTML_ENCODE(name)] = /icon ([value])" + #endif + +/* else if (istype(value, /image)) + #ifdef VARSICON + var/rnd = rand(1, 10000) + var/image/I = value + + src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") + html += "[name] = " + #else + html += "[name] = /image ([value])" + #endif +*/ + else if (isfile(value)) + item = "[VV_HTML_ENCODE(name)] = '[value]'" + + //else if (istype(value, /client)) + // var/client/C = value + // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" + + else if (istype(value, /datum)) + var/datum/D = value + if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" + else + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" + + else if (islist(value)) + var/list/L = value + var/list/items = list() + + if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) + for (var/i in 1 to L.len) + var/key = L[i] + var/val + if (IS_NORMAL_LIST(L) && !isnum(key)) + val = L[key] + if (!val) + val = key + key = i + + items += debug_variable(key, val, level + 1, sanitize = sanitize) + + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " + else + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + + else + item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" + + return "[header][item]
  • " + +#undef VV_HTML_ENCODE + +/client/proc/view_var_Topic(href, href_list, hsrc) + if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list)) + return + if(href_list["Vars"]) + debug_variables(locate(href_list["Vars"])) + + else if(href_list["datumrefresh"]) + var/datum/DAT = locate(href_list["datumrefresh"]) + if(!DAT) //can't be an istype() because /client etc aren't datums + return + src.debug_variables(DAT) + + else if(href_list["mob_player_panel"]) + if(!check_rights(0)) + return + +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) var/mob/M = locate(href_list["mob_player_panel"]) in GLOB.mob_list if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob") @@ -541,6 +995,7 @@ return var/mob/M = locate(href_list["regenerateicons"]) in GLOB.mob_list +<<<<<<< HEAD if(!ismob(M)) to_chat(usr, "This can only be done to instances of type /mob") return @@ -557,6 +1012,44 @@ if(!check_rights(0)) return +======= + if(!ismob(M)) + to_chat(usr, "This can only be done to instances of type /mob") + return + M.regenerate_icons() + else if(href_list["expose"]) + if(!check_rights(R_ADMIN, FALSE)) + return + var/thing = locate(href_list["expose"]) + if (!thing) + return + var/value = vv_get_value(VV_CLIENT) + if (value["class"] != VV_CLIENT) + return + var/client/C = value["value"] + if (!C) + return + var/prompt = alert("Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anything nor open nested vv windows unless they themselves are an admin)", "Confirm", "Yes", "No") + if (prompt != "Yes" || !usr.client) + return + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") + log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [thing]") + to_chat(C, "[usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") + C.debug_variables(thing) + + +//Needs +VAREDIT past this point + + else if(check_rights(R_VAREDIT)) + + + //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). + + if(href_list["rename"]) + if(!check_rights(0)) + return + +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) var/mob/M = locate(href_list["rename"]) in GLOB.mob_list if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob") diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 77bcefeddf..049d9bf838 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -613,10 +613,10 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) . += "---" var/turf/curturf = get_turf(src) if (curturf) - .["Jump to"] = "?_src_=holder;adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" - .["Add reagent"] = "?_src_=vars;addreagent=\ref[src]" - .["Trigger EM pulse"] = "?_src_=vars;emp=\ref[src]" - .["Trigger explosion"] = "?_src_=vars;explode=\ref[src]" + .["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" + .["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=\ref[src]" + .["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=\ref[src]" + .["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=\ref[src]" /atom/proc/drop_location() var/atom/L = loc diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index f4cbcda098..e8c30f1fcc 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -497,7 +497,7 @@ /atom/movable/vv_get_dropdown() . = ..() . -= "Jump to" - .["Follow"] = "?_src_=holder;adminplayerobservefollow=\ref[src]" + .["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=\ref[src]" /atom/movable/proc/ex_check(ex_id) if(!ex_id) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 1f3668f283..568921cfbf 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -198,7 +198,7 @@ /obj/vv_get_dropdown() . = ..() - .["Delete all of type"] = "?_src_=vars;delall=\ref[src]" + .["Delete all of type"] = "?_src_=vars;[HrefToken()];delall=\ref[src]" /obj/examine(mob/user) ..() diff --git a/code/modules/admin/DB_ban/functions.dm b/code/modules/admin/DB_ban/functions.dm index e580b306b3..c6f44fd1da 100644 --- a/code/modules/admin/DB_ban/functions.dm +++ b/code/modules/admin/DB_ban/functions.dm @@ -414,7 +414,7 @@ if(bancount > bansperpage) output += "
    Page: " while(bancount > 0) - output+= "|[pagecount == page ? "\[[pagecount]\]" : "\[[pagecount]\]"]" + output+= "|[pagecount == page ? "\[[pagecount]\]" : "\[[pagecount]\]"]" bancount -= bansperpage pagecount++ output += "|" @@ -462,25 +462,25 @@ if("PERMABAN") typedesc = "PERMABAN" if("TEMPBAN") - typedesc = "TEMPBAN
    ([duration] minutes [(unbanned) ? "" : "(Edit))"]
    Expires [expiration]
    " + typedesc = "TEMPBAN
    ([duration] minutes [(unbanned) ? "" : "(Edit))"]
    Expires [expiration]
    " if("JOB_PERMABAN") typedesc = "JOBBAN
    ([job])" if("JOB_TEMPBAN") - typedesc = "TEMP JOBBAN
    ([job])
    ([duration] minutes [(unbanned) ? "" : "(Edit))"]
    Expires [expiration]" + typedesc = "TEMP JOBBAN
    ([job])
    ([duration] minutes [(unbanned) ? "" : "(Edit))"]
    Expires [expiration]" if("ADMIN_PERMABAN") typedesc = "ADMIN PERMABAN" if("ADMIN_TEMPBAN") - typedesc = "ADMIN TEMPBAN
    ([duration] minutes [(unbanned) ? "" : "(Edit))"]
    Expires [expiration]
    " + typedesc = "ADMIN TEMPBAN
    ([duration] minutes [(unbanned) ? "" : "(Edit))"]
    Expires [expiration]
    " output += "" output += "[typedesc]" output += "[ckey]" output += "[bantime]" output += "[ackey]" - output += "[(unbanned) ? "" : "Unban"]" + output += "[(unbanned) ? "" : "Unban"]" output += "" output += "" - output += "Reason: [(unbanned) ? "" : "(Edit)"] \"[reason]\"" + output += "Reason: [(unbanned) ? "" : "(Edit)"] \"[reason]\"" output += "" if(edits) output += "" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index b88451b724..392d361773 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -30,68 +30,68 @@ body += "Options panel for [M]" if(M.client) body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" if(config.use_exp_tracking) - body += "\[" + M.client.get_exp_living() + "\]" + body += "\[" + M.client.get_exp_living() + "\]" if(isnewplayer(M)) body += " Hasn't Entered Game " else - body += " \[Heal\] " + body += " \[Heal\] " if(M.client) body += "
    \[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]" body += "

    Show related accounts by: " - body += "\[ CID | " - body += "IP \]" + body += "\[ CID | " + body += "IP \]" body += "

    \[ " - body += "VV - " - body += "TP - " + body += "VV - " + body += "TP - " body += "PM - " - body += "SM - " - body += "FLW - " - body += "LOGS\]
    " + body += "SM - " + body += "FLW - " + body += "LOGS\]
    " body += "Mob type = [M.type]

    " - body += "Kick | " - body += "Ban | " - body += "Jobban | " - body += "Identity Ban | " + body += "Kick | " + body += "Ban | " + body += "Jobban | " + body += "Identity Ban | " if(jobban_isbanned(M, "OOC")) - body+= "OOCBan | " + body+= "OOCBan | " else - body+= "OOCBan | " + body+= "OOCBan | " if(jobban_isbanned(M, "emote")) - body+= "EmoteBan | " + body+= "EmoteBan | " else - body+= "Emoteban | " + body+= "Emoteban | " - body += "Notes | Messages | Watchlist | " + body += "Notes | Messages | Watchlist | " if(M.client) - body += "| Prison | " - body += "\ Send back to Lobby | " + body += "| Prison | " + body += "\ Send back to Lobby | " var/muted = M.client.prefs.muted body += "
    Mute: " - body += "\[IC | " - body += "OOC | " - body += "PRAY | " - body += "ADMINHELP | " - body += "DEADCHAT\]" - body += "(toggle all)" + body += "\[IC | " + body += "OOC | " + body += "PRAY | " + body += "ADMINHELP | " + body += "DEADCHAT\]" + body += "(toggle all)" body += "

    " - body += "Jump to | " - body += "Get | " - body += "Send To" + body += "Jump to | " + body += "Get | " + body += "Send To" body += "

    " - body += "Traitor panel | " - body += "Narrate to | " - body += "Subtle message | " - body += "Language Menu" + body += "Traitor panel | " + body += "Narrate to | " + body += "Subtle message | " + body += "Language Menu" if (M.client) if(!isnewplayer(M)) @@ -103,73 +103,71 @@ if(ishuman(M)) body += "Human | " else - body += "Humanize | " + body += "Humanize | " //Monkey if(ismonkey(M)) body += "Monkeyized | " else - body += "Monkeyize | " + body += "Monkeyize | " //Corgi if(iscorgi(M)) body += "Corgized | " else - body += "Corgize | " + body += "Corgize | " //AI / Cyborg if(isAI(M)) body += "Is an AI " else if(ishuman(M)) - body += "Make AI | " - body += "Make Robot | " - body += "Make Alien | " - body += "Make Slime | " - body += "Make Blob | " + body += "Make AI | " + body += "Make Robot | " + body += "Make Alien | " + body += "Make Slime | " + body += "Make Blob | " //Simple Animals if(isanimal(M)) - body += "Re-Animalize | " + body += "Re-Animalize | " else - body += "Animalize | " + body += "Animalize | " body += "

    " body += "Rudimentary transformation:
    These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

    " - body += "Observer | " - body += "\[ Alien: Drone, " - body += "Hunter, " - body += "Sentinel, " - body += "Praetorian, " - body += "Queen, " - body += "Larva \] " - body += "Human " - body += "\[ slime: Baby, " - body += "Adult \] " - body += "Monkey | " - body += "Cyborg | " - body += "Cat | " - body += "Runtime | " - body += "Corgi | " - body += "Ian | " - body += "Crab | " - body += "Coffee | " - //body += "Parrot | " - //body += "Poly | " - body += "\[ Construct: Juggernaut , " - body += "Artificer , " - body += "Wraith \] " - body += "Shade" + body += "Observer | " + body += "\[ Alien: Drone, " + body += "Hunter, " + body += "Sentinel, " + body += "Praetorian, " + body += "Queen, " + body += "Larva \] " + body += "Human " + body += "\[ slime: Baby, " + body += "Adult \] " + body += "Monkey | " + body += "Cyborg | " + body += "Cat | " + body += "Runtime | " + body += "Corgi | " + body += "Ian | " + body += "Crab | " + body += "Coffee | " + body += "\[ Construct: Juggernaut , " + body += "Artificer , " + body += "Wraith \] " + body += "Shade" body += "
    " if (M.client) body += "

    " body += "Other actions:" body += "
    " - body += "Forcesay | " - body += "Thunderdome 1 | " - body += "Thunderdome 2 | " - body += "Thunderdome Admin | " - body += "Thunderdome Observer | " + body += "Forcesay | " + body += "Thunderdome 1 | " + body += "Thunderdome 2 | " + body += "Thunderdome Admin | " + body += "Thunderdome Observer | " body += "
    " body += "" @@ -197,19 +195,19 @@ dat += "
    Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units." dat += "
    Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!
    " if(GLOB.news_network.wanted_issue.active) - dat+= "
    Read Wanted Issue" - dat+= "

    Create Feed Channel" - dat+= "
    View Feed Channels" - dat+= "
    Submit new Feed story" - dat+= "

    Exit" + dat+= "
    Read Wanted Issue" + dat+= "

    Create Feed Channel" + dat+= "
    View Feed Channels" + dat+= "
    Submit new Feed story" + dat+= "

    Exit" var/wanted_already = 0 if(GLOB.news_network.wanted_issue.active) wanted_already = 1 dat+="
    Feed Security functions:
    " - dat+="
    [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" - dat+="
    Censor Feed Stories" - dat+="
    Mark Feed Channel with Nanotrasen D-Notice (disables and locks the channel)." - dat+="

    The newscaster recognises you as:
    [src.admin_signature]
    " + dat+="
    [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" + dat+="
    Censor Feed Stories" + dat+="
    Mark Feed Channel with Nanotrasen D-Notice (disables and locks the channel)." + dat+="

    The newscaster recognises you as:
    [src.admin_signature]
    " if(1) dat+= "Station Feed Channels
    " if( isemptylist(GLOB.news_network.network_channels) ) @@ -219,34 +217,34 @@ if(CHANNEL.is_admin_channel) dat+="[CHANNEL.channel_name]
    " else - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
    " - dat+="

    Refresh" - dat+="
    Back" + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
    " + dat+="

    Refresh" + dat+="
    Back" if(2) dat+="Creating new Feed Channel..." - dat+="
    Channel Name: [src.admincaster_feed_channel.channel_name]
    " - dat+="Channel Author: [src.admin_signature]
    " - dat+="Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

    " - dat+="
    Submit

    Cancel
    " + dat+="
    Channel Name: [src.admincaster_feed_channel.channel_name]
    " + dat+="Channel Author: [src.admin_signature]
    " + dat+="Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

    " + dat+="
    Submit

    Cancel
    " if(3) dat+="Creating new Feed Message..." - dat+="
    Receiving Channel: [src.admincaster_feed_channel.channel_name]
    " //MARK + dat+="
    Receiving Channel: [src.admincaster_feed_channel.channel_name]
    " //MARK dat+="Message Author: [src.admin_signature]
    " - dat+="Message Body: [src.admincaster_feed_message.returnBody(-1)]
    " - dat+="
    Submit

    Cancel
    " + dat+="Message Body: [src.admincaster_feed_message.returnBody(-1)]
    " + dat+="
    Submit

    Cancel
    " if(4) dat+="Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].

    " - dat+="
    Return
    " + dat+="
    Return
    " if(5) dat+="Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.

    " - dat+="
    Return
    " + dat+="
    Return
    " if(6) dat+="ERROR: Could not submit Feed story to Network.

    " if(src.admincaster_feed_channel.channel_name=="") dat+="•Invalid receiving channel name.
    " if(src.admincaster_feed_message.returnBody(-1) == "" || src.admincaster_feed_message.returnBody(-1) == "\[REDACTED\]") dat+="•Invalid message body.
    " - dat+="
    Return
    " + dat+="
    Return
    " if(7) dat+="ERROR: Could not submit Feed Channel to Network.

    " if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]") @@ -258,7 +256,7 @@ break if(check) dat+="•Channel name already in use.
    " - dat+="
    Return
    " + dat+="
    Return
    " if(9) dat+="[admincaster_feed_channel.channel_name]: \[created by: [admincaster_feed_channel.returnAuthor(-1)]\]
    " if(src.admincaster_feed_channel.censored) @@ -280,8 +278,8 @@ for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments) dat+="[comment.body]
    [comment.author] [comment.time_stamp]
    " dat+="
    " - dat+="

    Refresh" - dat+="
    Back" + dat+="

    Refresh" + dat+="
    Back" if(10) dat+="Nanotrasen Feed Censorship Tool
    " dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
    " @@ -291,8 +289,8 @@ dat+="No feed channels found active...
    " else for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
    " - dat+="
    Cancel" + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
    " + dat+="
    Cancel" if(11) dat+="Nanotrasen D-Notice Handler
    " dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" @@ -302,26 +300,26 @@ dat+="No feed channels found active...
    " else for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
    " + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
    " - dat+="
    Back" + dat+="
    Back" if(12) dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
    " - dat+="[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]
    " + dat+="[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]
    " if( isemptylist(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
    " else for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) dat+="-[MESSAGE.returnBody(-1)]
    \[Story by [MESSAGE.returnAuthor(-1)]\]
    " - dat+="[(MESSAGE.bodyCensor) ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.authorCensor) ? ("Undo Author Censorship") : ("Censor message Author")]
    " - dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]: [MESSAGE.locked ? "Unlock" : "Lock"]
    " + dat+="[(MESSAGE.bodyCensor) ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.authorCensor) ? ("Undo Author Censorship") : ("Censor message Author")]
    " + dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]: [MESSAGE.locked ? "Unlock" : "Lock"]
    " for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments) - dat+="[comment.body] X
    [comment.author] [comment.time_stamp]
    " - dat+="
    Back" + dat+="[comment.body] X
    [comment.author] [comment.time_stamp]
    " + dat+="
    Back" if(13) dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
    " - dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
    " + dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
    " if(src.admincaster_feed_channel.censored) dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
    " dat+="No further feed story additions are allowed while the D-Notice is in effect.


    " @@ -331,7 +329,7 @@ else for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) dat+="-[MESSAGE.returnBody(-1)]
    \[Story by [MESSAGE.returnAuthor(-1)]\]
    " - dat+="
    Back" + dat+="
    Back" if(14) dat+="Wanted Issue Handler:" var/wanted_already = 0 @@ -342,29 +340,29 @@ if(wanted_already) dat+="
    A wanted issue is already in Feed Circulation. You can edit or cancel it below.
    " dat+="
    " - dat+="Criminal Name: [src.admincaster_wanted_message.criminal]
    " - dat+="Description: [src.admincaster_wanted_message.body]
    " + dat+="Criminal Name: [src.admincaster_wanted_message.criminal]
    " + dat+="Description: [src.admincaster_wanted_message.body]
    " if(wanted_already) dat+="Wanted Issue created by:[GLOB.news_network.wanted_issue.scannedUser]
    " else dat+="Wanted Issue will be created under prosecutor:[src.admin_signature]
    " - dat+="
    [(wanted_already) ? ("Edit Issue") : ("Submit")]" + dat+="
    [(wanted_already) ? ("Edit Issue") : ("Submit")]" if(wanted_already) - dat+="
    Take down Issue" - dat+="
    Cancel" + dat+="
    Take down Issue" + dat+="
    Cancel" if(15) dat+="Wanted issue for [src.admincaster_wanted_message.criminal] is now in Network Circulation.

    " - dat+="
    Return
    " + dat+="
    Return
    " if(16) dat+="ERROR: Wanted Issue rejected by Network.

    " if(src.admincaster_wanted_message.criminal =="" || src.admincaster_wanted_message.criminal == "\[REDACTED\]") dat+="•Invalid name for person wanted.
    " if(src.admincaster_wanted_message.body == "" || src.admincaster_wanted_message.body == "\[REDACTED\]") dat+="•Invalid description.
    " - dat+="
    Return
    " + dat+="
    Return
    " if(17) dat+="Wanted Issue successfully deleted from Circulation
    " - dat+="
    Return
    " + dat+="
    Return
    " if(18) dat+="-- STATIONWIDE WANTED ISSUE --
    \[Submitted by: [GLOB.news_network.wanted_issue.scannedUser]\]
    " dat+="Criminal: [GLOB.news_network.wanted_issue.criminal]
    " @@ -375,10 +373,10 @@ dat+="
    " else dat+="None" - dat+="
    Back
    " + dat+="
    Back
    " if(19) dat+="Wanted issue for [src.admincaster_wanted_message.criminal] successfully edited.

    " - dat+="
    Return
    " + dat+="
    Return
    " else dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" @@ -394,21 +392,21 @@ var/dat = {"
    Game Panel

    \n - Change Game Mode
    + Change Game Mode
    "} if(GLOB.master_mode == "secret") - dat += "(Force Secret Mode)
    " + dat += "(Force Secret Mode)
    " dat += {"
    - Create Object
    - Quick Create Object
    - Create Turf
    - Create Mob
    + Create Object
    + Quick Create Object
    + Create Turf
    + Create Mob
    "} if(marked_datum && istype(marked_datum, /atom)) - dat += "Duplicate Marked Datum
    " + dat += "Duplicate Marked Datum
    " usr << browse(dat, "window=admin2;size=210x200") return @@ -755,14 +753,14 @@ dat += " (Cannot Late Join)
    " continue if(job.total_positions >= 0) - dat += " Add | " + dat += " Add | " if(job.total_positions > job.current_positions) - dat += "Remove | " + dat += "Remove | " else dat += "Remove | " - dat += "Unlimit" + dat += "Unlimit" else - dat += " Limit" + dat += " Limit" dat += "
    " dat += "" diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index cf0d4be37f..7bfd7ec80a 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /datum/admins/proc/create_mob(mob/user) var/static/create_mob_html @@ -23,4 +24,31 @@ H.dna.blood_type = random_blood_type() H.update_body() H.update_hair() +======= + +/datum/admins/proc/create_mob(mob/user) + var/static/create_mob_html + if (!create_mob_html) + var/mobjs = null + mobjs = jointext(typesof(/mob), ";") + create_mob_html = file2text('html/create_object.html') + create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"") + + user << browse(replacetext(create_mob_html, "/* ref src */", "\ref[src];[HrefToken()]"), "window=create_mob;size=425x475") + +/proc/randomize_human(mob/living/carbon/human/H) + H.gender = pick(MALE, FEMALE) + H.real_name = random_unique_name(H.gender) + H.name = H.real_name + H.underwear = random_underwear(H.gender) + H.skin_tone = random_skin_tone() + H.hair_style = random_hair_style(H.gender) + H.facial_hair_style = random_facial_hair_style(H.gender) + H.hair_color = random_short_color() + H.facial_hair_color = H.hair_color + H.eye_color = random_eye_color() + H.dna.blood_type = random_blood_type() + H.update_body() + H.update_hair() +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) H.update_body_parts() \ No newline at end of file diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm index 32801149f9..cddadb4082 100644 --- a/code/modules/admin/create_object.dm +++ b/code/modules/admin/create_object.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /datum/admins/proc/create_object(mob/user) var/static/create_object_html = null if (!create_object_html) @@ -23,4 +24,32 @@ html_form = replacetext(html_form, "null /* object types */", "\"[objectjs]\"") create_object_forms[path] = html_form - user << browse(replacetext(html_form, "/* ref src */", "\ref[src]"), "window=qco[path];size=425x475") \ No newline at end of file + user << browse(replacetext(html_form, "/* ref src */", "\ref[src]"), "window=qco[path];size=425x475") +======= +/datum/admins/proc/create_object(mob/user) + var/static/create_object_html = null + if (!create_object_html) + var/objectjs = null + objectjs = jointext(typesof(/obj), ";") + create_object_html = file2text('html/create_object.html') + create_object_html = replacetext(create_object_html, "null /* object types */", "\"[objectjs]\"") + + user << browse(replacetext(create_object_html, "/* ref src */", "\ref[src];[HrefToken()]"), "window=create_object;size=425x475") + +/datum/admins/proc/quick_create_object(mob/user) + var/static/list/create_object_forms = list( + /obj, /obj/structure, /obj/machinery, /obj/effect, + /obj/item, /obj/item/clothing, /obj/item/stack, /obj/item/device, + /obj/item/reagent_containers, /obj/item/gun) + + var/path = input("Select the path of the object you wish to create.", "Path", /obj) in create_object_forms + var/html_form = create_object_forms[path] + + if (!html_form) + var/objectjs = jointext(typesof(path), ";") + html_form = file2text('html/create_object.html') + html_form = replacetext(html_form, "null /* object types */", "\"[objectjs]\"") + create_object_forms[path] = html_form + + user << browse(replacetext(html_form, "/* ref src */", "\ref[src];[HrefToken()]"), "window=qco[path];size=425x475") +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) diff --git a/code/modules/admin/create_turf.dm b/code/modules/admin/create_turf.dm index 63e3b8cf69..62e26d89d5 100644 --- a/code/modules/admin/create_turf.dm +++ b/code/modules/admin/create_turf.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /datum/admins/proc/create_turf(mob/user) var/static/create_turf_html if (!create_turf_html) @@ -7,3 +8,14 @@ create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"") user << browse(replacetext(create_turf_html, "/* ref src */", "\ref[src]"), "window=create_turf;size=425x475") +======= +/datum/admins/proc/create_turf(mob/user) + var/static/create_turf_html + if (!create_turf_html) + var/turfjs = null + turfjs = jointext(typesof(/turf), ";") + create_turf_html = file2text('html/create_object.html') + create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"") + + user << browse(replacetext(create_turf_html, "/* ref src */", "\ref[src];[HrefToken()]"), "window=create_turf;size=425x475") +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index bdd799badf..d9c5b88364 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD GLOBAL_LIST_EMPTY(admin_datums) GLOBAL_PROTECT(admin_datums) @@ -102,4 +103,131 @@ you will have to do something like if(client.rights & R_ADMIN) yourself. if(rights_required && !(rights_required & subject.holder.rank.rights)) return 0 return 1 +======= +GLOBAL_LIST_EMPTY(admin_datums) +GLOBAL_PROTECT(admin_datums) + +GLOBAL_VAR_INIT(href_token, GenerateToken()) +GLOBAL_PROTECT(href_token) + +/datum/admins + var/datum/admin_rank/rank + + var/client/owner = null + var/fakekey = null + + var/datum/marked_datum + + var/spamcooldown = 0 + + var/admincaster_screen = 0 //TODO: remove all these 5 variables, they are completly unacceptable + var/datum/newscaster/feed_message/admincaster_feed_message = new /datum/newscaster/feed_message + var/datum/newscaster/wanted_message/admincaster_wanted_message = new /datum/newscaster/wanted_message + var/datum/newscaster/feed_channel/admincaster_feed_channel = new /datum/newscaster/feed_channel + var/admin_signature + var/href_token + +/datum/admins/New(datum/admin_rank/R, ckey) + if(!ckey) + QDEL_IN(src, 0) + throw EXCEPTION("Admin datum created without a ckey") + return + if(!istype(R)) + QDEL_IN(src, 0) + throw EXCEPTION("Admin datum created without a rank") + return + rank = R + admin_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]" + href_token = GenerateToken() + GLOB.admin_datums[ckey] = src + +/proc/GenerateToken() + . = "" + for(var/I in 1 to 32) + . += "[rand(10)]" + +/proc/HrefToken(forceGlobal = FALSE) + var/tok = GLOB.href_token + if(!forceGlobal && usr) + var/client/C = usr.client + if(!C) + CRASH("No client for HrefToken()!") + var/datum/admins/holder = C.holder + if(holder) + tok = holder.href_token + return "admin_token=[tok]" + +/datum/admins/proc/associate(client/C) + if(IsAdminAdvancedProcCall()) + var/msg = " has tried to elevate permissions!" + message_admins("[key_name_admin(usr)][msg]") + log_admin_private("[key_name(usr)][msg]") + return + if(istype(C)) + owner = C + owner.holder = src + owner.add_admin_verbs() //TODO + owner.verbs -= /client/proc/readmin + GLOB.admins |= C + +/datum/admins/proc/disassociate() + if(owner) + GLOB.admins -= owner + owner.remove_admin_verbs() + owner.holder = null + owner = null + +/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other) + if(!other) + return 1 //they have no rights + if(rank.rights == 65535) + return 1 //we have all the rights + if(src == other) + return 1 //you always have more rights than yourself + if(rank.rights != other.rank.rights) + if( (rank.rights & other.rank.rights) == other.rank.rights ) + return 1 //we have all the rights they have and more + return 0 + +/datum/admins/vv_edit_var(var_name, var_value) + return FALSE //nice try trialmin + +/* +checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags) +if rights_required == 0, then it simply checks if they are an admin. +if it doesn't return 1 and show_msg=1 it will prints a message explaining why the check has failed +generally it would be used like so: + +/proc/admin_proc() + if(!check_rights(R_ADMIN)) return + to_chat(world, "you have enough rights!") + +NOTE: it checks usr! not src! So if you're checking somebody's rank in a proc which they did not call +you will have to do something like if(client.rights & R_ADMIN) yourself. +*/ +/proc/check_rights(rights_required, show_msg=1) + if(usr && usr.client) + if (check_rights_for(usr.client, rights_required)) + return 1 + else + if(show_msg) + to_chat(usr, "Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].") + return 0 + +//probably a bit iffy - will hopefully figure out a better solution +/proc/check_if_greater_rights_than(client/other) + if(usr && usr.client) + if(usr.client.holder) + if(!other || !other.holder) + return 1 + return usr.client.holder.check_if_greater_rights_than_holder(other.holder) + return 0 + +//This proc checks whether subject has at least ONE of the rights specified in rights_required. +/proc/check_rights_for(client/subject, rights_required) + if(subject && subject.holder && subject.holder.rank) + if(rights_required && !(rights_required & subject.holder.rank.rights)) + return 0 + return 1 +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) return 0 \ No newline at end of file diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm index aafe3b393e..552757b750 100644 --- a/code/modules/admin/permissionverbs/permissionedit.dm +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -20,7 +20,7 @@
    - + @@ -36,10 +36,10 @@ if(!rights) rights = "*none*" output += "" - output += "" - output += "" - output += "" - output += "" + output += "" + output += "" + output += "" + output += "" output += "" output += {" diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 9237d1f1e2..0a3520285c 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -75,16 +75,16 @@ body += "
    CKEY \[+\]CKEY \[+\] RANK PERMISSIONS VERB-OVERRIDES
    [adm_ckey] \[-\][D.rank.name][rights][rights2text(0," ",D.rank.adds,D.rank.subs)][adm_ckey] \[-\][D.rank.name][rights][rights2text(0," ",D.rank.adds,D.rank.subs)]
    "; - body += "PP - " - body += "N - " + body += "PP - " + body += "N - " body += "VV - " - body += "TP - " + body += "TP - " body += "PM - " - body += "SM - " - body += "FLW - " - body += "LOGS
    " + body += "SM - " + body += "FLW - " + body += "LOGS
    " if(antagonist > 0) - body += "Antagonist"; + body += "Antagonist"; body += "
    "; @@ -195,7 +195,7 @@ Player panel
    - Hover over a line to see more information - Check antagonists - Kick everyone/AFKers in lobby + Hover over a line to see more information - Check antagonists - Kick everyone/AFKers in lobby

    @@ -320,26 +320,26 @@ dat += "Round Duration: [round(world.time / 36000)]:[add_zero("[world.time / 600 % 60]", 2)]:[world.time / 100 % 6][world.time / 100 % 10]
    " dat += "Emergency shuttle
    " if(EMERGENCY_IDLE_OR_RECALLED) - dat += "Call Shuttle
    " + dat += "Call Shuttle
    " else var/timeleft = SSshuttle.emergency.timeLeft() if(SSshuttle.emergency.mode == SHUTTLE_CALL) - dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
    " - dat += "Send Back
    " + dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
    " + dat += "Send Back
    " else - dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
    " + dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
    " dat += "Continuous Round Status
    " - dat += "[config.continuous[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]" + dat += "[config.continuous[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]" if(config.continuous[SSticker.mode.config_tag]) - dat += ", [config.midround_antag[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]
    " + dat += ", [config.midround_antag[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]
    " else dat += "
    " if(config.midround_antag[SSticker.mode.config_tag]) - dat += "Time limit: [config.midround_antag_time_check] minutes into round
    " - dat += "Living crew limit: [config.midround_antag_life_check * 100]% of crew alive
    " - dat += "If limits past: [SSticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]
    " - dat += "End Round Now
    " - dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]" + dat += "Time limit: [config.midround_antag_time_check] minutes into round
    " + dat += "Living crew limit: [config.midround_antag_life_check * 100]% of crew alive
    " + dat += "If limits past: [SSticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]
    " + dat += "End Round Now
    " + dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]" var/connected_players = GLOB.clients.len var/lobby_players = 0 var/observers = 0 @@ -389,11 +389,11 @@ for(var/datum/mind/N in SSticker.mode.syndicates) var/mob/M = N.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" + dat += "FLW" else - dat += "[N.name]([N.key]) Nuclear Operative Body destroyed!" + dat += "[N.name]([N.key]) Nuclear Operative Body destroyed!" dat += "PM" dat += "
    " for(var/obj/item/disk/nuclear/N in GLOB.poi_list) @@ -402,7 +402,7 @@ while(!isturf(disk_loc)) if(ismob(disk_loc)) var/mob/M = disk_loc - dat += "carried by [M.real_name] " + dat += "carried by [M.real_name] " if(isobj(disk_loc)) var/obj/O = disk_loc dat += "in \a [O.name] " @@ -415,29 +415,29 @@ for(var/datum/mind/N in SSticker.mode.head_revolutionaries) var/mob/M = N.current if(!M) - dat += "" + dat += "" dat += "" else - dat += "" + dat += "" dat += "" - dat += "" + dat += "" for(var/datum/mind/N in SSticker.mode.revolutionaries) var/mob/M = N.current if(M) - dat += "" + dat += "" dat += "" - dat += "" + dat += "" dat += "
    Nuclear Disk(s)
    [N.name]([N.key])Head Revolutionary body destroyed!
    [N.name]([N.key])Head Revolutionary body destroyed!PM
    [M.real_name] (Leader)[M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]
    [M.real_name] (Leader)[M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]PMFLW
    FLW
    [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]
    [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]PMFLW
    FLW
    " for(var/datum/mind/N in SSticker.mode.get_living_heads()) var/mob/M = N.current if(M) - dat += "" + dat += "" dat += "" - dat += "" + dat += "" var/turf/mob_loc = get_turf(M) dat += "" else - dat += "" + dat += "" dat += "" dat += "
    Target(s)Location
    [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]
    [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]PMFLWFLW[mob_loc.loc]
    [N.name]([N.key])Head body destroyed!
    [N.name]([N.key])Head body destroyed!PM
    " @@ -464,12 +464,12 @@ for(var/datum/mind/changeling in SSticker.mode.changelings) var/mob/M = changeling.current if(M) - dat += "[M.mind.changeling.changelingID] as [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.mind.changeling.changelingID] as [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" - dat += "Show Objective" + dat += "FLW" + dat += "Show Objective" else - dat += "[changeling.name]([changeling.key])Changeling body destroyed!" + dat += "[changeling.name]([changeling.key])Changeling body destroyed!" dat += "PM" dat += "" @@ -478,12 +478,12 @@ for(var/datum/mind/wizard in SSticker.mode.wizards) var/mob/M = wizard.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" - dat += "Show Objective" + dat += "FLW" + dat += "Show Objective" else - dat += "[wizard.name]([wizard.key])Wizard body destroyed!" + dat += "[wizard.name]([wizard.key])Wizard body destroyed!" dat += "PM" dat += "" @@ -492,12 +492,12 @@ for(var/datum/mind/apprentice in SSticker.mode.apprentices) var/mob/M = apprentice.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" - dat += "Show Objective" + dat += "FLW" + dat += "Show Objective" else - dat += "[apprentice.name]([apprentice.key])Apprentice body destroyed!!" + dat += "[apprentice.name]([apprentice.key])Apprentice body destroyed!!" dat += "PM" dat += "" @@ -506,9 +506,9 @@ for(var/datum/mind/N in SSticker.mode.cult) var/mob/M = N.current if(M) - dat += "[M.real_name][N.has_antag_datum(ANTAG_DATUM_CULT_MASTER) ? " \[Master\]" : ""][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][N.has_antag_datum(ANTAG_DATUM_CULT_MASTER) ? " \[Master\]" : ""][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" + dat += "FLW" dat += "" if(SSticker.mode.servants_of_ratvar.len) @@ -516,9 +516,9 @@ for(var/datum/mind/N in SSticker.mode.servants_of_ratvar) var/mob/M = N.current if(M) - dat += "[M.real_name][M.client ? "" : " (ghost)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (ghost)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" + dat += "FLW" dat += "" if(SSticker.mode.traitors.len > 0) @@ -526,12 +526,12 @@ for(var/datum/mind/traitor in SSticker.mode.traitors) var/mob/M = traitor.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" - dat += "Show Objective" + dat += "FLW" + dat += "Show Objective" else - dat += "[traitor.name]([traitor.key])Traitor body destroyed!" + dat += "[traitor.name]([traitor.key])Traitor body destroyed!" dat += "PM" dat += "" @@ -540,12 +540,12 @@ for(var/datum/mind/abductor in SSticker.mode.abductors) var/mob/M = abductor.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" - dat += "Show Objective" + dat += "FLW" + dat += "Show Objective" else - dat += "[abductor.name]([abductor.key])Abductor body destroyed!" + dat += "[abductor.name]([abductor.key])Abductor body destroyed!" dat += "PM" dat += "" dat += "
    " @@ -553,12 +553,12 @@ for(var/datum/mind/abductee in E.abductee_minds) var/mob/M = abductee.current if(M) - dat += "" + dat += "" dat += "" - dat += "" - dat += "" + dat += "" + dat += "" else - dat += "" + dat += "" dat += "" dat += "
    Abductees
    [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]
    [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]PMFLWShow Objective
    FLWShow Objective
    [abductee.name]([abductee.key])Abductee body destroyed!
    [abductee.name]([abductee.key])Abductee body destroyed!PM
    " @@ -569,12 +569,12 @@ var/mob/M = devil.current var/datum/antagonist/devil/devilinfo = devil.has_antag_datum(ANTAG_DATUM_DEVIL) if(M) - dat += "[M.real_name] : [devilinfo.truename][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name] : [devilinfo.truename][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "Show Objective" - dat += "Show all devil info" + dat += "Show Objective" + dat += "Show all devil info" else - dat += "[devil.name] : [devilinfo.truename] ([devil.key])devil body destroyed!" + dat += "[devil.name] : [devilinfo.truename] ([devil.key])devil body destroyed!" dat += "PM" dat += "" @@ -584,11 +584,11 @@ var/datum/mind/sintouched = X var/mob/M = sintouched.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "Show Objective" + dat += "Show Objective" else - dat += "[sintouched.name]([sintouched.key])sintouched body destroyed!" + dat += "[sintouched.name]([sintouched.key])sintouched body destroyed!" dat += "PM" dat += "" @@ -606,11 +606,11 @@ for(var/datum/mind/blob in blob_minds) var/mob/M = blob.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" + dat += "FLW" else - dat += "[blob.name]([blob.key])Blob not found!" + dat += "[blob.name]([blob.key])Blob not found!" dat += "PM" dat += "" @@ -622,11 +622,11 @@ for(var/datum/mind/eek in mode.ape_infectees) var/mob/M = eek.current if(M) - dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" + dat += "[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]" dat += "PM" - dat += "FLW" + dat += "FLW" else - dat += "[eek.name]([eek.key])Monkey not found!" + dat += "[eek.name]([eek.key])Monkey not found!" dat += "PM" dat += "" diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 70c7346369..899e763c92 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -7,9 +7,9 @@ dat +={" General Secrets

    - Show Job Debug
    - Admin Log
    - Show Admin List
    + Show Job Debug
    + Admin Log
    + Show Admin List

    "} @@ -17,27 +17,27 @@ dat += {" Admin Secrets

    - Cure all diseases currently in existence
    - Bombing List
    - Show current traitors and objectives
    - Show last [length(GLOB.lastsignalers)] signalers
    - Show last [length(GLOB.lawchanges)] law changes
    - Show AI Laws
    - Show Game Mode
    - Show Crew Manifest
    - List DNA (Blood)
    - List Fingerprints
    - Enable/Disable CTF

    - Reset Thunderdome to default state
    - Rename Station Name
    - Reset Station Name
    + Cure all diseases currently in existence
    + Bombing List
    + Show current traitors and objectives
    + Show last [length(GLOB.lastsignalers)] signalers
    + Show last [length(GLOB.lawchanges)] law changes
    + Show AI Laws
    + Show Game Mode
    + Show Crew Manifest
    + List DNA (Blood)
    + List Fingerprints
    + Enable/Disable CTF

    + Reset Thunderdome to default state
    + Rename Station Name
    + Reset Station Name

    Shuttles

    - Move Ferry
    - Toggle Arrivals Ferry
    - Move Mining Shuttle
    - Move Labor Shuttle
    + Move Ferry
    + Toggle Arrivals Ferry
    + Move Mining Shuttle
    + Move Labor Shuttle

    "} @@ -45,6 +45,7 @@ dat += {" Fun Secrets

    +<<<<<<< HEAD Trigger a Virus Outbreak
    Turn all humans into monkeys
    @@ -66,10 +67,35 @@ Break all lights
    Fix all lights
    The floor is lava! (DANGEROUS: extremely lame)
    +======= +<<<<<<< HEAD + +======= +>>>>>>> 6e5ebf9c41fc97d5ee0daf4fd22536844438ace0 + Trigger a Virus Outbreak
    + Turn all humans into monkeys
    + Chinese Cartoons
    + Change the species of all humans
    + Make all areas powered
    + Make all areas unpowered
    + Power all SMES
    + Triple AI mode (needs to be used in the lobby)
    + Everyone is the traitor
    + Summon Guns
    + Summon Magic
    + Summon Events (Toggle)
    + There can only be one!
    + There can only be one! (40-second delay)
    + Make all players retarded
    + Egalitarian Station Mode
    + Break all lights
    + Fix all lights
    + The floor is lava! (DANGEROUS: extremely lame)
    +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839)
    - Change bomb cap
    - Mass Purrbation
    - Mass Remove Purrbation
    + Change bomb cap
    + Mass Purrbation
    + Mass Remove Purrbation
    "} dat += "
    " @@ -78,9 +104,9 @@ dat += {" Security Level Elevated

    - Change all maintenance doors to engie/brig access only
    - Change all maintenance doors to brig access only
    - Remove cap on security officers
    + Change all maintenance doors to engie/brig access only
    + Change all maintenance doors to brig access only
    + Remove cap on security officers

    "} diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index b42fe93eef..9eb66986b0 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -147,10 +147,10 @@ return var/output var/ruler = "


    " - var/navbar = "\[All\]|\[#\]" + var/navbar = "\[All\]|\[#\]" for(var/letter in GLOB.alphabet) - navbar += "|\[[letter]\]" - navbar += "|\[Memos\]|\[Watchlist\]" + navbar += "|\[[letter]\]" + navbar += "|\[Memos\]|\[Watchlist\]" navbar += "
    \ \ \ @@ -160,14 +160,14 @@ if(type == "memo" || type == "watchlist entry") if(type == "memo") output += "

    Admin memos

    " - output += "\[Add memo\]" + output += "\[Add memo\]" else if(type == "watchlist entry") output += "

    Watchlist entries

    " - output += "\[Add watchlist entry\]" + output += "\[Add watchlist entry\]" if(filter) - output += "|\[Unfilter clients\]" + output += "|\[Unfilter clients\]" else - output += "|\[Filter offline clients\]" + output += "|\[Filter offline clients\]" output += ruler var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, targetckey, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]'") if(!query_get_type_messages.warn_execute()) @@ -186,10 +186,10 @@ if(type == "watchlist entry") output += "[t_ckey] | " output += "[timestamp] | [server] | [admin_ckey]
    " - output += " \[Delete\]" - output += " \[Edit\]" + output += " \[Delete\]" + output += " \[Edit\]" if(editor_ckey) - output += " Last edit by [editor_ckey] (Click here to see edit log)" + output += " Last edit by [editor_ckey] (Click here to see edit log)" output += "
    [text]
    " if(target_ckey) target_ckey = sanitizeSQL(target_ckey) @@ -215,18 +215,23 @@ var/data data += "[timestamp] | [server] | [admin_ckey]" if(!linkless) - data += " \[Delete\]" + data += " \[Delete\]" if(type == "note") - data += " [secret ? "\[Secret\]" : "\[Not secret\]"]" + data += " [secret ? "\[Secret\]" : "\[Not secret\]"]" if(type == "message sent") data += " Message has been sent" if(editor_ckey) data += "|" else - data += " \[Edit\]" + data += " \[Edit\]" if(editor_ckey) +<<<<<<< HEAD data += " Last edit by [editor_ckey] (Click here to see edit log)" data += "
    [text]
    " +======= + data += " Last edit by [editor_ckey] (Click here to see edit log)" + data += "
    [text]


    " +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) switch(type) if("message") messagedata += data @@ -238,12 +243,12 @@ notedata += data output += "

    [target_ckey]

    " if(!linkless) - output += "\[Add note\]" - output += " \[Add message\]" - output += " \[Add to watchlist\]" - output += " \[Refresh page\]
    " + output += "\[Add note\]" + output += " \[Add message\]" + output += " \[Add to watchlist\]" + output += " \[Refresh page\]" else - output += " \[Refresh page\]" + output += " \[Refresh page\]" output += ruler if(messagedata) output += "

    Messages

    " @@ -257,7 +262,7 @@ if(index) var/index_ckey var/search - output += "
    \[Add message\]\[Add watchlist entry\]\[Add note\]
    " + output += "
    \[Add message\]\[Add watchlist entry\]\[Add note\]
    " output += ruler if(!isnum(index)) index = sanitizeSQL(index) @@ -273,9 +278,9 @@ return while(query_list_messages.NextRow()) index_ckey = query_list_messages.item[1] - output += "[index_ckey]
    " + output += "[index_ckey]
    " else if(!type && !target_ckey && !index) - output += "
    \[Add message\]\[Add watchlist entry\]\[Add note\]
    " + output += "
    \[Add message\]\[Add watchlist entry\]\[Add note\]
    " output += ruler usr << browse(output, "window=browse_messages;size=900x500") @@ -313,7 +318,7 @@ proc/get_message_output(type, target_ckey) if("memo") output += "Memo by [admin_ckey] on [timestamp]" if(editor_ckey) - output += "
    Last edit by [editor_ckey] (Click here to see edit log)" + output += "
    Last edit by [editor_ckey] (Click here to see edit log)" output += "
    [text]

    " return output diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index 9ac85e49fa..f5d6c72ffb 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -152,11 +152,11 @@ /datum/admins/proc/stickyban_gethtml(ckey, ban) . = {" - \[-\] - \[revert\] + \[-\] + \[revert\] [ckey]
    " - [ban["message"]] \[Edit\]
    + [ban["message"]] \[Edit\]
    "} if (ban["admin"]) . += "[ban["admin"]]
    " @@ -166,7 +166,7 @@ for (var/key in ban["keys"]) if (ckey(key) == ckey) continue - . += "
  • \[-\][key]
  • " + . += "
  • \[-\][key]
  • " . += "\n" /datum/admins/proc/stickyban_show() @@ -185,7 +185,7 @@ Sticky Bans -

    All Sticky Bans:

    \[+\]
    +

    All Sticky Bans:

    \[+\]
    [banhtml] "} diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index f7b0f8b6ff..f5f3326001 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1,3 +1,16 @@ +/datum/admins/proc/CheckAdminHref(href, href_list) + var/auth = href_list["admin_token"] + . = auth && auth != href_token && auth != GLOB.href_token + if(.) + return + var/msg = !auth ? "no" : "a bad" + message_admins("[key_name_admin(usr)] clicked an href with [msg] authorization key!") + if(config.debug_admin_hrefs) + message_admins("Debug mode enabled, call not blocked. Please ask your coders to review this round's logs.") + log_world("UAH: [href]") + return TRUE + log_admin_private("[key_name(usr)] clicked an href with [msg] authorization key! [href]") + /datum/admins/Topic(href, href_list) ..() @@ -5,6 +18,10 @@ message_admins("[usr.key] has attempted to override the admin panel!") log_admin("[key_name(usr)] tried to use the admin panel without authorization.") return + + if(!CheckAdminHref(href, href_list)) + return + if(href_list["ahelp"]) if(!check_rights(R_ADMIN, TRUE)) return diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 5d4e0dc29a..eaa98934d5 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -122,7 +122,7 @@ /proc/SDQL_gen_vv_href(t) var/text = "" - text += "\ref[t]" + text += "\ref[t]" if(istype(t, /atom)) var/atom/a = t var/turf/T = a.loc diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index d593973188..c1c1894184 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -80,10 +80,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(!l2b) return var/list/dat = list("[title]") - dat += "Refresh

    " + dat += "Refresh

    " for(var/I in l2b) var/datum/admin_help/AH = I - dat += "Ticket #[AH.id]: [AH.initiator_key_name]: [AH.name]
    " + dat += "Ticket #[AH.id]: [AH.initiator_key_name]: [AH.name]
    " usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480") @@ -228,22 +228,22 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /datum/admin_help/proc/ClosureLinks(ref_src) if(!ref_src) ref_src = "\ref[src]" - . = " (REJT)" - . += " (IC)" - . += " (CLOSE)" - . += " (RSLVE)" + . = " (REJT)" + . += " (IC)" + . += " (CLOSE)" + . += " (RSLVE)" //private /datum/admin_help/proc/LinkedReplyName(ref_src) if(!ref_src) ref_src = "\ref[src]" - return "[initiator_key_name]" + return "[initiator_key_name]" //private /datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket") if(!ref_src) ref_src = "\ref[src]" - return "[msg]" + return "[msg]" //message from the initiator without a target, all admins will see this //won't bug irc @@ -675,7 +675,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(found.mind && found.mind.special_role) is_antag = 1 founds += "Name: [found.name]([found.real_name]) Ckey: [found.ckey] [is_antag ? "(Antag)" : null] " - msg += "[original_word](?|F) " + msg += "[original_word](?|F) " continue msg += "[original_word] " if(irc) diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 707a76854f..8e543c8a73 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -12,7 +12,7 @@ log_talk(mob,"[key_name(src)] : [msg]",LOGASAY) msg = keywords_lookup(msg) if(check_rights(R_ADMIN,0)) - msg = "ADMIN: [key_name(usr, 1)] (FLW): [msg]" + msg = "ADMIN: [key_name(usr, 1)] [ADMIN_FLW(mob)]: [msg]" to_chat(GLOB.admins, msg) else msg = "ADMIN: [key_name(usr, 1)]: [msg]" diff --git a/code/modules/admin/verbs/individual_logging.dm b/code/modules/admin/verbs/individual_logging.dm index ca84d5d759..cd3feed5d0 100644 --- a/code/modules/admin/verbs/individual_logging.dm +++ b/code/modules/admin/verbs/individual_logging.dm @@ -1,12 +1,12 @@ /proc/show_individual_logging_panel(mob/M, type = INDIVIDUAL_ATTACK_LOG) if(!M || !ismob(M)) return - var/dat = "
    Attack log | " - dat += "Say log | " - dat += "Emote log | " - dat += "OOC log | " - dat += "Show all | " - dat += "Refresh
    " + var/dat = "
    Attack log | " + dat += "Say log | " + dat += "Emote log | " + dat += "OOC log | " + dat += "Show all | " + dat += "Refresh
    " dat += "
    " diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index c8df7f56f1..398965e74d 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -11,6 +11,7 @@ /datum/admins/proc/one_click_antag() var/dat = {" +<<<<<<< HEAD Make Traitors
    Make Changelings
    Make Revs
    @@ -23,6 +24,19 @@ Make CentCom Response Team (Requires Ghosts)
    Make Abductor Team (Requires Ghosts)
    Make Revenant (Requires Ghost)
    +======= + Make Traitors
    + Make Changelings
    + Make Revs
    + Make Cult
    + Make Clockwork Cult
    + Make Blob
    + Make Wizard (Requires Ghosts)
    + Make Nuke Team (Requires Ghosts)
    + Make CentCom Response Team (Requires Ghosts)
    + Make Abductor Team (Requires Ghosts)
    + Make Revenant (Requires Ghost)
    +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) "} var/datum/browser/popup = new(usr, "oneclickantag", "Quick-Create Antagonist", 400, 400) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 62f3cab1d1..cb27d019ce 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -1147,8 +1147,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits /datum/admins/proc/modify_goals() var/dat = "" for(var/datum/station_goal/S in SSticker.mode.station_goals) - dat += "[S.name] - Announce | Remove
    " - dat += "
    Add New Goal" + dat += "[S.name] - Announce | Remove
    " + dat += "
    Add New Goal" usr << browse(dat, "window=goals;size=400x400") @@ -1219,7 +1219,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits var/list/msg = list() msg += "Playtime ReportPlaytime:
    " src << browse(msg.Join(), "window=Player_playtime_check") @@ -1233,7 +1233,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits var/list/body = list() body += "Playtime for [C.key]
    Playtime:" body += C.get_exp_report() - body += "Toggle Exempt status" + body += "Toggle Exempt status" body += "" usr << browse(body.Join(), "window=playerplaytime[C.ckey];size=550x615") diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm index eee95fe0af..dddff75bb2 100644 --- a/code/modules/error_handler/error_viewer.dm +++ b/code/modules/error_handler/error_viewer.dm @@ -71,7 +71,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) if (linear) back_to_param += ";viewruntime_linear=1" - return "[linktext]" + return "[linktext]" /datum/error_viewer/error_cache var/list/errors = list() @@ -181,12 +181,12 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) var/html = build_header(back_to, linear) html += "[name]
    [desc]
    " if (usr_ref) - html += "
    usr: VV" - html += " PP" - html += " Follow" + html += "
    usr: VV" + html += " PP" + html += " Follow" if (istype(usr_loc)) - html += "
    usr.loc: VV" - html += " JMP" + html += "
    usr.loc: VV" + html += " JMP" browse_to(user, html) diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 1feb7aa116..5ea8c20e32 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -390,10 +390,10 @@ /datum/spacevine_controller/vv_get_dropdown() . = ..() . += "---" - .["Delete Vines"] = "?_src_=\ref[src];purge_vines=1" + .["Delete Vines"] = "?_src_=\ref[src];[HrefToken()];purge_vines=1" /datum/spacevine_controller/Topic(href, href_list) - if(..() || !check_rights(R_ADMIN, FALSE)) + if(..() || !check_rights(R_ADMIN, FALSE) || !usr.client.holder.CheckAdminHref(href, href_list)) return if(href_list["purge_vines"]) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 84ff0c2ef2..717c5478a5 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -860,7 +860,7 @@ /mob/living/carbon/vv_get_dropdown() . = ..() . += "---" - .["Make AI"] = "?_src_=vars;makeai=\ref[src]" - .["Modify bodypart"] = "?_src_=vars;editbodypart=\ref[src]" - .["Modify organs"] = "?_src_=vars;editorgans=\ref[src]" - .["Hallucinate"] = "?_src_=vars;hallucinate=\ref[src]" + .["Make AI"] = "?_src_=vars;[HrefToken()];makeai=\ref[src]" + .["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=\ref[src]" + .["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=\ref[src]" + .["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=\ref[src]" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 304a745220..069dcb8ab5 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -906,12 +906,12 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/vv_get_dropdown() . = ..() . += "---" - .["Make monkey"] = "?_src_=vars;makemonkey=\ref[src]" - .["Set Species"] = "?_src_=vars;setspecies=\ref[src]" - .["Make cyborg"] = "?_src_=vars;makerobot=\ref[src]" - .["Make alien"] = "?_src_=vars;makealien=\ref[src]" - .["Make slime"] = "?_src_=vars;makeslime=\ref[src]" - .["Toggle Purrbation"] = "?_src_=vars;purrbation=\ref[src]" + .["Make monkey"] = "?_src_=vars;[HrefToken()];makemonkey=\ref[src]" + .["Set Species"] = "?_src_=vars;[HrefToken()];setspecies=\ref[src]" + .["Make cyborg"] = "?_src_=vars;[HrefToken()];makerobot=\ref[src]" + .["Make alien"] = "?_src_=vars;[HrefToken()];makealien=\ref[src]" + .["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=\ref[src]" + .["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=\ref[src]" /mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user) if((target != pulling) || (grab_state < GRAB_AGGRESSIVE) || (user != target) || !isliving(user) || stat || user.stat)//Get consent first :^) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 76553d17fd..1ef1d9df25 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -950,18 +950,18 @@ /mob/vv_get_dropdown() . = ..() . += "---" - .["Gib"] = "?_src_=vars;gib=\ref[src]" - .["Give Spell"] = "?_src_=vars;give_spell=\ref[src]" - .["Remove Spell"] = "?_src_=vars;remove_spell=\ref[src]" - .["Give Disease"] = "?_src_=vars;give_disease=\ref[src]" - .["Toggle Godmode"] = "?_src_=vars;godmode=\ref[src]" - .["Drop Everything"] = "?_src_=vars;drop_everything=\ref[src]" - .["Regenerate Icons"] = "?_src_=vars;regenerateicons=\ref[src]" - .["Make Space Ninja"] = "?_src_=vars;ninja=\ref[src]" - .["Show player panel"] = "?_src_=vars;mob_player_panel=\ref[src]" - .["Toggle Build Mode"] = "?_src_=vars;build_mode=\ref[src]" - .["Assume Direct Control"] = "?_src_=vars;direct_control=\ref[src]" - .["Offer Control to Ghosts"] = "?_src_=vars;offer_control=\ref[src]" + .["Gib"] = "?_src_=vars;[HrefToken()];gib=\ref[src]" + .["Give Spell"] = "?_src_=vars;[HrefToken()];give_spell=\ref[src]" + .["Remove Spell"] = "?_src_=vars;[HrefToken()];remove_spell=\ref[src]" + .["Give Disease"] = "?_src_=vars;[HrefToken()];give_disease=\ref[src]" + .["Toggle Godmode"] = "?_src_=vars;[HrefToken()];godmode=\ref[src]" + .["Drop Everything"] = "?_src_=vars;[HrefToken()];drop_everything=\ref[src]" + .["Regenerate Icons"] = "?_src_=vars;[HrefToken()];regenerateicons=\ref[src]" + .["Make Space Ninja"] = "?_src_=vars;[HrefToken()];ninja=\ref[src]" + .["Show player panel"] = "?_src_=vars;[HrefToken()];mob_player_panel=\ref[src]" + .["Toggle Build Mode"] = "?_src_=vars;[HrefToken()];build_mode=\ref[src]" + .["Assume Direct Control"] = "?_src_=vars;[HrefToken()];direct_control=\ref[src]" + .["Offer Control to Ghosts"] = "?_src_=vars;[HrefToken()];offer_control=\ref[src]" /mob/vv_get_var(var_name) switch(var_name) diff --git a/code/modules/station_goals/station_goal.dm b/code/modules/station_goals/station_goal.dm index 4a9bc42438..98ec01f641 100644 --- a/code/modules/station_goals/station_goal.dm +++ b/code/modules/station_goals/station_goal.dm @@ -39,7 +39,7 @@ /datum/station_goal/Topic(href, href_list) ..() - if(!check_rights(R_ADMIN)) + if(!check_rights(R_ADMIN) || !usr.client.holder.CheckAdminHref(href, href_list)) return if(href_list["announce"]) diff --git a/config/config.txt b/config/config.txt index ae2cc1e43a..7073d7e33c 100644 --- a/config/config.txt +++ b/config/config.txt @@ -329,3 +329,9 @@ MINUTE_TOPIC_LIMIT 100 ## Send a message to IRC when starting a new game #IRC_ANNOUNCE_NEW_GAME +<<<<<<< HEAD +======= + +## Allow admin hrefs that don't use the new token system, will eventually be removed +DEBUG_ADMIN_HREFS +>>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) From 8e0ef4f38f18879ebd14c0e9853c2a80481444c5 Mon Sep 17 00:00:00 2001 From: Kyle Spier-Swenson Date: Sat, 9 Sep 2017 12:23:54 -0700 Subject: [PATCH 017/102] num2text the Instances number (#30509) --- code/modules/mob/mob.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 76553d17fd..a759bb89ec 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -587,7 +587,7 @@ var/turf/T = get_turf(client.eye) stat("Location:", COORD(T)) stat("CPU:", "[world.cpu]") - stat("Instances:", "[world.contents.len]") + stat("Instances:", "[num2text(world.contents.len, 10)]") GLOB.stat_entry() config.stat_entry() stat(null) From eaeaae7bef957e594e2727d02a7f3accd4392567 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Sat, 9 Sep 2017 20:39:49 -0400 Subject: [PATCH 019/102] Added warnings for ultrasafe and safe security modes (#30515) --- code/__DEFINES/misc.dm | 5 +++++ code/game/world.dm | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 209a33e0c5..1c79dde65f 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -458,3 +458,8 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE #define SHELLEO_ERRORLEVEL 1 #define SHELLEO_STDOUT 2 #define SHELLEO_STDERR 3 + +//server security mode +#define SECURITY_SAFE 1 +#define SECURITY_ULTRASAFE 2 +#define SECURITY_TRUSTED 3 diff --git a/code/game/world.dm b/code/game/world.dm index a1fcc364cd..991e6230e6 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,3 +1,6 @@ +GLOBAL_VAR(security_mode) +GLOBAL_PROTECT(security_mode) + /world/New() log_world("World loaded at [time_stamp()]") @@ -5,6 +8,8 @@ GLOB.config_error_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl + CheckSecurityMode() + make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) config = new @@ -94,6 +99,20 @@ if(GLOB.round_id) log_game("Round ID: [GLOB.round_id]") +/world/proc/CheckSecurityMode() + //try to write to data + if(!text2file("The world is running at least safe mode", "data/server_security_check.lock")) + GLOB.security_mode = SECURITY_ULTRASAFE + warning("/tg/station 13 is not supported in ultrasafe security mode. Everything will break!") + return + + //try to shell + if(shell("echo \"The world is running in trusted mode\"") != null) + GLOB.security_mode = SECURITY_TRUSTED + else + GLOB.security_mode = SECURITY_SAFE + warning("/tg/station 13 uses many file operations, a few shell()s, and some external call()s. Trusted mode is recommended. You can download our source code for your own browsing and compilation at https://github.com/tgstation/tgstation") + /world/Topic(T, addr, master, key) var/list/input = params2list(T) From 8a297a3a9cc58c056886a889eeffa4554814f861 Mon Sep 17 00:00:00 2001 From: KorPhaeron Date: Sat, 9 Sep 2017 21:07:02 -0500 Subject: [PATCH 021/102] People in soft crit will leave blood trails when dragging themselves/Will take less damage in soft crit --- .../mob/living/carbon/human/human_movement.dm | 56 +++++++++++++++++++ code/modules/mob/living/carbon/life.dm | 10 +++- code/modules/mob/living/living.dm | 28 +++++----- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 52650ec273..d01048c69a 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -12,6 +12,7 @@ /mob/living/carbon/human/experience_pressure_difference() playsound(src, 'sound/effects/space_wind.ogg', 50, 1) if(shoes && shoes.flags_1&NOSLIP_1) +<<<<<<< HEAD return 0 return ..() @@ -65,3 +66,58 @@ if(..()) return 1 return dna.species.space_move(src) +======= + return 0 + return ..() + +/mob/living/carbon/human/mob_has_gravity() + . = ..() + if(!.) + if(mob_negates_gravity()) + . = 1 + +/mob/living/carbon/human/mob_negates_gravity() + return ((shoes && shoes.negates_gravity()) || dna.species.negates_gravity(src)) + +/mob/living/carbon/human/Move(NewLoc, direct) + . = ..() + for(var/datum/mutation/human/HM in dna.mutations) + HM.on_move(src, NewLoc) + + if(shoes) + if(!lying && !buckled) + if(loc == NewLoc) + if(!has_gravity(loc)) + return + var/obj/item/clothing/shoes/S = shoes + + //Bloody footprints + var/turf/T = get_turf(src) + if(S.bloody_shoes && S.bloody_shoes[S.blood_state]) + var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T + if(oldFP && oldFP.blood_state == S.blood_state) + return + else + //No oldFP or it's a different kind of blood + S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state]-BLOOD_LOSS_PER_STEP) + var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T) + FP.blood_state = S.blood_state + FP.entered_dirs |= dir + FP.bloodiness = S.bloody_shoes[S.blood_state] + if(S.blood_DNA && S.blood_DNA.len) + FP.transfer_blood_dna(S.blood_DNA) + FP.update_icon() + update_inv_shoes() + //End bloody footprints + + S.step_action() +/mob/living/carbon/human/Moved() + . = ..() + if(buckled_mobs && buckled_mobs.len && riding_datum) + riding_datum.on_vehicle_move() + +/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee. + if(..()) + return 1 + return dna.species.space_move(src) +>>>>>>> 96a55aa... People in soft crit will leave blood trails when dragging themselves/Will take less damage in soft crit (#30482) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index d6d6084380..38e13f41d0 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -58,12 +58,14 @@ var/datum/gas_mixture/breath - if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube"))) + if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube"))) losebreath++ + else if(health <= HEALTH_THRESHOLD_CRIT) + losebreath += 0.25 + //Suffocate if(losebreath > 0) - losebreath-- if(prob(10)) emote("gasp") if(istype(loc, /obj/)) @@ -113,7 +115,9 @@ if(!breath || (breath.total_moles() == 0) || !lungs) if(reagents.has_reagent("epinephrine") && lungs) return - adjustOxyLoss(1) + var/oxy_loss = min(losebreath, 1) + adjustOxyLoss(oxy_loss) + losebreath -= oxy_loss failed_last_breath = 1 throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) return 0 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 70a8474165..b2c771db08 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -429,6 +429,7 @@ else return 0 + var/old_direction = dir var/atom/movable/pullee = pulling if(pullee && get_dist(src, pullee) > 1) stop_pulling() @@ -444,10 +445,6 @@ var/pull_dir = get_dir(src, pulling) if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) //puller and pullee more than one tile away or in diagonal position - if(isliving(pulling)) - var/mob/living/M = pulling - if(M.lying && !M.buckled && (prob(M.getBruteLoss()*200/M.maxHealth))) - M.makeTrail(T) pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up stop_pulling() @@ -458,6 +455,10 @@ if (s_active && !(CanReach(s_active,view_only = TRUE))) s_active.close(src) + if(lying && !buckled && prob(getBruteLoss()*200/maxHealth)) + + makeTrail(newloc, T, old_direction) + /mob/living/movement_delay(ignorewalk = 0) . = ..() if(isopenturf(loc) && !is_flying()) @@ -474,31 +475,32 @@ if(MOVE_INTENT_WALK) . += config.walk_speed -/mob/living/proc/makeTrail(turf/target_turf) +/mob/living/proc/makeTrail(turf/target_turf, turf/start, direction) if(!has_gravity()) return var/blood_exists = FALSE - for(var/obj/effect/decal/cleanable/trail_holder/C in loc) //checks for blood splatter already on the floor + for(var/obj/effect/decal/cleanable/trail_holder/C in start) //checks for blood splatter already on the floor blood_exists = TRUE - if(isturf(loc)) + if(isturf(start)) var/trail_type = getTrail() if(trail_type) var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1) if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage. - var/newdir = get_dir(target_turf, loc) - if(newdir != dir) - newdir = newdir | dir + var/newdir = get_dir(target_turf, start) + if(newdir != direction) + newdir = newdir | direction if(newdir == 3) //N + S newdir = NORTH else if(newdir == 12) //E + W newdir = EAST if((newdir in GLOB.cardinals) && (prob(50))) - newdir = turn(get_dir(target_turf, loc), 180) + newdir = turn(get_dir(target_turf, start), 180) if(!blood_exists) - new /obj/effect/decal/cleanable/trail_holder(loc) - for(var/obj/effect/decal/cleanable/trail_holder/TH in loc) + new /obj/effect/decal/cleanable/trail_holder(start) + + for(var/obj/effect/decal/cleanable/trail_holder/TH in start) if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) TH.existing_dirs += newdir TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir)) From d158ec95285f53e801b72773690b431e0957d56a Mon Sep 17 00:00:00 2001 From: Kerbin-Fiber Date: Sun, 10 Sep 2017 03:42:16 -0500 Subject: [PATCH 022/102] Adds Donksoft Toy Vendor (Machine Board) to the Circuit Imprinter --- code/game/machinery/vending.dm | 61 ++++++++++++ .../circuitboards/machine_circuitboards.dm | 10 +- code/game/objects/items/vending_items.dm | 90 ++++++++++++++++++ code/modules/cargo/packs.dm | 3 +- .../boxes_magazines/external_mag.dm | 11 ++- .../modules/projectiles/guns/ballistic/toy.dm | 14 ++- .../research/designs/machine_designs.dm | 8 ++ icons/obj/vending_restock.dmi | Bin 1343 -> 1454 bytes 8 files changed, 192 insertions(+), 5 deletions(-) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 427bc95253..e65d71e38f 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -1138,6 +1138,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C /obj/item/clothing/ears/headphones = 10) contraband = list(/obj/item/clothing/under/syndicate/tacticool=1, /obj/item/clothing/mask/balaclava=1, /obj/item/clothing/head/ushanka=1, /obj/item/clothing/under/soviet=1, /obj/item/storage/belt/fannypack/black=2, /obj/item/clothing/suit/jacket/letterman_syndie=1, /obj/item/clothing/under/jabroni=1, /obj/item/clothing/suit/vapeshirt=1, /obj/item/clothing/under/geisha=1) premium = list(/obj/item/clothing/under/suit_jacket/checkered=1, /obj/item/clothing/head/mailman=1, /obj/item/clothing/under/rank/mailman=1, /obj/item/clothing/suit/jacket/leather=1, /obj/item/clothing/suit/jacket/leather/overcoat=1, /obj/item/clothing/under/pants/mustangjeans=1, /obj/item/clothing/neck/necklace/dope=3, /obj/item/clothing/suit/jacket/letterman_nanotrasen=1) +<<<<<<< HEAD refill_canister = /obj/item/vending_refill/clothing /obj/machinery/vending/toyliberationstation @@ -1169,3 +1170,63 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C #undef STANDARD_CHARGE #undef CONTRABAND_CHARGE #undef COIN_CHARGE +======= + refill_canister = /obj/item/vending_refill/clothing + +/obj/machinery/vending/toyliberationstation + name = "\improper Syndicate Donksoft Toy Vendor" + desc = "A ages 8 and up approved vendor that dispenses toys. If you were to find the right wires, you can unlock the adult mode setting!" + icon_state = "syndi" + req_access_txt = "1" + product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!" + product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!" + vend_reply = "Come back for more!" + products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10, + /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10, + /obj/item/gun/ballistic/shotgun/toy/unrestricted = 10, + /obj/item/toy/sword = 10, + /obj/item/ammo_box/foambox = 20, + /obj/item/toy/foamblade = 10, + /obj/item/toy/syndicateballoon = 10, + /obj/item/clothing/suit/syndicatefake = 5, + /obj/item/clothing/head/syndicatefake = 5) //OPS IN DORMS oh wait it's just a assistant + contraband = list(/obj/item/gun/ballistic/shotgun/toy/crossbow = 10, //Congrats, you unlocked the +18 setting! + /obj/item/gun/ballistic/automatic/c20r/toy/riot/unrestricted = 10, + /obj/item/gun/ballistic/automatic/l6_saw/toy/riot/unrestricted = 10, + /obj/item/ammo_box/foambox/riot = 20, + /obj/item/toy/katana = 10, + /obj/item/twohanded/dualsaber/toy = 5, + /obj/item/toy/cards/deck/syndicate = 10) //Gambling and it hurts, making it a +18 item + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + refill_canister = /obj/item/vending_refill/donksoft + +/obj/machinery/vending/donksofttoyvendor + name = "\improper Donksoft Toy Vendor" + desc = "Ages 8 and up approved vendor that dispenses toys." + icon_state = "syndi" + product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!" + product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!" + vend_reply = "Come back for more!" + products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10, + /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10, + /obj/item/gun/ballistic/shotgun/toy/unrestricted = 10, + /obj/item/toy/sword = 10, + /obj/item/ammo_box/foambox = 20, + /obj/item/toy/foamblade = 10, + /obj/item/toy/syndicateballoon = 10, + /obj/item/clothing/suit/syndicatefake = 5, + /obj/item/clothing/head/syndicatefake = 5) + contraband = list(/obj/item/gun/ballistic/shotgun/toy/crossbow = 10, + /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted = 10, + /obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted = 10, + /obj/item/toy/katana = 10, + /obj/item/twohanded/dualsaber/toy = 5) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + refill_canister = /obj/item/vending_refill/donksoft + +#undef STANDARD_CHARGE +#undef CONTRABAND_CHARGE +#undef COIN_CHARGE +>>>>>>> 91a9164... Adds Donksoft Toy Vendor (Machine Board) to the Circuit Imprinter (#30531) diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index 645e8c05a3..cbbf1d0cb7 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -720,4 +720,12 @@ /obj/item/stock_parts/matter_bin = 1, /obj/item/stack/cable_coil = 2, /obj/item/stock_parts/console_screen = 1, - /obj/item/stack/sheet/glass = 1) \ No newline at end of file + /obj/item/stack/sheet/glass = 1) + +/obj/item/circuitboard/machine/vending/donksofttoyvendor + name = "Donksoft Toy Vendor (Machine Board)" + build_path = /obj/machinery/vending/donksofttoyvendor + origin_tech = "programming=1;syndicate=2" + req_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/vending_refill/donksoft = 3) diff --git a/code/game/objects/items/vending_items.dm b/code/game/objects/items/vending_items.dm index 3227228127..7837b10939 100644 --- a/code/game/objects/items/vending_items.dm +++ b/code/game/objects/items/vending_items.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /obj/item/vending_refill name = "resupply canister" var/machine_name = "Generic" @@ -79,3 +80,92 @@ icon_state = "refill_medical" charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium init_charges = list(26, 5, 3) +======= +/obj/item/vending_refill + name = "resupply canister" + var/machine_name = "Generic" + + icon = 'icons/obj/vending_restock.dmi' + icon_state = "refill_snack" + item_state = "restock_unit" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + flags_1 = CONDUCT_1 + force = 7 + throwforce = 10 + throw_speed = 1 + throw_range = 7 + w_class = WEIGHT_CLASS_BULKY + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 30) + var/charges = list(0, 0, 0) //how many restocking "charges" the refill has for standard/contraband/coin products + var/init_charges = list(0, 0, 0) + + +/obj/item/vending_refill/New(amt = -1) + ..() + name = "\improper [machine_name] restocking unit" + if(isnum(amt) && amt > -1) + charges[1] = amt + +/obj/item/vending_refill/examine(mob/user) + ..() + if(charges[1] > 0) + to_chat(user, "It can restock [charges[1]+charges[2]+charges[3]] item(s).") + else + to_chat(user, "It's empty!") + +//NOTE I decided to go for about 1/3 of a machine's capacity + +/obj/item/vending_refill/boozeomat + machine_name = "Booze-O-Mat" + icon_state = "refill_booze" + charges = list(54, 4, 0)//of 159 standard, 12 contraband + init_charges = list(54, 4, 0) + +/obj/item/vending_refill/coffee + machine_name = "Solar's Best Hot Drinks" + icon_state = "refill_joe" + charges = list(25, 4, 0)//of 75 standard, 12 contraband + init_charges = list(25, 4, 0) + +/obj/item/vending_refill/snack + machine_name = "Getmore Chocolate Corp" + charges = list(12, 2, 0)//of 36 standard, 6 contraband + init_charges = list(12, 2, 0) + +/obj/item/vending_refill/cola + machine_name = "Robust Softdrinks" + icon_state = "refill_cola" + charges = list(30, 4, 1)//of 90 standard, 12 contraband, 1 premium + init_charges = list(30, 4, 1) + +/obj/item/vending_refill/cigarette + machine_name = "ShadyCigs Deluxe" + icon_state = "refill_smoke" + charges = list(12, 3, 2)// of 36 standard, 9 contraband, 6 premium + init_charges = list(12, 3, 2) + +/obj/item/vending_refill/autodrobe + machine_name = "AutoDrobe" + icon_state = "refill_costume" + charges = list(32, 2, 3)// of 96 standard, 6 contraband, 9 premium + init_charges = list(32, 2, 3) + +/obj/item/vending_refill/clothing + machine_name = "ClothesMate" + icon_state = "refill_clothes" + charges = list(37, 4, 4)// of 111 standard, 12 contraband, 10 premium(?) + init_charges = list(37, 4, 4) + +/obj/item/vending_refill/medical + machine_name = "NanoMed" + icon_state = "refill_medical" + charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium + init_charges = list(26, 5, 3) + +/obj/item/vending_refill/donksoft + machine_name = "Donksoft Toy Vendor" + icon_state = "refill_donksoft" + charges = list(32,28,0)// of 90 standard, 75 contraband, 0 premium + init_charges = list(32,28,0) +>>>>>>> 91a9164... Adds Donksoft Toy Vendor (Machine Board) to the Circuit Imprinter (#30531) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 8bdbc328ad..ba536acdac 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1648,7 +1648,8 @@ /obj/item/stack/tile/fakespace/loaded, /obj/item/gun/ballistic/shotgun/toy/crossbow, /obj/item/toy/redbutton, - /obj/item/toy/eightball) + /obj/item/toy/eightball, + /obj/item/vending_refill/donksoft) crate_name = "toy crate" /datum/supply_pack/misc/autodrobe diff --git a/code/modules/projectiles/boxes_magazines/external_mag.dm b/code/modules/projectiles/boxes_magazines/external_mag.dm index 3bfb90224d..525466be28 100644 --- a/code/modules/projectiles/boxes_magazines/external_mag.dm +++ b/code/modules/projectiles/boxes_magazines/external_mag.dm @@ -324,6 +324,7 @@ /obj/item/ammo_box/magazine/toy/smg name = "foam force SMG magazine" icon_state = "smg9mm-42" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart max_ammo = 20 /obj/item/ammo_box/magazine/toy/smg/update_icon() @@ -348,23 +349,29 @@ /obj/item/ammo_box/magazine/toy/smgm45 name = "donksoft SMG magazine" caliber = "foam_force" - ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot + ammo_type = /obj/item/ammo_casing/caseless/foam_dart max_ammo = 20 /obj/item/ammo_box/magazine/toy/smgm45/update_icon() ..() icon_state = "c20r45-[round(ammo_count(),2)]" +/obj/item/ammo_box/magazine/toy/smgm45/riot + ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot + /obj/item/ammo_box/magazine/toy/m762 name = "donksoft box magazine" caliber = "foam_force" - ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot + ammo_type = /obj/item/ammo_casing/caseless/foam_dart max_ammo = 50 /obj/item/ammo_box/magazine/toy/m762/update_icon() ..() icon_state = "a762-[round(ammo_count(),10)]" +/obj/item/ammo_box/magazine/toy/m762/riot + ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot + diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm index 135540436a..fc1ad963e4 100644 --- a/code/modules/projectiles/guns/ballistic/toy.dm +++ b/code/modules/projectiles/guns/ballistic/toy.dm @@ -89,6 +89,12 @@ /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted pin = /obj/item/device/firing_pin +/obj/item/gun/ballistic/automatic/smgm45/toy/riot + mag_type = /obj/item/ammo_box/magazine/toy/smgm45/riot + +/obj/item/gun/ballistic/automatic/c20r/toy/riot/unrestricted + pin = /obj/item/device/firing_pin + /obj/item/gun/ballistic/automatic/l6_saw/toy name = "donksoft LMG" desc = "A heavily modified toy light machine gun, designated 'L6 SAW'. Ages 8 and up." @@ -99,4 +105,10 @@ casing_ejector = 0 /obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted - pin = /obj/item/device/firing_pin \ No newline at end of file + pin = /obj/item/device/firing_pin + +/obj/item/gun/ballistic/automatic/l6_saw/toy/riot + mag_type = /obj/item/ammo_box/magazine/toy/m762/riot + +/obj/item/gun/ballistic/automatic/l6_saw/toy/riot/unrestricted + pin = /obj/item/device/firing_pin diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index cee8167666..bb2887e2a1 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -418,3 +418,11 @@ req_tech = list("programming" = 1) build_path = /obj/item/circuitboard/machine/deep_fryer category = list ("Misc. Machinery") + +/datum/design/board/donksofttoyvendor + name = "Machine Design (Donksoft Toy Vendor Board)" + desc = "The circuit board for a Donksoft Toy Vendor." + id = "donksofttoyvendor" + req_tech = list("programming" = 1, "syndicate" = 2) + build_path = /obj/item/circuitboard/machine/vending/donksofttoyvendor + category = list ("Misc. Machinery") diff --git a/icons/obj/vending_restock.dmi b/icons/obj/vending_restock.dmi index eac7b8a266846d2499b22b5b6e97f7af561cf82d..7f8289a0877ff2bd07cb43f6ce9f4a87438919a6 100644 GIT binary patch delta 1220 zcmV;#1Uvh`3a$%~Bmw!6C6`EZb904-g_M+(#Fb#Oi&E@fIA+W<{{R300000pGnoJY z|7QO)0RR7)GiGKp0RJ<{4L8HTui_3W+1c5vtE)afKCKHe|Nk?Q=^hn4(ms^{0004W zQchCy3`3+~O1nNB-q&)eg<)mv8?pj1=T=e>dO&00Xf}L_t(& zf$fzvxj7>vqc@d+a_~a|FS?%bawd!aD=E2MsW^_K<}Q=w`j1re9xAE0Q>oat z?I^ilWpV-kl*wYEfA#a<0C2~#KVuDd7pgv181PkS-cuNG?$}6Sz`45s3~)Iowgs%? z4sx{Icgw(_HvI)^m>v<P-O-( zUiaPfdfJ1MVBpR38T>SG=KvbOf4hhmp!a_zJwm&{06quM zKz>B@`LbVopf#X9fCko-*b(89$e97>jxFQ#8Fo1rdQhq@z3S@{Jp!!fj-2~$%6%Wc zifYSKs$o1MhxOs34zHh?&;GJ6;6_G9Mn?aQW_{&bK*IHJ!O~+2)cHPaps*1FZoTo9 z)wQ*?vZcJff0-xl)q&+hHzyT6s?EujuCkFUTJe zB^ zEtvtW8e|567;d+Bc6PQor#+B_-wrLo`Q{c9(>2Z4e@)Nh3uq6-0=s*Ad;94QP$=?F zrxPS+P{UiOD>XRq4$}ND^ne-cQ>7d{2aI<*nFHnBLz%%r^T5;eV0s5_`3^ei4!Va& zviX1=5zqHx57_5)1L^$GXvyXSX2AL3kv!iwy)@s`9!U7^?rzG%g82c~7xTYY!2fc7 zF!OK`9lD&GImr}YO) zPRMz5@$(Gue7>jkd%FB@Q3ow25y1)rzUsKA&;Nry*79Ew*3Sn$bg9k%13c7nf=R)A zaCxQ8|9IGya6(ANNhFEy`1<$th-c5ss~c_pe;;;-A}6=Ew}f+YD(s+MAIGEXQ9Mo- zT-`{2ADB#116p6;w0^`LYWRX+FXXbM$_&mTVF#A=yd3Yx%g;%^ zQh#`q<$r53N#}#=lfcRA2B^U~>;cR7@TbA^S4l$4ajm0+@qQtVzh|7QQl4L8HTui_3W z+1c5vtE)afKCKHeDJdyhT3TJ1z8pAjy}i9BKaUnHR>na97Z(>WFfighTFU?c00DGT zPE!Ct=GbNc005wqHvuhwW^B@dOjPjn2D=m??%o?d-ezibY`cC?&8e3Uh>SF=gW9jw zQasTnm&3fH`x0M3z(a{@SbcR&ECX2h02bR1!%<-S`50rkx< zP$zVYh>l|$X}KS`Frcv^YEbitjw2}`1-rX~OEZ85@Gj!~JJl*c#T&jWuBS7oNC94r z-=ORR@GcSoj=r@Z?BbjN&f6`lKOcDE zp|<}=IMVVKKGL5LFqnbFyG{N1;pkXd-@{PUZ#V;3@8Jv}KRP~91yI*;6%fkh_Vn!R z?38ml14a4mQwz?IPq5ssX}|7x9{&KHfow21KR>^J5G%lu%=`U*nC?NHoZz7{VC0QN z|CeUK0xqZo2hRcH{r)O}^5LZ_VAL6Tni*`apr>9zU#wtwd8IlZur1>KUY-H_J6(V{ zKQz0l^8pLs{PIfO?>nC8_jCpdJ{SxHj|$EY&|mKVUI8z8elX_)BO@atqrax2eqY23 z{ny2Ray+@dz8+h-d^-C%o6brmK>x|a%Hz{tQ|ezb0Q7t6Ki2hsizbjfuYv&XG8yap z|7=Ri1;Bnk#y8sjKO^&!0kGfS+-mzjnGeeb&`L?}e%~#4_q@5i*Y^MUu=ENVjb*&J zTg1!M;Pzhm|A8bC0o1=-_hAN$IA%Yo!99L`&<4!O;|Bs3G+@C4@WYcFkfcgEc?`-2 zusuq5h#EXRJ!=CVgO{=ami4+HU&Q;bX}^DZR`q`?NyPaecqusp*6)|`+wv`5rv3g| z-T#wB^#8K{yx%XGKG^>Y1Geq|g#o7j8~xAv14w70nwsEWfB*mh07*qoM6N<$f^Xk5 A1ONa4 From adc85f0edca5f9bd267692a0fad2c2488939538f Mon Sep 17 00:00:00 2001 From: oranges Date: Sun, 10 Sep 2017 21:00:32 +1000 Subject: [PATCH 023/102] In which smartfridge ui_data is called only when needed, and a minor display bug involving drying racks is fixed --- .../kitchen_machinery/smartfridge.dm | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index e996429939..491da12a81 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -150,6 +150,7 @@ if(stat) return FALSE +<<<<<<< HEAD var/dat = "Select an item:
    " if (contents.len == 0) @@ -189,6 +190,39 @@ /obj/machinery/smartfridge/Topic(var/href, var/list/href_list) if(..()) +======= +/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "smartvend", name, 440, 550, master_ui, state) + ui.set_autoupdate(FALSE) + ui.open() + +/obj/machinery/smartfridge/ui_data(mob/user) + . = list() + + var/listofitems = list() + for (var/I in src) + var/atom/movable/O = I + if (!QDELETED(O)) + if (listofitems[O.name]) + listofitems[O.name]["amount"]++ + else + listofitems[O.name] = list("name" = O.name, "type" = O.type, "amount" = 1) + sortList(listofitems) + + .["contents"] = listofitems + .["name"] = name + .["isdryer"] = FALSE + + +/obj/machinery/smartfridge/handle_atom_del(atom/A) // Update the UIs in case something inside gets deleted + SStgui.update_uis(src) + +/obj/machinery/smartfridge/ui_act(action, params) + . = ..() + if(.) +>>>>>>> 5f6b2a9... Merge pull request #30519 from vuonojenmustaturska/smartfridges2electricboogaloo return usr.set_machine(src) @@ -240,6 +274,7 @@ /obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(obj/item/crowbar/C, ignore_panel = 1) ..() +<<<<<<< HEAD /obj/machinery/smartfridge/drying_rack/interact(mob/user) var/dat = ..() if(dat) @@ -254,6 +289,25 @@ toggle_drying(FALSE) updateUsrDialog() update_icon() +======= +/obj/machinery/smartfridge/drying_rack/ui_data(mob/user) + . = ..() + .["isdryer"] = TRUE + .["verb"] = "Take" + .["drying"] = drying + + +/obj/machinery/smartfridge/drying_rack/ui_act(action, params) + . = ..() + if(.) + update_icon() // This is to handle a case where the last item is taken out manually instead of through drying pop-out + return + switch(action) + if("Dry") + toggle_drying(FALSE) + return TRUE + return FALSE +>>>>>>> 5f6b2a9... Merge pull request #30519 from vuonojenmustaturska/smartfridges2electricboogaloo /obj/machinery/smartfridge/drying_rack/power_change() if(powered() && anchored) @@ -279,6 +333,7 @@ ..() if(drying) if(rack_dry())//no need to update unless something got dried + SStgui.update_uis(src) update_icon() /obj/machinery/smartfridge/drying_rack/accept_check(obj/item/O) From 0e24ac55a545713f9290e5a2d0c9fb6be3ab41e6 Mon Sep 17 00:00:00 2001 From: Leo Date: Sun, 10 Sep 2017 11:35:13 -0300 Subject: [PATCH 024/102] Merge pull request #30558 from Cyberboss/IFUCKINGHATETHISGODAMNSTUPIDASSFILE Adds href tokens to topic.dm --- code/modules/admin/topic.dm | 116 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index f7b0f8b6ff..8f29176568 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -604,15 +604,15 @@ //Regular jobs //Command (Blue) dat += "" - dat += "" + dat += "" for(var/jobPos in GLOB.command_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 6) //So things dont get squiiiiished! @@ -623,15 +623,15 @@ //Security (Red) counter = 0 dat += "
    Command Positions
    Command Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.security_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get squiiiiished! @@ -642,15 +642,15 @@ //Engineering (Yellow) counter = 0 dat += "
    Security Positions
    Security Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.engineering_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get squiiiiished! @@ -661,15 +661,15 @@ //Medical (White) counter = 0 dat += "
    Engineering Positions
    Engineering Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.medical_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get squiiiiished! @@ -680,15 +680,15 @@ //Science (Purple) counter = 0 dat += "
    Medical Positions
    Medical Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.science_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get squiiiiished! @@ -699,15 +699,15 @@ //Supply (Brown) counter = 0 dat += "
    Science Positions
    Science Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.supply_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get COPYPASTE! @@ -718,15 +718,15 @@ //Civilian (Grey) counter = 0 dat += "
    Supply Positions
    Supply Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.civilian_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get squiiiiished! @@ -737,15 +737,15 @@ //Non-Human (Green) counter = 0 dat += "
    Civilian Positions
    Civilian Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" for(var/jobPos in GLOB.nonhuman_positions) if(!jobPos) continue if(jobban_isbanned(M, jobPos)) - dat += "" + dat += "" counter++ else - dat += "" + dat += "" counter++ if(counter >= 5) //So things dont get squiiiiished! @@ -756,71 +756,71 @@ //Ghost Roles (light light gray) dat += "
    Non-human Positions
    Non-human Positions
    [jobPos][jobPos][jobPos][jobPos]
    " - dat += "" + dat += "" //pAI if(jobban_isbanned(M, "pAI")) - dat += "" + dat += "" else - dat += "" + dat += "" //Drones if(jobban_isbanned(M, "drone")) - dat += "" + dat += "" else - dat += "" + dat += "" //Positronic Brains if(jobban_isbanned(M, "posibrain")) - dat += "" + dat += "" else - dat += "" + dat += "" //Deathsquad if(jobban_isbanned(M, "deathsquad")) - dat += "" + dat += "" else - dat += "" + dat += "" //Lavaland roles if(jobban_isbanned(M, "lavaland")) - dat += "" + dat += "" else - dat += "" + dat += "" dat += "
    Ghost Roles
    Ghost Roles
    pAIpAIpAIpAIDroneDroneDroneDronePosibrainPosibrainPosibrainPosibrainDeathsquadDeathsquadDeathsquadDeathsquadLavalandLavalandLavalandLavaland
    " //Antagonist (Orange) var/isbanned_dept = jobban_isbanned(M, "Syndicate") dat += "" - dat += "" + dat += "" //Traitor if(jobban_isbanned(M, "traitor") || isbanned_dept) - dat += "" + dat += "" else dat += "" //Changeling if(jobban_isbanned(M, "changeling") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Nuke Operative if(jobban_isbanned(M, "operative") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Revolutionary if(jobban_isbanned(M, "revolutionary") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Gangster if(jobban_isbanned(M, "gangster") || isbanned_dept) @@ -832,27 +832,27 @@ //Cultist if(jobban_isbanned(M, "cultist") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Servant of Ratvar if(jobban_isbanned(M, "servant of Ratvar") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Wizard if(jobban_isbanned(M, "wizard") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Abductor if(jobban_isbanned(M, "abductor") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" //Borer if(jobban_isbanned(M, "borer") || isbanned_dept) @@ -862,9 +862,9 @@ //Alien if(jobban_isbanned(M, "alien candidate") || isbanned_dept) - dat += "" + dat += "" else - dat += "" + dat += "" dat += "
    Antagonist Positions
    Antagonist Positions
    TraitorTraitorTraitorChangelingChangelingChangelingChangelingNuke OperativeNuke OperativeNuke OperativeNuke OperativeRevolutionaryRevolutionaryRevolutionaryRevolutionaryCultistCultistCultistCultistServantServantServantServantWizardWizardWizardWizardAbductorAbductorAbductorAbductorAlienAlienAlienAlien
    " usr << browse(dat, "window=jobban2;size=800x450") @@ -1207,9 +1207,9 @@ return alert(usr, "The game has already started.", null, null, null, null) var/dat = {"What mode do you wish to play?
    "} for(var/mode in config.modes) - dat += {"[config.mode_names[mode]]
    "} - dat += {"Secret
    "} - dat += {"Random
    "} + dat += {"[config.mode_names[mode]]
    "} + dat += {"Secret
    "} + dat += {"Random
    "} dat += {"Now: [GLOB.master_mode]"} usr << browse(dat, "window=c_mode") @@ -1223,8 +1223,8 @@ return alert(usr, "The game mode has to be secret!", null, null, null, null) var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret.
    "} for(var/mode in config.modes) - dat += {"[config.mode_names[mode]]
    "} - dat += {"Random (default)
    "} + dat += {"[config.mode_names[mode]]
    "} + dat += {"Random (default)
    "} dat += {"Now: [GLOB.secret_force_mode]"} usr << browse(dat, "window=f_secret") From 33f35fe4d2c895ecefa4970c2d25cf303c63951d Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 10 Sep 2017 11:46:34 -0500 Subject: [PATCH 026/102] Update tools.dm --- code/game/objects/items/tools.dm | 1583 +++++++++++++++--------------- 1 file changed, 790 insertions(+), 793 deletions(-) diff --git a/code/game/objects/items/tools.dm b/code/game/objects/items/tools.dm index 0e557497c0..5c901ca4bd 100644 --- a/code/game/objects/items/tools.dm +++ b/code/game/objects/items/tools.dm @@ -1,795 +1,793 @@ -<<<<<<< HEAD -#define WELDER_FUEL_BURN_INTERVAL 13 - -/* Tools! - * Note: Multitools are /obj/item/device - * - * Contains: - * Wrench - * Screwdriver - * Wirecutters - * Welding Tool - * Crowbar - */ - -/* - * Wrench - */ -/obj/item/wrench - name = "wrench" - desc = "A wrench with common uses. Can be found in your hand." - icon = 'icons/obj/tools.dmi' - icon_state = "wrench" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - usesound = 'sound/items/ratchet.ogg' - materials = list(MAT_METAL=150) - origin_tech = "materials=1;engineering=1" - attack_verb = list("bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/wrench/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wrench/cyborg - name = "automatic wrench" - desc = "An advanced robotic wrench. Can be found in construction cyborgs." - toolspeed = 0.5 - -/obj/item/wrench/brass - name = "brass wrench" - desc = "A brass wrench. It's faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "wrench_brass" - toolspeed = 0.5 - -/obj/item/wrench/abductor - name = "alien wrench" - desc = "A polarized wrench. It causes anything placed between the jaws to turn." - icon = 'icons/obj/abductor.dmi' - icon_state = "wrench" - usesound = 'sound/effects/empulse.ogg' - toolspeed = 0.1 - origin_tech = "materials=5;engineering=5;abductor=3" - -/obj/item/wrench/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a bolt bit." - icon_state = "drill_bolt" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/drill_use.ogg' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - attack_verb = list("drilled", "screwed", "jabbed") - toolspeed = 0.25 - -/obj/item/wrench/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power - to_chat(user, "You attach the screw driver bit to [src].") - qdel(src) - user.put_in_active_hand(s_drill) - -/obj/item/wrench/power/suicide_act(mob/user) - user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/wrench/medical - name = "medical wrench" - desc = "A medical wrench with common(medical?) uses. Can be found in your hand." - icon_state = "wrench_medical" - force = 2 //MEDICAL - throwforce = 4 - origin_tech = "materials=1;engineering=1;biotech=3" - attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") - -/obj/item/wrench/medical/suicide_act(mob/living/user) - user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") - // TODO Make them glow with the power of the M E D I C A L W R E N C H - // during their ascension - - // Stun stops them from wandering off - user.Stun(100, ignore_canstun = TRUE) - playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) - - // Let the sound effect finish playing - sleep(20) - - if(!user) - return - - for(var/obj/item/W in user) - user.dropItemToGround(W) - - var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) - W.add_fingerprint(user) - W.desc += " For some reason, it reminds you of [user.name]." - - if(!user) - return - - user.dust() - - return OXYLOSS - -/* - * Screwdriver - */ -/obj/item/screwdriver - name = "screwdriver" - desc = "You can be totally screwy with this." - icon = 'icons/obj/tools.dmi' - icon_state = "screwdriver" - item_state = "screwdriver" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - w_class = WEIGHT_CLASS_TINY - throwforce = 5 - throw_speed = 3 - throw_range = 5 - materials = list(MAT_METAL=75) - attack_verb = list("stabbed") - hitsound = 'sound/weapons/bladeslice.ogg' - usesound = 'sound/items/screwdriver.ogg' - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - var/random_color = TRUE //if the screwdriver uses random coloring - var/static/list/screwdriver_colors = list(\ - "blue" = rgb(24, 97, 213), \ - "red" = rgb(149, 23, 16), \ - "pink" = rgb(213, 24, 141), \ - "brown" = rgb(160, 82, 18), \ - "green" = rgb(14, 127, 27), \ - "cyan" = rgb(24, 162, 213), \ - "yellow" = rgb(213, 140, 24), \ - ) - -/obj/item/screwdriver/suicide_act(mob/user) - user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/Initialize() - . = ..() - if(random_color) //random colors! - var/our_color = pick(screwdriver_colors) - add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) - update_icon() - if(prob(75)) - pixel_y = rand(0, 16) - -/obj/item/screwdriver/update_icon() - if(!random_color) //icon override - return - cut_overlays() - var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") - base_overlay.appearance_flags = RESET_COLOR - add_overlay(base_overlay) - -/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) - . = list() - if(isinhands && random_color) - var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") - M.appearance_flags = RESET_COLOR - . += M - -/obj/item/screwdriver/get_belt_overlay() - if(random_color) - var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") - var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") - body.color = color - head.overlays += body - return head - else - return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) - -/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M)) - return ..() - if(user.zone_selected != "eyes" && user.zone_selected != "head") - return ..() - if(user.disabilities & CLUMSY && prob(50)) - M = user - return eyestab(M,user) - -/obj/item/screwdriver/brass - name = "brass screwdriver" - desc = "A screwdriver made of brass. The handle feels freezing cold." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "screwdriver_brass" - item_state = "screwdriver_brass" - toolspeed = 0.5 - random_color = FALSE - -/obj/item/screwdriver/abductor - name = "alien screwdriver" - desc = "An ultrasonic screwdriver." - icon = 'icons/obj/abductor.dmi' - icon_state = "screwdriver_a" - item_state = "screwdriver_nuke" - usesound = 'sound/items/pshoom.ogg' - toolspeed = 0.1 - random_color = FALSE - -/obj/item/screwdriver/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a screw bit." - icon_state = "drill_screw" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - throw_speed = 2 - throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far - attack_verb = list("drilled", "screwed", "jabbed","whacked") - hitsound = 'sound/items/drill_hit.ogg' - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.25 - random_color = FALSE - -/obj/item/screwdriver/power/suicide_act(mob/user) - user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power - to_chat(user, "You attach the bolt driver bit to [src].") - qdel(src) - user.put_in_active_hand(b_drill) - -/obj/item/screwdriver/cyborg - name = "powered screwdriver" - desc = "An electrical screwdriver, designed to be both precise and quick." - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.5 - -/* - * Wirecutters - */ -/obj/item/wirecutters - name = "wirecutters" - desc = "This cuts wires." - icon = 'icons/obj/tools.dmi' - icon_state = null - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 6 - throw_speed = 3 - throw_range = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=80) - attack_verb = list("pinched", "nipped") - hitsound = 'sound/items/wirecutter.ogg' - usesound = 'sound/items/wirecutter.ogg' - origin_tech = "materials=1;engineering=1" - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - - -/obj/item/wirecutters/New(loc, var/param_color = null) - ..() - if(!icon_state) - if(!param_color) - param_color = pick("yellow","red") - icon_state = "cutters_[param_color]" - -/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) - if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) - user.visible_message("[user] cuts [C]'s restraints with [src]!") - qdel(C.handcuffed) - C.handcuffed = null - if(C.buckled && C.buckled.buckle_requires_restraints) - C.buckled.unbuckle_mob(C) - C.update_handcuffed() - return - else - ..() - -/obj/item/wirecutters/suicide_act(mob/user) - user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, usesound, 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/brass - name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" - toolspeed = 0.5 - -/obj/item/wirecutters/abductor - name = "alien wirecutters" - desc = "Extremely sharp wirecutters, made out of a silvery-green metal." - icon = 'icons/obj/abductor.dmi' - icon_state = "cutters" - toolspeed = 0.1 - origin_tech = "materials=5;engineering=4;abductor=3" - -/obj/item/wirecutters/cyborg - name = "wirecutters" - desc = "This cuts wires." - toolspeed = 0.5 - -/obj/item/wirecutters/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." - icon_state = "jaws_cutter" - item_state = "jawsoflife" - origin_tech = "materials=2;engineering=2" - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - usesound = 'sound/items/jaws_cut.ogg' - toolspeed = 0.25 - -/obj/item/wirecutters/power/suicide_act(mob/user) - user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") - playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/bodypart/BP = C.get_bodypart("head") - if(BP) - BP.drop_limb() - playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power - to_chat(user, "You attach the pry jaws to [src].") - qdel(src) - user.put_in_active_hand(pryjaws) -/* - * Welding Tool - */ -/obj/item/weldingtool - name = "welding tool" - desc = "A standard edition welder provided by NanoTrasen." - icon = 'icons/obj/tools.dmi' - icon_state = "welder" - item_state = "welder" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 3 - throwforce = 5 - hitsound = "swing_hit" - usesound = 'sound/items/welder.ogg' - var/acti_sound = 'sound/items/welderactivate.ogg' - var/deac_sound = 'sound/items/welderdeactivate.ogg' - throw_speed = 3 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) - resistance_flags = FIRE_PROOF - - materials = list(MAT_METAL=70, MAT_GLASS=30) - origin_tech = "engineering=1;plasmatech=1" - var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) - var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) - var/max_fuel = 20 //The max amount of fuel the welder can hold - var/change_icons = 1 - var/can_off_process = 0 - var/light_intensity = 2 //how powerful the emitted light is when used. - var/burned_fuel_for = 0 //when fuel was last removed - heat = 3800 - toolspeed = 1 - -/obj/item/weldingtool/Initialize() - . = ..() - create_reagents(max_fuel) - reagents.add_reagent("welding_fuel", max_fuel) - update_icon() - - -/obj/item/weldingtool/proc/update_torch() - if(welding) - add_overlay("[initial(icon_state)]-on") - item_state = "[initial(item_state)]1" - else - item_state = "[initial(item_state)]" - - -/obj/item/weldingtool/update_icon() - cut_overlays() - if(change_icons) - var/ratio = get_fuel() / max_fuel - ratio = Ceiling(ratio*4) * 25 - add_overlay("[initial(icon_state)][ratio]") - update_torch() - return - - -/obj/item/weldingtool/process() - switch(welding) - if(0) - force = 3 - damtype = "brute" - update_icon() - if(!can_off_process) - STOP_PROCESSING(SSobj, src) - return - //Welders left on now use up fuel, but lets not have them run out quite that fast - if(1) - force = 15 - damtype = "fire" - ++burned_fuel_for - if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) - remove_fuel(1) - update_icon() - - //This is to start fires. process() is only called if the welder is on. - open_flame() - - -/obj/item/weldingtool/suicide_act(mob/user) - user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") - return (FIRELOSS) - - -/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) - flamethrower_screwdriver(I, user) - else if(istype(I, /obj/item/stack/rods)) - flamethrower_rods(I, user) - else - return ..() - - -/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) - if(!istype(H)) - return ..() - - var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - - if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) - if(src.remove_fuel(1)) - playsound(loc, usesound, 50, 1) - if(user == H) - user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") - if(!do_mob(user, H, 50)) - return - item_heal_robotic(H, user, 15, 0) - else - return ..() - - -/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) - if(!proximity) return - - if(welding) - remove_fuel(1) - var/turf/location = get_turf(user) - location.hotspot_expose(700, 50, 1) - if(get_fuel() <= 0) - set_light(0) - - if(isliving(O)) - var/mob/living/L = O - if(L.IgniteMob()) - message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") - log_game("[key_name(user)] set [key_name(L)] on fire") - - -/obj/item/weldingtool/attack_self(mob/user) - switched_on(user) - if(welding) - set_light(light_intensity) - - update_icon() - - -//Returns the amount of fuel in the welder -/obj/item/weldingtool/proc/get_fuel() - return reagents.get_reagent_amount("welding_fuel") - - -//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() -/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) - if(!welding || !check_fuel()) - return 0 - if(amount) - burned_fuel_for = 0 - if(get_fuel() >= amount) - reagents.remove_reagent("welding_fuel", amount) - check_fuel() - if(M) - M.flash_act(light_intensity) - return TRUE - else - if(M) - to_chat(M, "You need more welding fuel to complete this task!") - return FALSE - - -//Turns off the welder if there is no more fuel (does this really need to be its own proc?) -/obj/item/weldingtool/proc/check_fuel(mob/user) - if(get_fuel() <= 0 && welding) - switched_on(user) - update_icon() - //mob icon update - if(ismob(loc)) - var/mob/M = loc - M.update_inv_hands(0) - - return 0 - return 1 - -//Switches the welder on -/obj/item/weldingtool/proc/switched_on(mob/user) - if(!status) - to_chat(user, "[src] can't be turned on while unsecured!") - return - welding = !welding - if(welding) - if(get_fuel() >= 1) - to_chat(user, "You switch [src] on.") - playsound(loc, acti_sound, 50, 1) - force = 15 - damtype = "fire" - hitsound = 'sound/items/welder.ogg' - update_icon() - START_PROCESSING(SSobj, src) - else - to_chat(user, "You need more fuel!") - switched_off(user) - else - to_chat(user, "You switch [src] off.") - playsound(loc, deac_sound, 50, 1) - switched_off(user) - -//Switches the welder off -/obj/item/weldingtool/proc/switched_off(mob/user) - welding = 0 - set_light(0) - - force = 3 - damtype = "brute" - hitsound = "swing_hit" - update_icon() - - -/obj/item/weldingtool/examine(mob/user) - ..() - to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") - -/obj/item/weldingtool/is_hot() - return welding * heat - -//Returns whether or not the welding tool is currently on. -/obj/item/weldingtool/proc/isOn() - return welding - - -/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) - if(welding) - to_chat(user, "Turn it off first!") - return - status = !status - if(status) - to_chat(user, "You resecure [src].") - else - to_chat(user, "[src] can now be attached and modified.") - add_fingerprint(user) - -/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) - if(!status) - var/obj/item/stack/rods/R = I - if (R.use(1)) - var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) - if(!remove_item_from_storage(F)) - user.transferItemToLoc(src, F, TRUE) - F.weldtool = src - add_fingerprint(user) - to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") - user.put_in_hands(F) - else - to_chat(user, "You need one rod to start building a flamethrower!") - -/obj/item/weldingtool/ignition_effect(atom/A, mob/user) - if(welding && remove_fuel(1, user)) - . = "[user] casually lights [A] with [src], what a badass." - else - . = "" - -/obj/item/weldingtool/largetank - name = "industrial welding tool" - desc = "A slightly larger welder with a larger tank." - icon_state = "indwelder" - max_fuel = 40 - materials = list(MAT_GLASS=60) - origin_tech = "engineering=2;plasmatech=2" - -/obj/item/weldingtool/largetank/cyborg - name = "integrated welding tool" - desc = "An advanced welder designed to be used in robotic systems." - toolspeed = 0.5 - -/obj/item/weldingtool/largetank/flamethrower_screwdriver() - return - - -/obj/item/weldingtool/mini - name = "emergency welding tool" - desc = "A miniature welder used during emergencies." - icon_state = "miniwelder" - max_fuel = 10 - w_class = WEIGHT_CLASS_TINY - materials = list(MAT_METAL=30, MAT_GLASS=10) - change_icons = 0 - -/obj/item/weldingtool/mini/flamethrower_screwdriver() - return - -/obj/item/weldingtool/abductor - name = "alien welding tool" - desc = "An alien welding tool. Whatever fuel it uses, it never runs out." - icon = 'icons/obj/abductor.dmi' - icon_state = "welder" - toolspeed = 0.1 - light_intensity = 0 - change_icons = 0 - origin_tech = "plasmatech=5;engineering=5;abductor=3" - -/obj/item/weldingtool/abductor/process() - if(get_fuel() <= max_fuel) - reagents.add_reagent("welding_fuel", 1) - ..() - -/obj/item/weldingtool/hugetank - name = "upgraded industrial welding tool" - desc = "An upgraded welder based of the industrial welder." - icon_state = "upindwelder" - item_state = "upindwelder" - max_fuel = 80 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "engineering=3;plasmatech=2" - -/obj/item/weldingtool/experimental - name = "experimental welding tool" - desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." - icon_state = "exwelder" - item_state = "exwelder" - max_fuel = 40 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" - var/last_gen = 0 - change_icons = 0 - can_off_process = 1 - light_intensity = 1 - toolspeed = 0.5 - var/nextrefueltick = 0 - -/obj/item/weldingtool/experimental/brass - name = "brass welding tool" - desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "brasswelder" - item_state = "brasswelder" - - -/obj/item/weldingtool/experimental/process() - ..() - if(get_fuel() < max_fuel && nextrefueltick < world.time) - nextrefueltick = world.time + 10 - reagents.add_reagent("welding_fuel", 1) - - -/* - * Crowbar - */ - -/obj/item/crowbar - name = "pocket crowbar" - desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." - icon = 'icons/obj/tools.dmi' - icon_state = "crowbar" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/crowbar.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - origin_tech = "engineering=1;combat=1" - attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/crowbar/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/red - icon_state = "crowbar_red" - force = 8 - -/obj/item/crowbar/brass - name = "brass crowbar" - desc = "A brass crowbar. It feels faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "crowbar_brass" - toolspeed = 0.5 - -/obj/item/crowbar/abductor - name = "alien crowbar" - desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." - icon = 'icons/obj/abductor.dmi' - usesound = 'sound/weapons/sonic_jackhammer.ogg' - icon_state = "crowbar" - toolspeed = 0.1 - origin_tech = "combat=4;engineering=4;abductor=3" - -/obj/item/crowbar/large - name = "crowbar" - desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." - force = 12 - w_class = WEIGHT_CLASS_NORMAL - throw_speed = 3 - throw_range = 3 - materials = list(MAT_METAL=70) - icon_state = "crowbar_large" - item_state = "crowbar" - toolspeed = 0.5 - -/obj/item/crowbar/cyborg - name = "hydraulic crowbar" - desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." - usesound = 'sound/items/jaws_pry.ogg' - force = 10 - toolspeed = 0.5 - -/obj/item/crowbar/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." - icon_state = "jaws_pry" - item_state = "jawsoflife" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" - usesound = 'sound/items/jaws_pry.ogg' - force = 15 - toolspeed = 0.25 - -/obj/item/crowbar/power/suicide_act(mob/user) - user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power - to_chat(user, "You attach the cutting jaws to [src].") - qdel(src) - user.put_in_active_hand(cutjaws) - -#undef WELDER_FUEL_BURN_INTERVAL -======= +#define WELDER_FUEL_BURN_INTERVAL 13 + +/* Tools! + * Note: Multitools are /obj/item/device + * + * Contains: + * Wrench + * Screwdriver + * Wirecutters + * Welding Tool + * Crowbar + */ + +/* + * Wrench + */ +/obj/item/wrench + name = "wrench" + desc = "A wrench with common uses. Can be found in your hand." + icon = 'icons/obj/tools.dmi' + icon_state = "wrench" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + usesound = 'sound/items/ratchet.ogg' + materials = list(MAT_METAL=150) + origin_tech = "materials=1;engineering=1" + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/wrench/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wrench/cyborg + name = "automatic wrench" + desc = "An advanced robotic wrench. Can be found in construction cyborgs." + toolspeed = 0.5 + +/obj/item/wrench/brass + name = "brass wrench" + desc = "A brass wrench. It's faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "wrench_brass" + toolspeed = 0.5 + +/obj/item/wrench/abductor + name = "alien wrench" + desc = "A polarized wrench. It causes anything placed between the jaws to turn." + icon = 'icons/obj/abductor.dmi' + icon_state = "wrench" + usesound = 'sound/effects/empulse.ogg' + toolspeed = 0.1 + origin_tech = "materials=5;engineering=5;abductor=3" + +/obj/item/wrench/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a bolt bit." + icon_state = "drill_bolt" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/drill_use.ogg' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + attack_verb = list("drilled", "screwed", "jabbed") + toolspeed = 0.25 + +/obj/item/wrench/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power + to_chat(user, "You attach the screw driver bit to [src].") + qdel(src) + user.put_in_active_hand(s_drill) + +/obj/item/wrench/power/suicide_act(mob/user) + user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/wrench/medical + name = "medical wrench" + desc = "A medical wrench with common(medical?) uses. Can be found in your hand." + icon_state = "wrench_medical" + force = 2 //MEDICAL + throwforce = 4 + origin_tech = "materials=1;engineering=1;biotech=3" + attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") + +/obj/item/wrench/medical/suicide_act(mob/living/user) + user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") + // TODO Make them glow with the power of the M E D I C A L W R E N C H + // during their ascension + + // Stun stops them from wandering off + user.Stun(100, ignore_canstun = TRUE) + playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) + + // Let the sound effect finish playing + sleep(20) + + if(!user) + return + + for(var/obj/item/W in user) + user.dropItemToGround(W) + + var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) + W.add_fingerprint(user) + W.desc += " For some reason, it reminds you of [user.name]." + + if(!user) + return + + user.dust() + + return OXYLOSS + +/* + * Screwdriver + */ +/obj/item/screwdriver + name = "screwdriver" + desc = "You can be totally screwy with this." + icon = 'icons/obj/tools.dmi' + icon_state = "screwdriver" + item_state = "screwdriver" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + w_class = WEIGHT_CLASS_TINY + throwforce = 5 + throw_speed = 3 + throw_range = 5 + materials = list(MAT_METAL=75) + attack_verb = list("stabbed") + hitsound = 'sound/weapons/bladeslice.ogg' + usesound = 'sound/items/screwdriver.ogg' + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + var/random_color = TRUE //if the screwdriver uses random coloring + var/static/list/screwdriver_colors = list(\ + "blue" = rgb(24, 97, 213), \ + "red" = rgb(149, 23, 16), \ + "pink" = rgb(213, 24, 141), \ + "brown" = rgb(160, 82, 18), \ + "green" = rgb(14, 127, 27), \ + "cyan" = rgb(24, 162, 213), \ + "yellow" = rgb(213, 140, 24), \ + ) + +/obj/item/screwdriver/suicide_act(mob/user) + user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/Initialize() + . = ..() + if(random_color) //random colors! + var/our_color = pick(screwdriver_colors) + add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) + update_icon() + if(prob(75)) + pixel_y = rand(0, 16) + +/obj/item/screwdriver/update_icon() + if(!random_color) //icon override + return + cut_overlays() + var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") + base_overlay.appearance_flags = RESET_COLOR + add_overlay(base_overlay) + +/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) + . = list() + if(isinhands && random_color) + var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") + M.appearance_flags = RESET_COLOR + . += M + +/obj/item/screwdriver/get_belt_overlay() + if(random_color) + var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") + var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") + body.color = color + head.overlays += body + return head + else + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) + +/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) + if(!istype(M)) + return ..() + if(user.zone_selected != "eyes" && user.zone_selected != "head") + return ..() + if(user.disabilities & CLUMSY && prob(50)) + M = user + return eyestab(M,user) + +/obj/item/screwdriver/brass + name = "brass screwdriver" + desc = "A screwdriver made of brass. The handle feels freezing cold." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "screwdriver_brass" + item_state = "screwdriver_brass" + toolspeed = 0.5 + random_color = FALSE + +/obj/item/screwdriver/abductor + name = "alien screwdriver" + desc = "An ultrasonic screwdriver." + icon = 'icons/obj/abductor.dmi' + icon_state = "screwdriver_a" + item_state = "screwdriver_nuke" + usesound = 'sound/items/pshoom.ogg' + toolspeed = 0.1 + random_color = FALSE + +/obj/item/screwdriver/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a screw bit." + icon_state = "drill_screw" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + throw_speed = 2 + throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far + attack_verb = list("drilled", "screwed", "jabbed","whacked") + hitsound = 'sound/items/drill_hit.ogg' + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.25 + random_color = FALSE + +/obj/item/screwdriver/power/suicide_act(mob/user) + user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power + to_chat(user, "You attach the bolt driver bit to [src].") + qdel(src) + user.put_in_active_hand(b_drill) + +/obj/item/screwdriver/cyborg + name = "powered screwdriver" + desc = "An electrical screwdriver, designed to be both precise and quick." + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.5 + +/* + * Wirecutters + */ +/obj/item/wirecutters + name = "wirecutters" + desc = "This cuts wires." + icon = 'icons/obj/tools.dmi' + icon_state = null + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 6 + throw_speed = 3 + throw_range = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=80) + attack_verb = list("pinched", "nipped") + hitsound = 'sound/items/wirecutter.ogg' + usesound = 'sound/items/wirecutter.ogg' + origin_tech = "materials=1;engineering=1" + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + + +/obj/item/wirecutters/New(loc, var/param_color = null) + ..() + if(!icon_state) + if(!param_color) + param_color = pick("yellow","red") + icon_state = "cutters_[param_color]" + +/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) + if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) + user.visible_message("[user] cuts [C]'s restraints with [src]!") + qdel(C.handcuffed) + C.handcuffed = null + if(C.buckled && C.buckled.buckle_requires_restraints) + C.buckled.unbuckle_mob(C) + C.update_handcuffed() + return + else + ..() + +/obj/item/wirecutters/suicide_act(mob/user) + user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, usesound, 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/brass + name = "brass wirecutters" + desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "cutters_brass" + toolspeed = 0.5 + +/obj/item/wirecutters/abductor + name = "alien wirecutters" + desc = "Extremely sharp wirecutters, made out of a silvery-green metal." + icon = 'icons/obj/abductor.dmi' + icon_state = "cutters" + toolspeed = 0.1 + origin_tech = "materials=5;engineering=4;abductor=3" + +/obj/item/wirecutters/cyborg + name = "wirecutters" + desc = "This cuts wires." + toolspeed = 0.5 + +/obj/item/wirecutters/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." + icon_state = "jaws_cutter" + item_state = "jawsoflife" + origin_tech = "materials=2;engineering=2" + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + usesound = 'sound/items/jaws_cut.ogg' + toolspeed = 0.25 + +/obj/item/wirecutters/power/suicide_act(mob/user) + user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") + playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/obj/item/bodypart/BP = C.get_bodypart("head") + if(BP) + BP.drop_limb() + playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power + to_chat(user, "You attach the pry jaws to [src].") + qdel(src) + user.put_in_active_hand(pryjaws) +/* + * Welding Tool + */ +/obj/item/weldingtool + name = "welding tool" + desc = "A standard edition welder provided by NanoTrasen." + icon = 'icons/obj/tools.dmi' + icon_state = "welder" + item_state = "welder" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 3 + throwforce = 5 + hitsound = "swing_hit" + usesound = 'sound/items/welder.ogg' + var/acti_sound = 'sound/items/welderactivate.ogg' + var/deac_sound = 'sound/items/welderdeactivate.ogg' + throw_speed = 3 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) + resistance_flags = FIRE_PROOF + + materials = list(MAT_METAL=70, MAT_GLASS=30) + origin_tech = "engineering=1;plasmatech=1" + var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) + var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) + var/max_fuel = 20 //The max amount of fuel the welder can hold + var/change_icons = 1 + var/can_off_process = 0 + var/light_intensity = 2 //how powerful the emitted light is when used. + var/burned_fuel_for = 0 //when fuel was last removed + heat = 3800 + toolspeed = 1 + +/obj/item/weldingtool/Initialize() + . = ..() + create_reagents(max_fuel) + reagents.add_reagent("welding_fuel", max_fuel) + update_icon() + + +/obj/item/weldingtool/proc/update_torch() + if(welding) + add_overlay("[initial(icon_state)]-on") + item_state = "[initial(item_state)]1" + else + item_state = "[initial(item_state)]" + + +/obj/item/weldingtool/update_icon() + cut_overlays() + if(change_icons) + var/ratio = get_fuel() / max_fuel + ratio = Ceiling(ratio*4) * 25 + add_overlay("[initial(icon_state)][ratio]") + update_torch() + return + + +/obj/item/weldingtool/process() + switch(welding) + if(0) + force = 3 + damtype = "brute" + update_icon() + if(!can_off_process) + STOP_PROCESSING(SSobj, src) + return + //Welders left on now use up fuel, but lets not have them run out quite that fast + if(1) + force = 15 + damtype = "fire" + ++burned_fuel_for + if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) + remove_fuel(1) + update_icon() + + //This is to start fires. process() is only called if the welder is on. + open_flame() + + +/obj/item/weldingtool/suicide_act(mob/user) + user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") + return (FIRELOSS) + + +/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/screwdriver)) + flamethrower_screwdriver(I, user) + else if(istype(I, /obj/item/stack/rods)) + flamethrower_rods(I, user) + else + return ..() + + +/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return ..() + + var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) + + if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) + if(src.remove_fuel(1)) + playsound(loc, usesound, 50, 1) + if(user == H) + user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") + if(!do_mob(user, H, 50)) + return + item_heal_robotic(H, user, 15, 0) + else + return ..() + + +/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) + if(!proximity) return + + if(welding) + remove_fuel(1) + var/turf/location = get_turf(user) + location.hotspot_expose(700, 50, 1) + if(get_fuel() <= 0) + set_light(0) + + if(isliving(O)) + var/mob/living/L = O + if(L.IgniteMob()) + message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") + log_game("[key_name(user)] set [key_name(L)] on fire") + + +/obj/item/weldingtool/attack_self(mob/user) + switched_on(user) + if(welding) + set_light(light_intensity) + + update_icon() + + +//Returns the amount of fuel in the welder +/obj/item/weldingtool/proc/get_fuel() + return reagents.get_reagent_amount("welding_fuel") + + +//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() +/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) + if(!welding || !check_fuel()) + return 0 + if(amount) + burned_fuel_for = 0 + if(get_fuel() >= amount) + reagents.remove_reagent("welding_fuel", amount) + check_fuel() + if(M) + M.flash_act(light_intensity) + return TRUE + else + if(M) + to_chat(M, "You need more welding fuel to complete this task!") + return FALSE + + +//Turns off the welder if there is no more fuel (does this really need to be its own proc?) +/obj/item/weldingtool/proc/check_fuel(mob/user) + if(get_fuel() <= 0 && welding) + switched_on(user) + update_icon() + //mob icon update + if(ismob(loc)) + var/mob/M = loc + M.update_inv_hands(0) + + return 0 + return 1 + +//Switches the welder on +/obj/item/weldingtool/proc/switched_on(mob/user) + if(!status) + to_chat(user, "[src] can't be turned on while unsecured!") + return + welding = !welding + if(welding) + if(get_fuel() >= 1) + to_chat(user, "You switch [src] on.") + playsound(loc, acti_sound, 50, 1) + force = 15 + damtype = "fire" + hitsound = 'sound/items/welder.ogg' + update_icon() + START_PROCESSING(SSobj, src) + else + to_chat(user, "You need more fuel!") + switched_off(user) + else + to_chat(user, "You switch [src] off.") + playsound(loc, deac_sound, 50, 1) + switched_off(user) + +//Switches the welder off +/obj/item/weldingtool/proc/switched_off(mob/user) + welding = 0 + set_light(0) + + force = 3 + damtype = "brute" + hitsound = "swing_hit" + update_icon() + + +/obj/item/weldingtool/examine(mob/user) + ..() + to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") + +/obj/item/weldingtool/is_hot() + return welding * heat + +//Returns whether or not the welding tool is currently on. +/obj/item/weldingtool/proc/isOn() + return welding + + +/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) + if(welding) + to_chat(user, "Turn it off first!") + return + status = !status + if(status) + to_chat(user, "You resecure [src].") + else + to_chat(user, "[src] can now be attached and modified.") + add_fingerprint(user) + +/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) + if(!status) + var/obj/item/stack/rods/R = I + if (R.use(1)) + var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) + if(!remove_item_from_storage(F)) + user.transferItemToLoc(src, F, TRUE) + F.weldtool = src + add_fingerprint(user) + to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") + user.put_in_hands(F) + else + to_chat(user, "You need one rod to start building a flamethrower!") + +/obj/item/weldingtool/ignition_effect(atom/A, mob/user) + if(welding && remove_fuel(1, user)) + . = "[user] casually lights [A] with [src], what a badass." + else + . = "" + +/obj/item/weldingtool/largetank + name = "industrial welding tool" + desc = "A slightly larger welder with a larger tank." + icon_state = "indwelder" + max_fuel = 40 + materials = list(MAT_GLASS=60) + origin_tech = "engineering=2;plasmatech=2" + +/obj/item/weldingtool/largetank/cyborg + name = "integrated welding tool" + desc = "An advanced welder designed to be used in robotic systems." + toolspeed = 0.5 + +/obj/item/weldingtool/largetank/flamethrower_screwdriver() + return + + +/obj/item/weldingtool/mini + name = "emergency welding tool" + desc = "A miniature welder used during emergencies." + icon_state = "miniwelder" + max_fuel = 10 + w_class = WEIGHT_CLASS_TINY + materials = list(MAT_METAL=30, MAT_GLASS=10) + change_icons = 0 + +/obj/item/weldingtool/mini/flamethrower_screwdriver() + return + +/obj/item/weldingtool/abductor + name = "alien welding tool" + desc = "An alien welding tool. Whatever fuel it uses, it never runs out." + icon = 'icons/obj/abductor.dmi' + icon_state = "welder" + toolspeed = 0.1 + light_intensity = 0 + change_icons = 0 + origin_tech = "plasmatech=5;engineering=5;abductor=3" + +/obj/item/weldingtool/abductor/process() + if(get_fuel() <= max_fuel) + reagents.add_reagent("welding_fuel", 1) + ..() + +/obj/item/weldingtool/hugetank + name = "upgraded industrial welding tool" + desc = "An upgraded welder based of the industrial welder." + icon_state = "upindwelder" + item_state = "upindwelder" + max_fuel = 80 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "engineering=3;plasmatech=2" + +/obj/item/weldingtool/experimental + name = "experimental welding tool" + desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." + icon_state = "exwelder" + item_state = "exwelder" + max_fuel = 40 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" + var/last_gen = 0 + change_icons = 0 + can_off_process = 1 + light_intensity = 1 + toolspeed = 0.5 + var/nextrefueltick = 0 + +/obj/item/weldingtool/experimental/brass + name = "brass welding tool" + desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "brasswelder" + item_state = "brasswelder" + + +/obj/item/weldingtool/experimental/process() + ..() + if(get_fuel() < max_fuel && nextrefueltick < world.time) + nextrefueltick = world.time + 10 + reagents.add_reagent("welding_fuel", 1) + + +/* + * Crowbar + */ + +/obj/item/crowbar + name = "pocket crowbar" + desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." + icon = 'icons/obj/tools.dmi' + icon_state = "crowbar" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/crowbar.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + origin_tech = "engineering=1;combat=1" + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/crowbar/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/red + icon_state = "crowbar_red" + force = 8 + +/obj/item/crowbar/brass + name = "brass crowbar" + desc = "A brass crowbar. It feels faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "crowbar_brass" + toolspeed = 0.5 + +/obj/item/crowbar/abductor + name = "alien crowbar" + desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." + icon = 'icons/obj/abductor.dmi' + usesound = 'sound/weapons/sonic_jackhammer.ogg' + icon_state = "crowbar" + toolspeed = 0.1 + origin_tech = "combat=4;engineering=4;abductor=3" + +/obj/item/crowbar/large + name = "crowbar" + desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." + force = 12 + w_class = WEIGHT_CLASS_NORMAL + throw_speed = 3 + throw_range = 3 + materials = list(MAT_METAL=70) + icon_state = "crowbar_large" + item_state = "crowbar" + toolspeed = 0.5 + +/obj/item/crowbar/cyborg + name = "hydraulic crowbar" + desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." + usesound = 'sound/items/jaws_pry.ogg' + force = 10 + toolspeed = 0.5 + +/obj/item/crowbar/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." + icon_state = "jaws_pry" + item_state = "jawsoflife" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" + usesound = 'sound/items/jaws_pry.ogg' + force = 15 + toolspeed = 0.25 + +/obj/item/crowbar/power/suicide_act(mob/user) + user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power + to_chat(user, "You attach the cutting jaws to [src].") + qdel(src) + user.put_in_active_hand(cutjaws) + +#undef WELDER_FUEL_BURN_INTERVAL #define WELDER_FUEL_BURN_INTERVAL 13 /* Tools! @@ -1580,4 +1578,3 @@ user.put_in_active_hand(cutjaws) #undef WELDER_FUEL_BURN_INTERVAL ->>>>>>> 2240756... Gets rid of manual overlay manipulation (#30454) From 3dbfac920ae6b0360a49d93e7ecc180c8faa277a Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 10 Sep 2017 11:48:28 -0500 Subject: [PATCH 027/102] Update weaponry.dm --- code/game/objects/items/weaponry.dm | 1175 +++++++++++++-------------- 1 file changed, 586 insertions(+), 589 deletions(-) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index fe9c9485cd..443518ec0a 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -1,596 +1,594 @@ -/obj/item/banhammer - desc = "A banhammer" - name = "banhammer" - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "toyhammer" - slot_flags = SLOT_BELT - throwforce = 0 - w_class = WEIGHT_CLASS_TINY - throw_speed = 3 - throw_range = 7 - attack_verb = list("banned") - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 70) - resistance_flags = FIRE_PROOF - -/obj/item/banhammer/suicide_act(mob/user) - user.visible_message("[user] is hitting [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to ban [user.p_them()]self from life.") - return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS) - -/obj/item/banhammer/attack(mob/M, mob/user) +/obj/item/banhammer + desc = "A banhammer" + name = "banhammer" + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "toyhammer" + slot_flags = SLOT_BELT + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + throw_speed = 3 + throw_range = 7 + attack_verb = list("banned") + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 70) + resistance_flags = FIRE_PROOF + +/obj/item/banhammer/suicide_act(mob/user) + user.visible_message("[user] is hitting [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to ban [user.p_them()]self from life.") + return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS) + +/obj/item/banhammer/attack(mob/M, mob/user) if(user.zone_selected == "head") M.visible_message("[user] are stroking the head of [M] with a bangammer", "[user] are stroking the head with a bangammer", "you hear a bangammer stroking a head"); else M.visible_message("[M] has been banned FOR NO REISIN by [user]", "You have been banned FOR NO REISIN by [user]", "you hear a banhammer banning someone") -<<<<<<< HEAD - playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much - -/obj/item/sord - name = "\improper SORD" - desc = "This thing is so unspeakably shitty you are having a hard time even holding it." - icon_state = "sord" - item_state = "sord" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - slot_flags = SLOT_BELT - force = 2 - throwforce = 1 - w_class = WEIGHT_CLASS_NORMAL - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - -/obj/item/sord/suicide_act(mob/user) - user.visible_message("[user] is trying to impale [user.p_them()]self with [src]! It might be a suicide attempt if it weren't so shitty.", \ - "You try to impale yourself with [src], but it's USELESS...") - return SHAME - -/obj/item/claymore - name = "claymore" - desc = "What are you standing around staring at this for? Get to killing!" - icon_state = "claymore" - item_state = "claymore" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - hitsound = 'sound/weapons/bladeslice.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT | SLOT_BACK - force = 40 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 - sharpness = IS_SHARP - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/claymore/suicide_act(mob/user) - user.visible_message("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS - desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." - flags_1 = CONDUCT_1 | NODROP_1 | DROPDEL_1 - slot_flags = null - block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY - luminosity = 3 - attack_verb = list("brutalized", "eviscerated", "disemboweled", "hacked", "carved", "cleaved") //ONLY THE MOST VISCERAL ATTACK VERBS - var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE - var/obj/item/disk/nuclear/nuke_disk //OUR STORED NUKE DISK - -/obj/item/claymore/highlander/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/item/claymore/highlander/Destroy() - if(nuke_disk) - nuke_disk.forceMove(get_turf(src)) - nuke_disk.visible_message("The nuke disk is vulnerable!") - nuke_disk = null - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/claymore/highlander/process() - if(ishuman(loc)) - var/mob/living/carbon/human/H = loc - loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS) - H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS - else - if(!admin_spawned) - qdel(src) - - -/obj/item/claymore/highlander/pickup(mob/living/user) - to_chat(user, "The power of Scotland protects you! You are shielded from all stuns and knockdowns.") - user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!") - user.status_flags += IGNORESLOWDOWN - -/obj/item/claymore/highlander/dropped(mob/living/user) - user.status_flags -= IGNORESLOWDOWN - qdel(src) //If this ever happens, it's because you lost an arm - -/obj/item/claymore/highlander/examine(mob/user) - ..() - to_chat(user, "It has [!notches ? "nothing" : "[notches] notches"] scratched into the blade.") - if(nuke_disk) - to_chat(user, "It's holding the nuke disk!") - -/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) - . = ..() - if(target && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") - user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES - add_notch(user) - target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") - target.dust() - -/obj/item/claymore/highlander/attack_self(mob/living/user) - var/closest_victim - var/closest_distance = 255 - for(var/mob/living/carbon/human/H in GLOB.player_list - user) - if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) - closest_victim = H - if(!closest_victim) - to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") - return - to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].") - -/obj/item/claymore/highlander/IsReflect() - return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME? - -/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE - notches++ - force++ - var/new_name = name - switch(notches) - if(1) - to_chat(user, "Your first kill - hopefully one of many. You scratch a notch into [src]'s blade.") - to_chat(user, "You feel your fallen foe's soul entering your blade, restoring your wounds!") - new_name = "notched claymore" - if(2) - to_chat(user, "Another falls before you. Another soul fuses with your own. Another notch in the blade.") - new_name = "double-notched claymore" - add_atom_colour(rgb(255, 235, 235), ADMIN_COLOUR_PRIORITY) - if(3) - to_chat(user, "You're beginning to relish the thrill of battle.") - new_name = "triple-notched claymore" - add_atom_colour(rgb(255, 215, 215), ADMIN_COLOUR_PRIORITY) - if(4) - to_chat(user, "You've lost count of how many you've killed.") - new_name = "many-notched claymore" - add_atom_colour(rgb(255, 195, 195), ADMIN_COLOUR_PRIORITY) - if(5) - to_chat(user, "Five voices now echo in your mind, cheering the slaughter.") - new_name = "battle-tested claymore" - add_atom_colour(rgb(255, 175, 175), ADMIN_COLOUR_PRIORITY) - if(6) - to_chat(user, "Is this what the vikings felt like? Visions of glory fill your head as you slay your sixth foe.") - new_name = "battle-scarred claymore" - add_atom_colour(rgb(255, 155, 155), ADMIN_COLOUR_PRIORITY) - if(7) - to_chat(user, "Kill. Butcher. Conquer.") - new_name = "vicious claymore" - add_atom_colour(rgb(255, 135, 135), ADMIN_COLOUR_PRIORITY) - if(8) - to_chat(user, "IT NEVER GETS OLD. THE SCREAMING. THE BLOOD AS IT SPRAYS ACROSS YOUR FACE.") - new_name = "bloodthirsty claymore" - add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY) - if(9) - to_chat(user, "ANOTHER ONE FALLS TO YOUR BLOWS. ANOTHER WEAKLING UNFIT TO LIVE.") - new_name = "gore-stained claymore" - add_atom_colour(rgb(255, 95, 95), ADMIN_COLOUR_PRIORITY) - if(10) - user.visible_message("[user]'s eyes light up with a vengeful fire!", \ - "YOU FEEL THE POWER OF VALHALLA FLOWING THROUGH YOU! THERE CAN BE ONLY ONE!!!") - user.update_icons() - new_name = "GORE-DRENCHED CLAYMORE OF [pick("THE WHIMSICAL SLAUGHTER", "A THOUSAND SLAUGHTERED CATTLE", "GLORY AND VALHALLA", "ANNIHILATION", "OBLITERATION")]" - icon_state = "claymore_valhalla" - item_state = "cultblade" - remove_atom_colour(ADMIN_COLOUR_PRIORITY) - - name = new_name - playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) - -/obj/item/katana - name = "katana" - desc = "Woefully underpowered in D20" - icon_state = "katana" - item_state = "katana" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT | SLOT_BACK - force = 40 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 - sharpness = IS_SHARP - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/katana/cursed - slot_flags = null - -/obj/item/katana/suicide_act(mob/user) - user.visible_message("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!") - return(BRUTELOSS) - -/obj/item/wirerod - name = "wired rod" - desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." - icon_state = "wiredrod" - item_state = "rods" - flags_1 = CONDUCT_1 - force = 9 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - materials = list(MAT_METAL=1150, MAT_GLASS=75) - attack_verb = list("hit", "bludgeoned", "whacked", "bonked") - -/obj/item/wirerod/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/shard)) - var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear - - remove_item_from_storage(user) - qdel(I) - qdel(src) - - user.put_in_hands(S) - to_chat(user, "You fasten the glass shard to the top of the rod with the cable.") - - else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags_1 & NODROP_1)) - var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod - - remove_item_from_storage(user) - - to_chat(user, "You fasten [I] to the top of the rod with the cable.") - - qdel(I) - qdel(src) - - user.put_in_hands(P) - else - return ..() - - -/obj/item/throwing_star - name = "throwing star" - desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" - icon_state = "throwingstar" - item_state = "eshield0" - lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' - force = 2 - throwforce = 20 //This is never used on mobs since this has a 100% embed chance. - throw_speed = 4 - embedded_pain_multiplier = 4 - w_class = WEIGHT_CLASS_SMALL - embed_chance = 100 - embedded_fall_chance = 0 //Hahaha! - sharpness = IS_SHARP - materials = list(MAT_METAL=500, MAT_GLASS=500) - resistance_flags = FIRE_PROOF - - -/obj/item/switchblade - name = "switchblade" - icon_state = "switchblade" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - desc = "A sharp, concealable, spring-loaded knife." - flags_1 = CONDUCT_1 - force = 3 - w_class = WEIGHT_CLASS_SMALL - throwforce = 5 - throw_speed = 3 - throw_range = 6 - materials = list(MAT_METAL=12000) - origin_tech = "engineering=3;combat=2" - hitsound = 'sound/weapons/genhit.ogg' - attack_verb = list("stubbed", "poked") - resistance_flags = FIRE_PROOF - var/extended = 0 - -/obj/item/switchblade/attack_self(mob/user) - extended = !extended - playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1) - if(extended) - force = 20 - w_class = WEIGHT_CLASS_NORMAL - throwforce = 23 - icon_state = "switchblade_ext" - attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP - else - force = 3 - w_class = WEIGHT_CLASS_SMALL - throwforce = 5 - icon_state = "switchblade" - attack_verb = list("stubbed", "poked") - hitsound = 'sound/weapons/genhit.ogg' - sharpness = IS_BLUNT - -/obj/item/switchblade/suicide_act(mob/user) - user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/phone - name = "red phone" - desc = "Should anything ever go wrong..." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "red_phone" - force = 3 - throwforce = 2 - throw_speed = 3 - throw_range = 4 - w_class = WEIGHT_CLASS_SMALL - attack_verb = list("called", "rang") - hitsound = 'sound/weapons/ring.ogg' - -/obj/item/phone/suicide_act(mob/user) - if(locate(/obj/structure/chair/stool) in user.loc) - user.visible_message("[user] begins to tie a noose with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") - else - user.visible_message("[user] is strangling [user.p_them()]self with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") - return(OXYLOSS) - -/obj/item/cane - name = "cane" - desc = "A cane used by a true gentleman. Or a clown." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "cane" - item_state = "stick" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 5 - throwforce = 5 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") - -/obj/item/staff - name = "wizard staff" - desc = "Apparently a staff used by the wizard." - icon = 'icons/obj/wizard.dmi' - icon_state = "staff" - lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' - force = 3 - throwforce = 5 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armour_penetration = 100 - attack_verb = list("bludgeoned", "whacked", "disciplined") - resistance_flags = FLAMMABLE - -/obj/item/staff/broom - name = "broom" - desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." - icon = 'icons/obj/wizard.dmi' - icon_state = "broom" - resistance_flags = FLAMMABLE - -/obj/item/staff/stick - name = "stick" - desc = "A great tool to drag someone else's drinks across the bar." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "stick" - item_state = "stick" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 3 - throwforce = 5 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - -/obj/item/ectoplasm - name = "ectoplasm" - desc = "spooky" - gender = PLURAL - icon = 'icons/obj/wizard.dmi' - icon_state = "ectoplasm" - -/obj/item/ectoplasm/suicide_act(mob/user) - user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") - return (OXYLOSS) - -/obj/item/mounted_chainsaw - name = "mounted chainsaw" - desc = "A chainsaw that has replaced your arm." - icon_state = "chainsaw_on" - item_state = "mounted_chainsaw" - lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' - flags_1 = NODROP_1 | ABSTRACT_1 | DROPDEL_1 - w_class = WEIGHT_CLASS_HUGE - force = 21 - throwforce = 0 - throw_range = 0 - throw_speed = 0 - sharpness = IS_SHARP - attack_verb = list("sawed", "torn", "cut", "chopped", "diced") - hitsound = 'sound/weapons/chainsawhit.ogg' - -/obj/item/mounted_chainsaw/Destroy() - var/obj/item/bodypart/part - new /obj/item/twohanded/required/chainsaw(get_turf(src)) - if(iscarbon(loc)) - var/mob/living/carbon/holder = loc - var/index = holder.get_held_index_of_item(src) - if(index) - part = holder.hand_bodyparts[index] - . = ..() - if(part) - part.drop_limb() - -/obj/item/statuebust - name = "bust" - desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it - icon = 'icons/obj/statue.dmi' - icon_state = "bust" - force = 15 - throwforce = 10 - throw_speed = 5 - throw_range = 2 - attack_verb = list("busted") - -/obj/item/tailclub - name = "tail club" - desc = "For the beating to death of lizards with their own tails." - icon_state = "tailclub" - force = 14 - throwforce = 1 // why are you throwing a club do you even weapon - throw_speed = 1 - throw_range = 1 - attack_verb = list("clubbed", "bludgeoned") - -/obj/item/melee/chainofcommand/tailwhip - name = "liz o' nine tails" - desc = "A whip fashioned from the severed tails of lizards." - icon_state = "tailwhip" - origin_tech = "engineering=3;combat=3;biotech=3" - needs_permit = 0 - -/obj/item/melee/chainofcommand/tailwhip/kitty - name = "cat o' nine tails" - desc = "A whip fashioned from the severed tails of cats." - icon_state = "catwhip" - -/obj/item/melee/skateboard - name = "skateboard" - desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon." - icon_state = "skateboard" - item_state = "skateboard" - force = 12 - throwforce = 4 - w_class = WEIGHT_CLASS_HUGE - attack_verb = list("smacked", "whacked", "slammed", "smashed") - -/obj/item/melee/skateboard/attack_self(mob/user) - new /obj/vehicle/scooter/skateboard(get_turf(user)) - qdel(src) - -/obj/item/melee/baseball_bat - name = "baseball bat" - desc = "There ain't a skull in the league that can withstand a swatter." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "baseball_bat" - item_state = "baseball_bat" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 10 - throwforce = 12 - attack_verb = list("beat", "smacked") - w_class = WEIGHT_CLASS_HUGE - var/homerun_ready = 0 - var/homerun_able = 0 - -/obj/item/melee/baseball_bat/homerun - name = "home run bat" - desc = "This thing looks dangerous... Dangerously good at baseball, that is." - homerun_able = 1 - -/obj/item/melee/baseball_bat/attack_self(mob/user) - if(!homerun_able) - ..() - return - if(homerun_ready) - to_chat(user, "You're already ready to do a home run!") - ..() - return - to_chat(user, "You begin gathering strength...") - playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1) - if(do_after(user, 90, target = src)) - to_chat(user, "You gather power! Time for a home run!") - homerun_ready = 1 - ..() - -/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user) - . = ..() - var/atom/throw_target = get_edge_target_turf(target, user.dir) - if(homerun_ready) - user.visible_message("It's a home run!") - target.throw_at(throw_target, rand(8,10), 14, user) - target.ex_act(EXPLODE_HEAVY) - playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) - homerun_ready = 0 - return - else if(!target.anchored) - target.throw_at(throw_target, rand(1,2), 7, user) - -/obj/item/melee/baseball_bat/ablative - name = "metal baseball bat" - desc = "This bat is made of highly reflective, highly armored material." - icon_state = "baseball_bat_metal" - item_state = "baseball_bat_metal" - force = 12 - throwforce = 15 - -/obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers - var/picksound = rand(1,2) - var/turf = get_turf(src) - if(picksound == 1) - playsound(turf, 'sound/weapons/effects/batreflect1.ogg', 50, 1) - if(picksound == 2) - playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) - return 1 - -/obj/item/melee/flyswatter - name = "flyswatter" - desc = "Useful for killing insects of all sizes." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "flyswatter" - item_state = "flyswatter" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 1 - throwforce = 1 - attack_verb = list("swatted", "smacked") - hitsound = 'sound/effects/snap.ogg' - w_class = WEIGHT_CLASS_SMALL - //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. - var/list/strong_against - -/obj/item/melee/flyswatter/Initialize() - . = ..() - strong_against = typecacheof(list( - /mob/living/simple_animal/hostile/poison/bees/, - /mob/living/simple_animal/butterfly, - /mob/living/simple_animal/cockroach, - /obj/item/queen_bee - )) - - -/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag) - if(proximity_flag) - if(is_type_in_typecache(target, strong_against)) - new /obj/effect/decal/cleanable/deadcockroach(get_turf(target)) - to_chat(user, "You easily splat the [target].") - if(istype(target, /mob/living/)) - var/mob/living/bug = target - bug.death(1) - else - qdel(target) - -/obj/item/circlegame - name = "circled hand" - desc = "If somebody looks at this while it's below your waist, you get to bop them." - icon_state = "madeyoulook" - force = 0 - throwforce = 0 - flags_1 = DROPDEL_1 | ABSTRACT_1 - attack_verb = list("bopped") - -/obj/item/proc/can_trigger_gun(mob/living/user) - if(!user.can_use_guns(src)) - return FALSE -======= + playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much + +/obj/item/sord + name = "\improper SORD" + desc = "This thing is so unspeakably shitty you are having a hard time even holding it." + icon_state = "sord" + item_state = "sord" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + slot_flags = SLOT_BELT + force = 2 + throwforce = 1 + w_class = WEIGHT_CLASS_NORMAL + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/sord/suicide_act(mob/user) + user.visible_message("[user] is trying to impale [user.p_them()]self with [src]! It might be a suicide attempt if it weren't so shitty.", \ + "You try to impale yourself with [src], but it's USELESS...") + return SHAME + +/obj/item/claymore + name = "claymore" + desc = "What are you standing around staring at this for? Get to killing!" + icon_state = "claymore" + item_state = "claymore" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + hitsound = 'sound/weapons/bladeslice.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT | SLOT_BACK + force = 40 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + block_chance = 50 + sharpness = IS_SHARP + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/item/claymore/suicide_act(mob/user) + user.visible_message("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS + desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." + flags_1 = CONDUCT_1 | NODROP_1 | DROPDEL_1 + slot_flags = null + block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY + luminosity = 3 + attack_verb = list("brutalized", "eviscerated", "disemboweled", "hacked", "carved", "cleaved") //ONLY THE MOST VISCERAL ATTACK VERBS + var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE + var/obj/item/disk/nuclear/nuke_disk //OUR STORED NUKE DISK + +/obj/item/claymore/highlander/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/claymore/highlander/Destroy() + if(nuke_disk) + nuke_disk.forceMove(get_turf(src)) + nuke_disk.visible_message("The nuke disk is vulnerable!") + nuke_disk = null + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/claymore/highlander/process() + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS) + H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS + else + if(!admin_spawned) + qdel(src) + + +/obj/item/claymore/highlander/pickup(mob/living/user) + to_chat(user, "The power of Scotland protects you! You are shielded from all stuns and knockdowns.") + user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!") + user.status_flags += IGNORESLOWDOWN + +/obj/item/claymore/highlander/dropped(mob/living/user) + user.status_flags -= IGNORESLOWDOWN + qdel(src) //If this ever happens, it's because you lost an arm + +/obj/item/claymore/highlander/examine(mob/user) + ..() + to_chat(user, "It has [!notches ? "nothing" : "[notches] notches"] scratched into the blade.") + if(nuke_disk) + to_chat(user, "It's holding the nuke disk!") + +/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) + . = ..() + if(target && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") + user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES + add_notch(user) + target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") + target.dust() + +/obj/item/claymore/highlander/attack_self(mob/living/user) + var/closest_victim + var/closest_distance = 255 + for(var/mob/living/carbon/human/H in GLOB.player_list - user) + if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) + closest_victim = H + if(!closest_victim) + to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") + return + to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].") + +/obj/item/claymore/highlander/IsReflect() + return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME? + +/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE + notches++ + force++ + var/new_name = name + switch(notches) + if(1) + to_chat(user, "Your first kill - hopefully one of many. You scratch a notch into [src]'s blade.") + to_chat(user, "You feel your fallen foe's soul entering your blade, restoring your wounds!") + new_name = "notched claymore" + if(2) + to_chat(user, "Another falls before you. Another soul fuses with your own. Another notch in the blade.") + new_name = "double-notched claymore" + add_atom_colour(rgb(255, 235, 235), ADMIN_COLOUR_PRIORITY) + if(3) + to_chat(user, "You're beginning to relish the thrill of battle.") + new_name = "triple-notched claymore" + add_atom_colour(rgb(255, 215, 215), ADMIN_COLOUR_PRIORITY) + if(4) + to_chat(user, "You've lost count of how many you've killed.") + new_name = "many-notched claymore" + add_atom_colour(rgb(255, 195, 195), ADMIN_COLOUR_PRIORITY) + if(5) + to_chat(user, "Five voices now echo in your mind, cheering the slaughter.") + new_name = "battle-tested claymore" + add_atom_colour(rgb(255, 175, 175), ADMIN_COLOUR_PRIORITY) + if(6) + to_chat(user, "Is this what the vikings felt like? Visions of glory fill your head as you slay your sixth foe.") + new_name = "battle-scarred claymore" + add_atom_colour(rgb(255, 155, 155), ADMIN_COLOUR_PRIORITY) + if(7) + to_chat(user, "Kill. Butcher. Conquer.") + new_name = "vicious claymore" + add_atom_colour(rgb(255, 135, 135), ADMIN_COLOUR_PRIORITY) + if(8) + to_chat(user, "IT NEVER GETS OLD. THE SCREAMING. THE BLOOD AS IT SPRAYS ACROSS YOUR FACE.") + new_name = "bloodthirsty claymore" + add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY) + if(9) + to_chat(user, "ANOTHER ONE FALLS TO YOUR BLOWS. ANOTHER WEAKLING UNFIT TO LIVE.") + new_name = "gore-stained claymore" + add_atom_colour(rgb(255, 95, 95), ADMIN_COLOUR_PRIORITY) + if(10) + user.visible_message("[user]'s eyes light up with a vengeful fire!", \ + "YOU FEEL THE POWER OF VALHALLA FLOWING THROUGH YOU! THERE CAN BE ONLY ONE!!!") + user.update_icons() + new_name = "GORE-DRENCHED CLAYMORE OF [pick("THE WHIMSICAL SLAUGHTER", "A THOUSAND SLAUGHTERED CATTLE", "GLORY AND VALHALLA", "ANNIHILATION", "OBLITERATION")]" + icon_state = "claymore_valhalla" + item_state = "cultblade" + remove_atom_colour(ADMIN_COLOUR_PRIORITY) + + name = new_name + playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) + +/obj/item/katana + name = "katana" + desc = "Woefully underpowered in D20" + icon_state = "katana" + item_state = "katana" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT | SLOT_BACK + force = 40 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + block_chance = 50 + sharpness = IS_SHARP + max_integrity = 200 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/item/katana/cursed + slot_flags = null + +/obj/item/katana/suicide_act(mob/user) + user.visible_message("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!") + return(BRUTELOSS) + +/obj/item/wirerod + name = "wired rod" + desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." + icon_state = "wiredrod" + item_state = "rods" + flags_1 = CONDUCT_1 + force = 9 + throwforce = 10 + w_class = WEIGHT_CLASS_NORMAL + materials = list(MAT_METAL=1150, MAT_GLASS=75) + attack_verb = list("hit", "bludgeoned", "whacked", "bonked") + +/obj/item/wirerod/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/shard)) + var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear + + remove_item_from_storage(user) + qdel(I) + qdel(src) + + user.put_in_hands(S) + to_chat(user, "You fasten the glass shard to the top of the rod with the cable.") + + else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags_1 & NODROP_1)) + var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod + + remove_item_from_storage(user) + + to_chat(user, "You fasten [I] to the top of the rod with the cable.") + + qdel(I) + qdel(src) + + user.put_in_hands(P) + else + return ..() + + +/obj/item/throwing_star + name = "throwing star" + desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" + icon_state = "throwingstar" + item_state = "eshield0" + lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + force = 2 + throwforce = 20 //This is never used on mobs since this has a 100% embed chance. + throw_speed = 4 + embedded_pain_multiplier = 4 + w_class = WEIGHT_CLASS_SMALL + embed_chance = 100 + embedded_fall_chance = 0 //Hahaha! + sharpness = IS_SHARP + materials = list(MAT_METAL=500, MAT_GLASS=500) + resistance_flags = FIRE_PROOF + + +/obj/item/switchblade + name = "switchblade" + icon_state = "switchblade" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + desc = "A sharp, concealable, spring-loaded knife." + flags_1 = CONDUCT_1 + force = 3 + w_class = WEIGHT_CLASS_SMALL + throwforce = 5 + throw_speed = 3 + throw_range = 6 + materials = list(MAT_METAL=12000) + origin_tech = "engineering=3;combat=2" + hitsound = 'sound/weapons/genhit.ogg' + attack_verb = list("stubbed", "poked") + resistance_flags = FIRE_PROOF + var/extended = 0 + +/obj/item/switchblade/attack_self(mob/user) + extended = !extended + playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1) + if(extended) + force = 20 + w_class = WEIGHT_CLASS_NORMAL + throwforce = 23 + icon_state = "switchblade_ext" + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + sharpness = IS_SHARP + else + force = 3 + w_class = WEIGHT_CLASS_SMALL + throwforce = 5 + icon_state = "switchblade" + attack_verb = list("stubbed", "poked") + hitsound = 'sound/weapons/genhit.ogg' + sharpness = IS_BLUNT + +/obj/item/switchblade/suicide_act(mob/user) + user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/phone + name = "red phone" + desc = "Should anything ever go wrong..." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "red_phone" + force = 3 + throwforce = 2 + throw_speed = 3 + throw_range = 4 + w_class = WEIGHT_CLASS_SMALL + attack_verb = list("called", "rang") + hitsound = 'sound/weapons/ring.ogg' + +/obj/item/phone/suicide_act(mob/user) + if(locate(/obj/structure/chair/stool) in user.loc) + user.visible_message("[user] begins to tie a noose with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") + else + user.visible_message("[user] is strangling [user.p_them()]self with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") + return(OXYLOSS) + +/obj/item/cane + name = "cane" + desc = "A cane used by a true gentleman. Or a clown." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "cane" + item_state = "stick" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 5 + throwforce = 5 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") + +/obj/item/staff + name = "wizard staff" + desc = "Apparently a staff used by the wizard." + icon = 'icons/obj/wizard.dmi' + icon_state = "staff" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + force = 3 + throwforce = 5 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armour_penetration = 100 + attack_verb = list("bludgeoned", "whacked", "disciplined") + resistance_flags = FLAMMABLE + +/obj/item/staff/broom + name = "broom" + desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." + icon = 'icons/obj/wizard.dmi' + icon_state = "broom" + resistance_flags = FLAMMABLE + +/obj/item/staff/stick + name = "stick" + desc = "A great tool to drag someone else's drinks across the bar." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "stick" + item_state = "stick" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 3 + throwforce = 5 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + +/obj/item/ectoplasm + name = "ectoplasm" + desc = "spooky" + gender = PLURAL + icon = 'icons/obj/wizard.dmi' + icon_state = "ectoplasm" + +/obj/item/ectoplasm/suicide_act(mob/user) + user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") + return (OXYLOSS) + +/obj/item/mounted_chainsaw + name = "mounted chainsaw" + desc = "A chainsaw that has replaced your arm." + icon_state = "chainsaw_on" + item_state = "mounted_chainsaw" + lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' + flags_1 = NODROP_1 | ABSTRACT_1 | DROPDEL_1 + w_class = WEIGHT_CLASS_HUGE + force = 21 + throwforce = 0 + throw_range = 0 + throw_speed = 0 + sharpness = IS_SHARP + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsawhit.ogg' + +/obj/item/mounted_chainsaw/Destroy() + var/obj/item/bodypart/part + new /obj/item/twohanded/required/chainsaw(get_turf(src)) + if(iscarbon(loc)) + var/mob/living/carbon/holder = loc + var/index = holder.get_held_index_of_item(src) + if(index) + part = holder.hand_bodyparts[index] + . = ..() + if(part) + part.drop_limb() + +/obj/item/statuebust + name = "bust" + desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it + icon = 'icons/obj/statue.dmi' + icon_state = "bust" + force = 15 + throwforce = 10 + throw_speed = 5 + throw_range = 2 + attack_verb = list("busted") + +/obj/item/tailclub + name = "tail club" + desc = "For the beating to death of lizards with their own tails." + icon_state = "tailclub" + force = 14 + throwforce = 1 // why are you throwing a club do you even weapon + throw_speed = 1 + throw_range = 1 + attack_verb = list("clubbed", "bludgeoned") + +/obj/item/melee/chainofcommand/tailwhip + name = "liz o' nine tails" + desc = "A whip fashioned from the severed tails of lizards." + icon_state = "tailwhip" + origin_tech = "engineering=3;combat=3;biotech=3" + needs_permit = 0 + +/obj/item/melee/chainofcommand/tailwhip/kitty + name = "cat o' nine tails" + desc = "A whip fashioned from the severed tails of cats." + icon_state = "catwhip" + +/obj/item/melee/skateboard + name = "skateboard" + desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon." + icon_state = "skateboard" + item_state = "skateboard" + force = 12 + throwforce = 4 + w_class = WEIGHT_CLASS_HUGE + attack_verb = list("smacked", "whacked", "slammed", "smashed") + +/obj/item/melee/skateboard/attack_self(mob/user) + new /obj/vehicle/scooter/skateboard(get_turf(user)) + qdel(src) + +/obj/item/melee/baseball_bat + name = "baseball bat" + desc = "There ain't a skull in the league that can withstand a swatter." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "baseball_bat" + item_state = "baseball_bat" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 10 + throwforce = 12 + attack_verb = list("beat", "smacked") + w_class = WEIGHT_CLASS_HUGE + var/homerun_ready = 0 + var/homerun_able = 0 + +/obj/item/melee/baseball_bat/homerun + name = "home run bat" + desc = "This thing looks dangerous... Dangerously good at baseball, that is." + homerun_able = 1 + +/obj/item/melee/baseball_bat/attack_self(mob/user) + if(!homerun_able) + ..() + return + if(homerun_ready) + to_chat(user, "You're already ready to do a home run!") + ..() + return + to_chat(user, "You begin gathering strength...") + playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1) + if(do_after(user, 90, target = src)) + to_chat(user, "You gather power! Time for a home run!") + homerun_ready = 1 + ..() + +/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user) + . = ..() + var/atom/throw_target = get_edge_target_turf(target, user.dir) + if(homerun_ready) + user.visible_message("It's a home run!") + target.throw_at(throw_target, rand(8,10), 14, user) + target.ex_act(EXPLODE_HEAVY) + playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) + homerun_ready = 0 + return + else if(!target.anchored) + target.throw_at(throw_target, rand(1,2), 7, user) + +/obj/item/melee/baseball_bat/ablative + name = "metal baseball bat" + desc = "This bat is made of highly reflective, highly armored material." + icon_state = "baseball_bat_metal" + item_state = "baseball_bat_metal" + force = 12 + throwforce = 15 + +/obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers + var/picksound = rand(1,2) + var/turf = get_turf(src) + if(picksound == 1) + playsound(turf, 'sound/weapons/effects/batreflect1.ogg', 50, 1) + if(picksound == 2) + playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) + return 1 + +/obj/item/melee/flyswatter + name = "flyswatter" + desc = "Useful for killing insects of all sizes." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "flyswatter" + item_state = "flyswatter" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + force = 1 + throwforce = 1 + attack_verb = list("swatted", "smacked") + hitsound = 'sound/effects/snap.ogg' + w_class = WEIGHT_CLASS_SMALL + //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. + var/list/strong_against + +/obj/item/melee/flyswatter/Initialize() + . = ..() + strong_against = typecacheof(list( + /mob/living/simple_animal/hostile/poison/bees/, + /mob/living/simple_animal/butterfly, + /mob/living/simple_animal/cockroach, + /obj/item/queen_bee + )) + + +/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag) + if(proximity_flag) + if(is_type_in_typecache(target, strong_against)) + new /obj/effect/decal/cleanable/deadcockroach(get_turf(target)) + to_chat(user, "You easily splat the [target].") + if(istype(target, /mob/living/)) + var/mob/living/bug = target + bug.death(1) + else + qdel(target) + +/obj/item/circlegame + name = "circled hand" + desc = "If somebody looks at this while it's below your waist, you get to bop them." + icon_state = "madeyoulook" + force = 0 + throwforce = 0 + flags_1 = DROPDEL_1 | ABSTRACT_1 + attack_verb = list("bopped") + +/obj/item/proc/can_trigger_gun(mob/living/user) + if(!user.can_use_guns(src)) + return FALSE playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much /obj/item/sord @@ -1157,5 +1155,4 @@ /obj/item/proc/can_trigger_gun(mob/living/user) if(!user.can_use_guns(src)) return FALSE ->>>>>>> 129a7b9... Fixes brains counting towards highlander killstreaks (#30396) return TRUE From 134c3f5f39a0a4d1b85d7e6a2d0ce3813981092f Mon Sep 17 00:00:00 2001 From: KorPhaeron Date: Sun, 10 Sep 2017 12:36:42 -0500 Subject: [PATCH 028/102] Losebreath --- code/modules/mob/living/carbon/life.dm | 18 +++++++++++++++++- code/modules/surgery/organs/lungs.dm | 12 ++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index d6d6084380..d0dd1796bf 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -58,11 +58,23 @@ var/datum/gas_mixture/breath +<<<<<<< HEAD if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube"))) losebreath++ //Suffocate if(losebreath > 0) +======= + if(!getorganslot("breathing_tube")) + if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL)) + losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath + + else if(health <= HEALTH_THRESHOLD_CRIT) + losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times + + //Suffocate + if(losebreath >= 1) //You've missed a breath, take oxy damage +>>>>>>> d4e09c9... Losebreath (#30580) losebreath-- if(prob(10)) emote("gasp") @@ -114,6 +126,10 @@ if(reagents.has_reagent("epinephrine") && lungs) return adjustOxyLoss(1) +<<<<<<< HEAD +======= + +>>>>>>> d4e09c9... Losebreath (#30580) failed_last_breath = 1 throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) return 0 @@ -150,7 +166,7 @@ else //Enough oxygen failed_last_breath = 0 - if(oxyloss) + if(health >= HEALTH_THRESHOLD_CRIT) adjustOxyLoss(-5) oxygen_used = breath_gases["o2"][MOLES] clear_alert("not_enough_oxy") diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index f95e2cd996..9ff80e760c 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -122,7 +122,8 @@ H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) else H.failed_last_breath = FALSE - H.adjustOxyLoss(-5) + if(H.health >= HEALTH_THRESHOLD_CRIT) + H.adjustOxyLoss(-5) gas_breathed = breath_gases["o2"][MOLES] H.clear_alert("not_enough_oxy") @@ -149,7 +150,8 @@ H.throw_alert("nitro", /obj/screen/alert/not_enough_nitro) else H.failed_last_breath = FALSE - H.adjustOxyLoss(-5) + if(H.health >= HEALTH_THRESHOLD_CRIT) + H.adjustOxyLoss(-5) gas_breathed = breath_gases["n2"][MOLES] H.clear_alert("nitro") @@ -185,7 +187,8 @@ H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2) else H.failed_last_breath = FALSE - H.adjustOxyLoss(-5) + if(H.health >= HEALTH_THRESHOLD_CRIT) + H.adjustOxyLoss(-5) gas_breathed = breath_gases["co2"][MOLES] H.clear_alert("not_enough_co2") @@ -214,7 +217,8 @@ H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox) else H.failed_last_breath = FALSE - H.adjustOxyLoss(-5) + if(H.health >= HEALTH_THRESHOLD_CRIT) + H.adjustOxyLoss(-5) gas_breathed = breath_gases["plasma"][MOLES] H.clear_alert("not_enough_tox") From 44e62d80162cd15f04592a6f28a35cc7f86a6235 Mon Sep 17 00:00:00 2001 From: Leo Date: Sun, 10 Sep 2017 16:17:04 -0300 Subject: [PATCH 029/102] Uplink lock codes now pick from the phonetic alphabet global list (#30538) * Uplink lock codes now pick from the phonetic alphabet global list * Update virus_cart.dm --- code/datums/mind.dm | 2 +- code/game/objects/items/devices/PDA/virus_cart.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 78a402a2dc..7df65438f2 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -311,7 +311,7 @@ traitor_mob.mind.store_memory("Radio Frequency: [format_frequency(R.traitor_frequency)] ([R.name]).") else if(uplink_loc == PDA) - PDA.lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]" + PDA.lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]" if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.") traitor_mob.mind.store_memory("Uplink Passcode: [PDA.lock_code] ([PDA.name]).") diff --git a/code/game/objects/items/devices/PDA/virus_cart.dm b/code/game/objects/items/devices/PDA/virus_cart.dm index 2b0a9d3b3c..8c4a42a5aa 100644 --- a/code/game/objects/items/devices/PDA/virus_cart.dm +++ b/code/game/objects/items/devices/PDA/virus_cart.dm @@ -90,7 +90,7 @@ return if(!isnull(target) && !target.toff) charges-- - var/lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]" + var/lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]" to_chat(U, "Virus Sent! The unlock code to the target is: [lock_code]") if(!target.hidden_uplink) var/obj/item/device/uplink/uplink = new(target) From cb734046f728f54b1af4edf0af830bcbe813d3f1 Mon Sep 17 00:00:00 2001 From: Leo Date: Sun, 10 Sep 2017 16:18:12 -0300 Subject: [PATCH 031/102] Changes golem shell attackby istype chain to use an assoc list instead of an istype chain (#30542) * Changes golem shell attackby istype chain to use an assoc list instead * Makes the check use merge_type as opposed of item type --- code/modules/ruins/lavaland_ruin_code.dm | 86 +++++++----------------- 1 file changed, 25 insertions(+), 61 deletions(-) diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index e4927349d8..da965aae9d 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -46,71 +46,35 @@ desc = "The incomplete body of a golem. Add ten sheets of any mineral to finish." var/shell_type = /obj/effect/mob_spawn/human/golem var/has_owner = FALSE //if the resulting golem obeys someone - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_BULKY /obj/item/golem_shell/attackby(obj/item/I, mob/user, params) ..() - var/species - if(istype(I, /obj/item/stack/)) + var/static/list/golem_shell_species_types = list( + /obj/item/stack/sheet/metal = /datum/species/golem, + /obj/item/stack/sheet/glass = /datum/species/golem/glass, + /obj/item/stack/sheet/plasteel = /datum/species/golem/plasteel, + /obj/item/stack/sheet/mineral/sandstone = /datum/species/golem/sand, + /obj/item/stack/sheet/mineral/plasma = /datum/species/golem/plasma, + /obj/item/stack/sheet/mineral/diamond = /datum/species/golem/diamond, + /obj/item/stack/sheet/mineral/gold = /datum/species/golem/gold, + /obj/item/stack/sheet/mineral/silver = /datum/species/golem/silver, + /obj/item/stack/sheet/mineral/uranium = /datum/species/golem/uranium, + /obj/item/stack/sheet/mineral/bananium = /datum/species/golem/bananium, + /obj/item/stack/sheet/mineral/titanium = /datum/species/golem/titanium, + /obj/item/stack/sheet/mineral/plastitanium = /datum/species/golem/plastitanium, + /obj/item/stack/sheet/mineral/abductor = /datum/species/golem/alloy, + /obj/item/stack/sheet/mineral/wood = /datum/species/golem/wood, + /obj/item/stack/sheet/bluespace_crystal = /datum/species/golem/bluespace, + /obj/item/stack/sheet/runed_metal = /datum/species/golem/runic, + /obj/item/stack/medical/gauze = /datum/species/golem/cloth, + /obj/item/stack/sheet/cloth = /datum/species/golem/cloth, + /obj/item/stack/sheet/mineral/adamantine = /datum/species/golem/adamantine, + /obj/item/stack/sheet/plastic = /datum/species/golem/plastic) + + if(istype(I, /obj/item/stack)) var/obj/item/stack/O = I - - if(istype(O, /obj/item/stack/sheet/metal)) - species = /datum/species/golem - - if(istype(O, /obj/item/stack/sheet/glass)) - species = /datum/species/golem/glass - - if(istype(O, /obj/item/stack/sheet/plasteel)) - species = /datum/species/golem/plasteel - - if(istype(O, /obj/item/stack/sheet/mineral/sandstone)) - species = /datum/species/golem/sand - - if(istype(O, /obj/item/stack/sheet/mineral/plasma)) - species = /datum/species/golem/plasma - - if(istype(O, /obj/item/stack/sheet/mineral/diamond)) - species = /datum/species/golem/diamond - - if(istype(O, /obj/item/stack/sheet/mineral/gold)) - species = /datum/species/golem/gold - - if(istype(O, /obj/item/stack/sheet/mineral/silver)) - species = /datum/species/golem/silver - - if(istype(O, /obj/item/stack/sheet/mineral/uranium)) - species = /datum/species/golem/uranium - - if(istype(O, /obj/item/stack/sheet/mineral/bananium)) - species = /datum/species/golem/bananium - - if(istype(O, /obj/item/stack/sheet/mineral/titanium)) - species = /datum/species/golem/titanium - - if(istype(O, /obj/item/stack/sheet/mineral/plastitanium)) - species = /datum/species/golem/plastitanium - - if(istype(O, /obj/item/stack/sheet/mineral/abductor)) - species = /datum/species/golem/alloy - - if(istype(O, /obj/item/stack/sheet/mineral/wood)) - species = /datum/species/golem/wood - - if(istype(O, /obj/item/stack/sheet/bluespace_crystal)) - species = /datum/species/golem/bluespace - - if(istype(O, /obj/item/stack/sheet/runed_metal)) - species = /datum/species/golem/runic - - if(istype(O, /obj/item/stack/medical/gauze) || istype(O, /obj/item/stack/sheet/cloth)) - species = /datum/species/golem/cloth - - if(istype(O, /obj/item/stack/sheet/mineral/adamantine)) - species = /datum/species/golem/adamantine - - if(istype(O, /obj/item/stack/sheet/plastic)) - species = /datum/species/golem/plastic - + var/species = golem_shell_species_types[O.merge_type] if(species) if(O.use(10)) to_chat(user, "You finish up the golem shell with ten sheets of [O].") From c3fed32afbcb55111662e13473554c504cf7085f Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 10 Sep 2017 15:17:25 -0500 Subject: [PATCH 033/102] Update prolonging_prism.dm --- .../clock_structures/prolonging_prism.dm | 903 +++++++++++++++--- 1 file changed, 779 insertions(+), 124 deletions(-) diff --git a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm index a6bc9a7f38..c6692073b0 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm @@ -1,135 +1,790 @@ -//Prolonging Prism: A prism that consumes power to delay the shuttle -/obj/structure/destructible/clockwork/powered/prolonging_prism - name = "prolonging prism" - desc = "A dark onyx prism, held in midair by spiraling tendrils of stone." - clockwork_desc = "A powerful prism that will delay the arrival of an emergency shuttle." - icon_state = "prolonging_prism_inactive" - active_icon = "prolonging_prism" - inactive_icon = "prolonging_prism_inactive" - unanchored_icon = "prolonging_prism_unwrenched" - construction_value = 20 - max_integrity = 125 - break_message = "The prism falls to the ground with a heavy thud!" - debris = list(/obj/item/clockwork/alloy_shards/small = 3, \ - /obj/item/clockwork/alloy_shards/medium = 1, \ - /obj/item/clockwork/alloy_shards/large = 1, \ - /obj/item/clockwork/component/vanguard_cogwheel/onyx_prism = 1) - var/static/list/component_refund = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1) - var/static/delay_cost = 3000 - var/static/delay_cost_increase = 1250 - var/static/delay_remaining = 0 +#define WELDER_FUEL_BURN_INTERVAL 13 -/obj/structure/destructible/clockwork/powered/prolonging_prism/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE) - to_chat(user, "An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.") - else - var/efficiency = get_efficiency_mod(TRUE) - to_chat(user, "It requires at least [get_delay_cost()]W of power to attempt to delay the arrival of an emergency shuttle by [2 * efficiency] minutes.") - to_chat(user, "This cost increases by [delay_cost_increase]W for every previous activation.") +/* Tools! + * Note: Multitools are /obj/item/device + * + * Contains: + * Wrench + * Screwdriver + * Wirecutters + * Welding Tool + * Crowbar + */ -/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects) - if(active) - if(bad_effects) - try_use_power(MIN_CLOCKCULT_POWER*4) - visible_message("[src] emits an airy chuckling sound and falls dark!") - toggle() - return TRUE +/* + * Wrench + */ +/obj/item/wrench + name = "wrench" + desc = "A wrench with common uses. Can be found in your hand." + icon = 'icons/obj/tools.dmi' + icon_state = "wrench" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + usesound = 'sound/items/ratchet.ogg' + materials = list(MAT_METAL=150) + origin_tech = "materials=1;engineering=1" + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) -/obj/structure/destructible/clockwork/powered/prolonging_prism/attack_hand(mob/living/user) - if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user)) - if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE) - to_chat(user, "You break [src] apart, refunding some of the components used.") - for(var/i in component_refund) - generate_cache_component(i, src) - take_damage(max_integrity) - return 0 - if(active) - return 0 - var/turf/T = get_turf(src) - if(!T || T.z != ZLEVEL_STATION) - to_chat(user, "[src] must be on the station to function!") - return 0 - if(SSshuttle.emergency.mode != SHUTTLE_CALL) - to_chat(user, "No emergency shuttles are attempting to arrive at the station!") - return 0 - if(!try_use_power(get_delay_cost())) - to_chat(user, "[src] needs more power to function!") - return 0 - delay_cost += delay_cost_increase - delay_remaining += PRISM_DELAY_DURATION - toggle(0, user) +/obj/item/wrench/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) -/obj/structure/destructible/clockwork/powered/prolonging_prism/process() - var/turf/own_turf = get_turf(src) - if(SSshuttle.emergency.mode != SHUTTLE_CALL || delay_remaining <= 0 || !own_turf || own_turf.z != ZLEVEL_STATION) - forced_disable(FALSE) +/obj/item/wrench/cyborg + name = "automatic wrench" + desc = "An advanced robotic wrench. Can be found in construction cyborgs." + toolspeed = 0.5 + +/obj/item/wrench/brass + name = "brass wrench" + desc = "A brass wrench. It's faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "wrench_brass" + toolspeed = 0.5 + +/obj/item/wrench/abductor + name = "alien wrench" + desc = "A polarized wrench. It causes anything placed between the jaws to turn." + icon = 'icons/obj/abductor.dmi' + icon_state = "wrench" + usesound = 'sound/effects/empulse.ogg' + toolspeed = 0.1 + origin_tech = "materials=5;engineering=5;abductor=3" + +/obj/item/wrench/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a bolt bit." + icon_state = "drill_bolt" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/drill_use.ogg' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + attack_verb = list("drilled", "screwed", "jabbed") + toolspeed = 0.25 + +/obj/item/wrench/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power + to_chat(user, "You attach the screw driver bit to [src].") + qdel(src) + user.put_in_active_hand(s_drill) + +/obj/item/wrench/power/suicide_act(mob/user) + user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/wrench/medical + name = "medical wrench" + desc = "A medical wrench with common(medical?) uses. Can be found in your hand." + icon_state = "wrench_medical" + force = 2 //MEDICAL + throwforce = 4 + origin_tech = "materials=1;engineering=1;biotech=3" + attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") + +/obj/item/wrench/medical/suicide_act(mob/living/user) + user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") + // TODO Make them glow with the power of the M E D I C A L W R E N C H + // during their ascension + + // Stun stops them from wandering off + user.Stun(100, ignore_canstun = TRUE) + playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) + + // Let the sound effect finish playing + sleep(20) + + if(!user) return + + for(var/obj/item/W in user) + user.dropItemToGround(W) + + var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) + W.add_fingerprint(user) + W.desc += " For some reason, it reminds you of [user.name]." + + if(!user) + return + + user.dust() + + return OXYLOSS + +/* + * Screwdriver + */ +/obj/item/screwdriver + name = "screwdriver" + desc = "You can be totally screwy with this." + icon = 'icons/obj/tools.dmi' + icon_state = "screwdriver" + item_state = "screwdriver" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + w_class = WEIGHT_CLASS_TINY + throwforce = 5 + throw_speed = 3 + throw_range = 5 + materials = list(MAT_METAL=75) + attack_verb = list("stabbed") + hitsound = 'sound/weapons/bladeslice.ogg' + usesound = 'sound/items/screwdriver.ogg' + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + var/random_color = TRUE //if the screwdriver uses random coloring + var/static/list/screwdriver_colors = list(\ + "blue" = rgb(24, 97, 213), \ + "red" = rgb(149, 23, 16), \ + "pink" = rgb(213, 24, 141), \ + "brown" = rgb(160, 82, 18), \ + "green" = rgb(14, 127, 27), \ + "cyan" = rgb(24, 162, 213), \ + "yellow" = rgb(213, 140, 24), \ + ) + +/obj/item/screwdriver/suicide_act(mob/user) + user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/Initialize() . = ..() - var/delay_amount = 40 - delay_remaining -= delay_amount - var/efficiency = get_efficiency_mod() - SSshuttle.emergency.setTimer(SSshuttle.emergency.timeLeft(1) + (delay_amount * efficiency)) - var/highest_y - var/highest_x - var/lowest_y - var/lowest_x - var/list/prism_turfs = list() - for(var/t in SSshuttle.emergency.ripple_area(SSshuttle.getDock("emergency_home"))) - prism_turfs[t] = TRUE - var/turf/T = t - if(!highest_y || T.y > highest_y) - highest_y = T.y - if(!highest_x || T.x > highest_x) - highest_x = T.x - if(!lowest_y || T.y < lowest_y) - lowest_y = T.y - if(!lowest_x || T.x < lowest_x) - lowest_x = T.x - var/mean_y = Lerp(lowest_y, highest_y) - var/mean_x = Lerp(lowest_x, highest_x) - if(prob(50)) - mean_y = Ceiling(mean_y) + if(random_color) //random colors! + var/our_color = pick(screwdriver_colors) + add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) + update_icon() + if(prob(75)) + pixel_y = rand(0, 16) + +/obj/item/screwdriver/update_icon() + if(!random_color) //icon override + return + cut_overlays() + var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") + base_overlay.appearance_flags = RESET_COLOR + add_overlay(base_overlay) + +/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) + . = list() + if(isinhands && random_color) + var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") + M.appearance_flags = RESET_COLOR + . += M + +/obj/item/screwdriver/get_belt_overlay() + if(random_color) + var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") + var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") + body.color = color + head.add_overlay(body) + return head else - mean_y = Floor(mean_y) - if(prob(50)) - mean_x = Ceiling(mean_x) + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) + +/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) + if(!istype(M)) + return ..() + if(user.zone_selected != "eyes" && user.zone_selected != "head") + return ..() + if(user.disabilities & CLUMSY && prob(50)) + M = user + return eyestab(M,user) + +/obj/item/screwdriver/brass + name = "brass screwdriver" + desc = "A screwdriver made of brass. The handle feels freezing cold." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "screwdriver_brass" + item_state = "screwdriver_brass" + toolspeed = 0.5 + random_color = FALSE + +/obj/item/screwdriver/abductor + name = "alien screwdriver" + desc = "An ultrasonic screwdriver." + icon = 'icons/obj/abductor.dmi' + icon_state = "screwdriver_a" + item_state = "screwdriver_nuke" + usesound = 'sound/items/pshoom.ogg' + toolspeed = 0.1 + random_color = FALSE + +/obj/item/screwdriver/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a screw bit." + icon_state = "drill_screw" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + throw_speed = 2 + throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far + attack_verb = list("drilled", "screwed", "jabbed","whacked") + hitsound = 'sound/items/drill_hit.ogg' + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.25 + random_color = FALSE + +/obj/item/screwdriver/power/suicide_act(mob/user) + user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power + to_chat(user, "You attach the bolt driver bit to [src].") + qdel(src) + user.put_in_active_hand(b_drill) + +/obj/item/screwdriver/cyborg + name = "powered screwdriver" + desc = "An electrical screwdriver, designed to be both precise and quick." + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.5 + +/* + * Wirecutters + */ +/obj/item/wirecutters + name = "wirecutters" + desc = "This cuts wires." + icon = 'icons/obj/tools.dmi' + icon_state = null + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 6 + throw_speed = 3 + throw_range = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=80) + attack_verb = list("pinched", "nipped") + hitsound = 'sound/items/wirecutter.ogg' + usesound = 'sound/items/wirecutter.ogg' + origin_tech = "materials=1;engineering=1" + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + + +/obj/item/wirecutters/New(loc, var/param_color = null) + ..() + if(!icon_state) + if(!param_color) + param_color = pick("yellow","red") + icon_state = "cutters_[param_color]" + +/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) + if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) + user.visible_message("[user] cuts [C]'s restraints with [src]!") + qdel(C.handcuffed) + C.handcuffed = null + if(C.buckled && C.buckled.buckle_requires_restraints) + C.buckled.unbuckle_mob(C) + C.update_handcuffed() + return else - mean_x = Floor(mean_x) - var/turf/semi_random_center_turf = locate(mean_x, mean_y, ZLEVEL_STATION) - for(var/t in getline(src, semi_random_center_turf)) - prism_turfs[t] = TRUE - var/placement_style = prob(50) - for(var/t in prism_turfs) - var/turf/T = t - if(placement_style) - if(IsOdd(T.x + T.y)) - seven_random_hexes(T, efficiency) - else if(prob(50 * efficiency)) - new /obj/effect/temp_visual/ratvar/prolonging_prism(T) + ..() + +/obj/item/wirecutters/suicide_act(mob/user) + user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, usesound, 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/brass + name = "brass wirecutters" + desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "cutters_brass" + toolspeed = 0.5 + +/obj/item/wirecutters/abductor + name = "alien wirecutters" + desc = "Extremely sharp wirecutters, made out of a silvery-green metal." + icon = 'icons/obj/abductor.dmi' + icon_state = "cutters" + toolspeed = 0.1 + origin_tech = "materials=5;engineering=4;abductor=3" + +/obj/item/wirecutters/cyborg + name = "wirecutters" + desc = "This cuts wires." + toolspeed = 0.5 + +/obj/item/wirecutters/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." + icon_state = "jaws_cutter" + item_state = "jawsoflife" + origin_tech = "materials=2;engineering=2" + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + usesound = 'sound/items/jaws_cut.ogg' + toolspeed = 0.25 + +/obj/item/wirecutters/power/suicide_act(mob/user) + user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") + playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/obj/item/bodypart/BP = C.get_bodypart("head") + if(BP) + BP.drop_limb() + playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power + to_chat(user, "You attach the pry jaws to [src].") + qdel(src) + user.put_in_active_hand(pryjaws) +/* + * Welding Tool + */ +/obj/item/weldingtool + name = "welding tool" + desc = "A standard edition welder provided by Nanotrasen." + icon = 'icons/obj/tools.dmi' + icon_state = "welder" + item_state = "welder" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 3 + throwforce = 5 + hitsound = "swing_hit" + usesound = 'sound/items/welder.ogg' + var/acti_sound = 'sound/items/welderactivate.ogg' + var/deac_sound = 'sound/items/welderdeactivate.ogg' + throw_speed = 3 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) + resistance_flags = FIRE_PROOF + + materials = list(MAT_METAL=70, MAT_GLASS=30) + origin_tech = "engineering=1;plasmatech=1" + var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) + var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) + var/max_fuel = 20 //The max amount of fuel the welder can hold + var/change_icons = 1 + var/can_off_process = 0 + var/light_intensity = 2 //how powerful the emitted light is when used. + var/burned_fuel_for = 0 //when fuel was last removed + heat = 3800 + toolspeed = 1 + +/obj/item/weldingtool/Initialize() + . = ..() + create_reagents(max_fuel) + reagents.add_reagent("welding_fuel", max_fuel) + update_icon() + + +/obj/item/weldingtool/proc/update_torch() + if(welding) + add_overlay("[initial(icon_state)]-on") + item_state = "[initial(item_state)]1" + else + item_state = "[initial(item_state)]" + + +/obj/item/weldingtool/update_icon() + cut_overlays() + if(change_icons) + var/ratio = get_fuel() / max_fuel + ratio = Ceiling(ratio*4) * 25 + add_overlay("[initial(icon_state)][ratio]") + update_torch() + return + + +/obj/item/weldingtool/process() + switch(welding) + if(0) + force = 3 + damtype = "brute" + update_icon() + if(!can_off_process) + STOP_PROCESSING(SSobj, src) + return + //Welders left on now use up fuel, but lets not have them run out quite that fast + if(1) + force = 15 + damtype = "fire" + ++burned_fuel_for + if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) + remove_fuel(1) + update_icon() + + //This is to start fires. process() is only called if the welder is on. + open_flame() + + +/obj/item/weldingtool/suicide_act(mob/user) + user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") + return (FIRELOSS) + + +/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/screwdriver)) + flamethrower_screwdriver(I, user) + else if(istype(I, /obj/item/stack/rods)) + flamethrower_rods(I, user) + else + return ..() + + +/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return ..() + + var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) + + if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) + if(src.remove_fuel(1)) + playsound(loc, usesound, 50, 1) + if(user == H) + user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") + if(!do_mob(user, H, 50)) + return + item_heal_robotic(H, user, 15, 0) + else + return ..() + + +/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) + if(!proximity) return + + if(welding) + remove_fuel(1) + var/turf/location = get_turf(user) + location.hotspot_expose(700, 50, 1) + if(get_fuel() <= 0) + set_light(0) + + if(isliving(O)) + var/mob/living/L = O + if(L.IgniteMob()) + message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") + log_game("[key_name(user)] set [key_name(L)] on fire") + + +/obj/item/weldingtool/attack_self(mob/user) + switched_on(user) + if(welding) + set_light(light_intensity) + + update_icon() + + +//Returns the amount of fuel in the welder +/obj/item/weldingtool/proc/get_fuel() + return reagents.get_reagent_amount("welding_fuel") + + +//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() +/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) + if(!welding || !check_fuel()) + return 0 + if(amount) + burned_fuel_for = 0 + if(get_fuel() >= amount) + reagents.remove_reagent("welding_fuel", amount) + check_fuel() + if(M) + M.flash_act(light_intensity) + return TRUE + else + if(M) + to_chat(M, "You need more welding fuel to complete this task!") + return FALSE + + +//Turns off the welder if there is no more fuel (does this really need to be its own proc?) +/obj/item/weldingtool/proc/check_fuel(mob/user) + if(get_fuel() <= 0 && welding) + switched_on(user) + update_icon() + //mob icon update + if(ismob(loc)) + var/mob/M = loc + M.update_inv_hands(0) + + return 0 + return 1 + +//Switches the welder on +/obj/item/weldingtool/proc/switched_on(mob/user) + if(!status) + to_chat(user, "[src] can't be turned on while unsecured!") + return + welding = !welding + if(welding) + if(get_fuel() >= 1) + to_chat(user, "You switch [src] on.") + playsound(loc, acti_sound, 50, 1) + force = 15 + damtype = "fire" + hitsound = 'sound/items/welder.ogg' + update_icon() + START_PROCESSING(SSobj, src) else - if(IsEven(T.x + T.y)) - seven_random_hexes(T, efficiency) - else if(prob(50 * efficiency)) - new /obj/effect/temp_visual/ratvar/prolonging_prism(T) - CHECK_TICK //we may be going over a hell of a lot of turfs + to_chat(user, "You need more fuel!") + switched_off(user) + else + to_chat(user, "You switch [src] off.") + playsound(loc, deac_sound, 50, 1) + switched_off(user) -/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/get_delay_cost() - return Floor(delay_cost, MIN_CLOCKCULT_POWER) +//Switches the welder off +/obj/item/weldingtool/proc/switched_off(mob/user) + welding = 0 + set_light(0) -/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/seven_random_hexes(turf/T, efficiency) - var/static/list/hex_states = list("prismhex1", "prismhex2", "prismhex3", "prismhex4", "prismhex5", "prismhex6", "prismhex7") - var/mutable_appearance/hex_combo - for(var/n in hex_states) //BUILD ME A HEXAGON - if(prob(50 * efficiency)) - if(!hex_combo) - hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER) - else - hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)) - if(hex_combo) //YOU BUILT A HEXAGON - hex_combo.pixel_x = -16 - hex_combo.pixel_y = -16 - hex_combo.mouse_opacity = MOUSE_OPACITY_TRANSPARENT - hex_combo.plane = GAME_PLANE - new /obj/effect/temp_visual/ratvar/prolonging_prism(T, hex_combo) + force = 3 + damtype = "brute" + hitsound = "swing_hit" + update_icon() + + +/obj/item/weldingtool/examine(mob/user) + ..() + to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") + +/obj/item/weldingtool/is_hot() + return welding * heat + +//Returns whether or not the welding tool is currently on. +/obj/item/weldingtool/proc/isOn() + return welding + + +/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) + if(welding) + to_chat(user, "Turn it off first!") + return + status = !status + if(status) + to_chat(user, "You resecure [src].") + else + to_chat(user, "[src] can now be attached and modified.") + add_fingerprint(user) + +/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) + if(!status) + var/obj/item/stack/rods/R = I + if (R.use(1)) + var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) + if(!remove_item_from_storage(F)) + user.transferItemToLoc(src, F, TRUE) + F.weldtool = src + add_fingerprint(user) + to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") + user.put_in_hands(F) + else + to_chat(user, "You need one rod to start building a flamethrower!") + +/obj/item/weldingtool/ignition_effect(atom/A, mob/user) + if(welding && remove_fuel(1, user)) + . = "[user] casually lights [A] with [src], what a badass." + else + . = "" + +/obj/item/weldingtool/largetank + name = "industrial welding tool" + desc = "A slightly larger welder with a larger tank." + icon_state = "indwelder" + max_fuel = 40 + materials = list(MAT_GLASS=60) + origin_tech = "engineering=2;plasmatech=2" + +/obj/item/weldingtool/largetank/cyborg + name = "integrated welding tool" + desc = "An advanced welder designed to be used in robotic systems." + toolspeed = 0.5 + +/obj/item/weldingtool/largetank/flamethrower_screwdriver() + return + + +/obj/item/weldingtool/mini + name = "emergency welding tool" + desc = "A miniature welder used during emergencies." + icon_state = "miniwelder" + max_fuel = 10 + w_class = WEIGHT_CLASS_TINY + materials = list(MAT_METAL=30, MAT_GLASS=10) + change_icons = 0 + +/obj/item/weldingtool/mini/flamethrower_screwdriver() + return + +/obj/item/weldingtool/abductor + name = "alien welding tool" + desc = "An alien welding tool. Whatever fuel it uses, it never runs out." + icon = 'icons/obj/abductor.dmi' + icon_state = "welder" + toolspeed = 0.1 + light_intensity = 0 + change_icons = 0 + origin_tech = "plasmatech=5;engineering=5;abductor=3" + +/obj/item/weldingtool/abductor/process() + if(get_fuel() <= max_fuel) + reagents.add_reagent("welding_fuel", 1) + ..() + +/obj/item/weldingtool/hugetank + name = "upgraded industrial welding tool" + desc = "An upgraded welder based of the industrial welder." + icon_state = "upindwelder" + item_state = "upindwelder" + max_fuel = 80 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "engineering=3;plasmatech=2" + +/obj/item/weldingtool/experimental + name = "experimental welding tool" + desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." + icon_state = "exwelder" + item_state = "exwelder" + max_fuel = 40 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" + var/last_gen = 0 + change_icons = 0 + can_off_process = 1 + light_intensity = 1 + toolspeed = 0.5 + var/nextrefueltick = 0 + +/obj/item/weldingtool/experimental/brass + name = "brass welding tool" + desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "brasswelder" + item_state = "brasswelder" + + +/obj/item/weldingtool/experimental/process() + ..() + if(get_fuel() < max_fuel && nextrefueltick < world.time) + nextrefueltick = world.time + 10 + reagents.add_reagent("welding_fuel", 1) + + +/* + * Crowbar + */ + +/obj/item/crowbar + name = "pocket crowbar" + desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." + icon = 'icons/obj/tools.dmi' + icon_state = "crowbar" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/crowbar.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + origin_tech = "engineering=1;combat=1" + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/crowbar/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/red + icon_state = "crowbar_red" + force = 8 + +/obj/item/crowbar/brass + name = "brass crowbar" + desc = "A brass crowbar. It feels faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "crowbar_brass" + toolspeed = 0.5 + +/obj/item/crowbar/abductor + name = "alien crowbar" + desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." + icon = 'icons/obj/abductor.dmi' + usesound = 'sound/weapons/sonic_jackhammer.ogg' + icon_state = "crowbar" + toolspeed = 0.1 + origin_tech = "combat=4;engineering=4;abductor=3" + +/obj/item/crowbar/large + name = "crowbar" + desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." + force = 12 + w_class = WEIGHT_CLASS_NORMAL + throw_speed = 3 + throw_range = 3 + materials = list(MAT_METAL=70) + icon_state = "crowbar_large" + item_state = "crowbar" + toolspeed = 0.5 + +/obj/item/crowbar/cyborg + name = "hydraulic crowbar" + desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." + usesound = 'sound/items/jaws_pry.ogg' + force = 10 + toolspeed = 0.5 + +/obj/item/crowbar/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." + icon_state = "jaws_pry" + item_state = "jawsoflife" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" + usesound = 'sound/items/jaws_pry.ogg' + force = 15 + toolspeed = 0.25 + +/obj/item/crowbar/power/suicide_act(mob/user) + user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power + to_chat(user, "You attach the cutting jaws to [src].") + qdel(src) + user.put_in_active_hand(cutjaws) + +#undef WELDER_FUEL_BURN_INTERVAL From 50587ea679a7df29066ac10d4675f9888e3491ee Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 10 Sep 2017 15:18:30 -0500 Subject: [PATCH 034/102] Update tools.dm --- code/game/objects/items/tools.dm | 1579 ------------------------------ 1 file changed, 1579 deletions(-) diff --git a/code/game/objects/items/tools.dm b/code/game/objects/items/tools.dm index 5c901ca4bd..d3f5a12faa 100644 --- a/code/game/objects/items/tools.dm +++ b/code/game/objects/items/tools.dm @@ -1,1580 +1 @@ -#define WELDER_FUEL_BURN_INTERVAL 13 -/* Tools! - * Note: Multitools are /obj/item/device - * - * Contains: - * Wrench - * Screwdriver - * Wirecutters - * Welding Tool - * Crowbar - */ - -/* - * Wrench - */ -/obj/item/wrench - name = "wrench" - desc = "A wrench with common uses. Can be found in your hand." - icon = 'icons/obj/tools.dmi' - icon_state = "wrench" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - usesound = 'sound/items/ratchet.ogg' - materials = list(MAT_METAL=150) - origin_tech = "materials=1;engineering=1" - attack_verb = list("bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/wrench/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wrench/cyborg - name = "automatic wrench" - desc = "An advanced robotic wrench. Can be found in construction cyborgs." - toolspeed = 0.5 - -/obj/item/wrench/brass - name = "brass wrench" - desc = "A brass wrench. It's faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "wrench_brass" - toolspeed = 0.5 - -/obj/item/wrench/abductor - name = "alien wrench" - desc = "A polarized wrench. It causes anything placed between the jaws to turn." - icon = 'icons/obj/abductor.dmi' - icon_state = "wrench" - usesound = 'sound/effects/empulse.ogg' - toolspeed = 0.1 - origin_tech = "materials=5;engineering=5;abductor=3" - -/obj/item/wrench/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a bolt bit." - icon_state = "drill_bolt" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/drill_use.ogg' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - attack_verb = list("drilled", "screwed", "jabbed") - toolspeed = 0.25 - -/obj/item/wrench/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power - to_chat(user, "You attach the screw driver bit to [src].") - qdel(src) - user.put_in_active_hand(s_drill) - -/obj/item/wrench/power/suicide_act(mob/user) - user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/wrench/medical - name = "medical wrench" - desc = "A medical wrench with common(medical?) uses. Can be found in your hand." - icon_state = "wrench_medical" - force = 2 //MEDICAL - throwforce = 4 - origin_tech = "materials=1;engineering=1;biotech=3" - attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") - -/obj/item/wrench/medical/suicide_act(mob/living/user) - user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") - // TODO Make them glow with the power of the M E D I C A L W R E N C H - // during their ascension - - // Stun stops them from wandering off - user.Stun(100, ignore_canstun = TRUE) - playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) - - // Let the sound effect finish playing - sleep(20) - - if(!user) - return - - for(var/obj/item/W in user) - user.dropItemToGround(W) - - var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) - W.add_fingerprint(user) - W.desc += " For some reason, it reminds you of [user.name]." - - if(!user) - return - - user.dust() - - return OXYLOSS - -/* - * Screwdriver - */ -/obj/item/screwdriver - name = "screwdriver" - desc = "You can be totally screwy with this." - icon = 'icons/obj/tools.dmi' - icon_state = "screwdriver" - item_state = "screwdriver" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - w_class = WEIGHT_CLASS_TINY - throwforce = 5 - throw_speed = 3 - throw_range = 5 - materials = list(MAT_METAL=75) - attack_verb = list("stabbed") - hitsound = 'sound/weapons/bladeslice.ogg' - usesound = 'sound/items/screwdriver.ogg' - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - var/random_color = TRUE //if the screwdriver uses random coloring - var/static/list/screwdriver_colors = list(\ - "blue" = rgb(24, 97, 213), \ - "red" = rgb(149, 23, 16), \ - "pink" = rgb(213, 24, 141), \ - "brown" = rgb(160, 82, 18), \ - "green" = rgb(14, 127, 27), \ - "cyan" = rgb(24, 162, 213), \ - "yellow" = rgb(213, 140, 24), \ - ) - -/obj/item/screwdriver/suicide_act(mob/user) - user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/Initialize() - . = ..() - if(random_color) //random colors! - var/our_color = pick(screwdriver_colors) - add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) - update_icon() - if(prob(75)) - pixel_y = rand(0, 16) - -/obj/item/screwdriver/update_icon() - if(!random_color) //icon override - return - cut_overlays() - var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") - base_overlay.appearance_flags = RESET_COLOR - add_overlay(base_overlay) - -/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) - . = list() - if(isinhands && random_color) - var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") - M.appearance_flags = RESET_COLOR - . += M - -/obj/item/screwdriver/get_belt_overlay() - if(random_color) - var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") - var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") - body.color = color - head.overlays += body - return head - else - return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) - -/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M)) - return ..() - if(user.zone_selected != "eyes" && user.zone_selected != "head") - return ..() - if(user.disabilities & CLUMSY && prob(50)) - M = user - return eyestab(M,user) - -/obj/item/screwdriver/brass - name = "brass screwdriver" - desc = "A screwdriver made of brass. The handle feels freezing cold." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "screwdriver_brass" - item_state = "screwdriver_brass" - toolspeed = 0.5 - random_color = FALSE - -/obj/item/screwdriver/abductor - name = "alien screwdriver" - desc = "An ultrasonic screwdriver." - icon = 'icons/obj/abductor.dmi' - icon_state = "screwdriver_a" - item_state = "screwdriver_nuke" - usesound = 'sound/items/pshoom.ogg' - toolspeed = 0.1 - random_color = FALSE - -/obj/item/screwdriver/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a screw bit." - icon_state = "drill_screw" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - throw_speed = 2 - throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far - attack_verb = list("drilled", "screwed", "jabbed","whacked") - hitsound = 'sound/items/drill_hit.ogg' - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.25 - random_color = FALSE - -/obj/item/screwdriver/power/suicide_act(mob/user) - user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power - to_chat(user, "You attach the bolt driver bit to [src].") - qdel(src) - user.put_in_active_hand(b_drill) - -/obj/item/screwdriver/cyborg - name = "powered screwdriver" - desc = "An electrical screwdriver, designed to be both precise and quick." - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.5 - -/* - * Wirecutters - */ -/obj/item/wirecutters - name = "wirecutters" - desc = "This cuts wires." - icon = 'icons/obj/tools.dmi' - icon_state = null - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 6 - throw_speed = 3 - throw_range = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=80) - attack_verb = list("pinched", "nipped") - hitsound = 'sound/items/wirecutter.ogg' - usesound = 'sound/items/wirecutter.ogg' - origin_tech = "materials=1;engineering=1" - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - - -/obj/item/wirecutters/New(loc, var/param_color = null) - ..() - if(!icon_state) - if(!param_color) - param_color = pick("yellow","red") - icon_state = "cutters_[param_color]" - -/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) - if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) - user.visible_message("[user] cuts [C]'s restraints with [src]!") - qdel(C.handcuffed) - C.handcuffed = null - if(C.buckled && C.buckled.buckle_requires_restraints) - C.buckled.unbuckle_mob(C) - C.update_handcuffed() - return - else - ..() - -/obj/item/wirecutters/suicide_act(mob/user) - user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, usesound, 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/brass - name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" - toolspeed = 0.5 - -/obj/item/wirecutters/abductor - name = "alien wirecutters" - desc = "Extremely sharp wirecutters, made out of a silvery-green metal." - icon = 'icons/obj/abductor.dmi' - icon_state = "cutters" - toolspeed = 0.1 - origin_tech = "materials=5;engineering=4;abductor=3" - -/obj/item/wirecutters/cyborg - name = "wirecutters" - desc = "This cuts wires." - toolspeed = 0.5 - -/obj/item/wirecutters/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." - icon_state = "jaws_cutter" - item_state = "jawsoflife" - origin_tech = "materials=2;engineering=2" - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - usesound = 'sound/items/jaws_cut.ogg' - toolspeed = 0.25 - -/obj/item/wirecutters/power/suicide_act(mob/user) - user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") - playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/bodypart/BP = C.get_bodypart("head") - if(BP) - BP.drop_limb() - playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power - to_chat(user, "You attach the pry jaws to [src].") - qdel(src) - user.put_in_active_hand(pryjaws) -/* - * Welding Tool - */ -/obj/item/weldingtool - name = "welding tool" - desc = "A standard edition welder provided by NanoTrasen." - icon = 'icons/obj/tools.dmi' - icon_state = "welder" - item_state = "welder" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 3 - throwforce = 5 - hitsound = "swing_hit" - usesound = 'sound/items/welder.ogg' - var/acti_sound = 'sound/items/welderactivate.ogg' - var/deac_sound = 'sound/items/welderdeactivate.ogg' - throw_speed = 3 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) - resistance_flags = FIRE_PROOF - - materials = list(MAT_METAL=70, MAT_GLASS=30) - origin_tech = "engineering=1;plasmatech=1" - var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) - var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) - var/max_fuel = 20 //The max amount of fuel the welder can hold - var/change_icons = 1 - var/can_off_process = 0 - var/light_intensity = 2 //how powerful the emitted light is when used. - var/burned_fuel_for = 0 //when fuel was last removed - heat = 3800 - toolspeed = 1 - -/obj/item/weldingtool/Initialize() - . = ..() - create_reagents(max_fuel) - reagents.add_reagent("welding_fuel", max_fuel) - update_icon() - - -/obj/item/weldingtool/proc/update_torch() - if(welding) - add_overlay("[initial(icon_state)]-on") - item_state = "[initial(item_state)]1" - else - item_state = "[initial(item_state)]" - - -/obj/item/weldingtool/update_icon() - cut_overlays() - if(change_icons) - var/ratio = get_fuel() / max_fuel - ratio = Ceiling(ratio*4) * 25 - add_overlay("[initial(icon_state)][ratio]") - update_torch() - return - - -/obj/item/weldingtool/process() - switch(welding) - if(0) - force = 3 - damtype = "brute" - update_icon() - if(!can_off_process) - STOP_PROCESSING(SSobj, src) - return - //Welders left on now use up fuel, but lets not have them run out quite that fast - if(1) - force = 15 - damtype = "fire" - ++burned_fuel_for - if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) - remove_fuel(1) - update_icon() - - //This is to start fires. process() is only called if the welder is on. - open_flame() - - -/obj/item/weldingtool/suicide_act(mob/user) - user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") - return (FIRELOSS) - - -/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) - flamethrower_screwdriver(I, user) - else if(istype(I, /obj/item/stack/rods)) - flamethrower_rods(I, user) - else - return ..() - - -/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) - if(!istype(H)) - return ..() - - var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - - if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) - if(src.remove_fuel(1)) - playsound(loc, usesound, 50, 1) - if(user == H) - user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") - if(!do_mob(user, H, 50)) - return - item_heal_robotic(H, user, 15, 0) - else - return ..() - - -/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) - if(!proximity) return - - if(welding) - remove_fuel(1) - var/turf/location = get_turf(user) - location.hotspot_expose(700, 50, 1) - if(get_fuel() <= 0) - set_light(0) - - if(isliving(O)) - var/mob/living/L = O - if(L.IgniteMob()) - message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") - log_game("[key_name(user)] set [key_name(L)] on fire") - - -/obj/item/weldingtool/attack_self(mob/user) - switched_on(user) - if(welding) - set_light(light_intensity) - - update_icon() - - -//Returns the amount of fuel in the welder -/obj/item/weldingtool/proc/get_fuel() - return reagents.get_reagent_amount("welding_fuel") - - -//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() -/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) - if(!welding || !check_fuel()) - return 0 - if(amount) - burned_fuel_for = 0 - if(get_fuel() >= amount) - reagents.remove_reagent("welding_fuel", amount) - check_fuel() - if(M) - M.flash_act(light_intensity) - return TRUE - else - if(M) - to_chat(M, "You need more welding fuel to complete this task!") - return FALSE - - -//Turns off the welder if there is no more fuel (does this really need to be its own proc?) -/obj/item/weldingtool/proc/check_fuel(mob/user) - if(get_fuel() <= 0 && welding) - switched_on(user) - update_icon() - //mob icon update - if(ismob(loc)) - var/mob/M = loc - M.update_inv_hands(0) - - return 0 - return 1 - -//Switches the welder on -/obj/item/weldingtool/proc/switched_on(mob/user) - if(!status) - to_chat(user, "[src] can't be turned on while unsecured!") - return - welding = !welding - if(welding) - if(get_fuel() >= 1) - to_chat(user, "You switch [src] on.") - playsound(loc, acti_sound, 50, 1) - force = 15 - damtype = "fire" - hitsound = 'sound/items/welder.ogg' - update_icon() - START_PROCESSING(SSobj, src) - else - to_chat(user, "You need more fuel!") - switched_off(user) - else - to_chat(user, "You switch [src] off.") - playsound(loc, deac_sound, 50, 1) - switched_off(user) - -//Switches the welder off -/obj/item/weldingtool/proc/switched_off(mob/user) - welding = 0 - set_light(0) - - force = 3 - damtype = "brute" - hitsound = "swing_hit" - update_icon() - - -/obj/item/weldingtool/examine(mob/user) - ..() - to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") - -/obj/item/weldingtool/is_hot() - return welding * heat - -//Returns whether or not the welding tool is currently on. -/obj/item/weldingtool/proc/isOn() - return welding - - -/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) - if(welding) - to_chat(user, "Turn it off first!") - return - status = !status - if(status) - to_chat(user, "You resecure [src].") - else - to_chat(user, "[src] can now be attached and modified.") - add_fingerprint(user) - -/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) - if(!status) - var/obj/item/stack/rods/R = I - if (R.use(1)) - var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) - if(!remove_item_from_storage(F)) - user.transferItemToLoc(src, F, TRUE) - F.weldtool = src - add_fingerprint(user) - to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") - user.put_in_hands(F) - else - to_chat(user, "You need one rod to start building a flamethrower!") - -/obj/item/weldingtool/ignition_effect(atom/A, mob/user) - if(welding && remove_fuel(1, user)) - . = "[user] casually lights [A] with [src], what a badass." - else - . = "" - -/obj/item/weldingtool/largetank - name = "industrial welding tool" - desc = "A slightly larger welder with a larger tank." - icon_state = "indwelder" - max_fuel = 40 - materials = list(MAT_GLASS=60) - origin_tech = "engineering=2;plasmatech=2" - -/obj/item/weldingtool/largetank/cyborg - name = "integrated welding tool" - desc = "An advanced welder designed to be used in robotic systems." - toolspeed = 0.5 - -/obj/item/weldingtool/largetank/flamethrower_screwdriver() - return - - -/obj/item/weldingtool/mini - name = "emergency welding tool" - desc = "A miniature welder used during emergencies." - icon_state = "miniwelder" - max_fuel = 10 - w_class = WEIGHT_CLASS_TINY - materials = list(MAT_METAL=30, MAT_GLASS=10) - change_icons = 0 - -/obj/item/weldingtool/mini/flamethrower_screwdriver() - return - -/obj/item/weldingtool/abductor - name = "alien welding tool" - desc = "An alien welding tool. Whatever fuel it uses, it never runs out." - icon = 'icons/obj/abductor.dmi' - icon_state = "welder" - toolspeed = 0.1 - light_intensity = 0 - change_icons = 0 - origin_tech = "plasmatech=5;engineering=5;abductor=3" - -/obj/item/weldingtool/abductor/process() - if(get_fuel() <= max_fuel) - reagents.add_reagent("welding_fuel", 1) - ..() - -/obj/item/weldingtool/hugetank - name = "upgraded industrial welding tool" - desc = "An upgraded welder based of the industrial welder." - icon_state = "upindwelder" - item_state = "upindwelder" - max_fuel = 80 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "engineering=3;plasmatech=2" - -/obj/item/weldingtool/experimental - name = "experimental welding tool" - desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." - icon_state = "exwelder" - item_state = "exwelder" - max_fuel = 40 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" - var/last_gen = 0 - change_icons = 0 - can_off_process = 1 - light_intensity = 1 - toolspeed = 0.5 - var/nextrefueltick = 0 - -/obj/item/weldingtool/experimental/brass - name = "brass welding tool" - desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "brasswelder" - item_state = "brasswelder" - - -/obj/item/weldingtool/experimental/process() - ..() - if(get_fuel() < max_fuel && nextrefueltick < world.time) - nextrefueltick = world.time + 10 - reagents.add_reagent("welding_fuel", 1) - - -/* - * Crowbar - */ - -/obj/item/crowbar - name = "pocket crowbar" - desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." - icon = 'icons/obj/tools.dmi' - icon_state = "crowbar" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/crowbar.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - origin_tech = "engineering=1;combat=1" - attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/crowbar/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/red - icon_state = "crowbar_red" - force = 8 - -/obj/item/crowbar/brass - name = "brass crowbar" - desc = "A brass crowbar. It feels faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "crowbar_brass" - toolspeed = 0.5 - -/obj/item/crowbar/abductor - name = "alien crowbar" - desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." - icon = 'icons/obj/abductor.dmi' - usesound = 'sound/weapons/sonic_jackhammer.ogg' - icon_state = "crowbar" - toolspeed = 0.1 - origin_tech = "combat=4;engineering=4;abductor=3" - -/obj/item/crowbar/large - name = "crowbar" - desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." - force = 12 - w_class = WEIGHT_CLASS_NORMAL - throw_speed = 3 - throw_range = 3 - materials = list(MAT_METAL=70) - icon_state = "crowbar_large" - item_state = "crowbar" - toolspeed = 0.5 - -/obj/item/crowbar/cyborg - name = "hydraulic crowbar" - desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." - usesound = 'sound/items/jaws_pry.ogg' - force = 10 - toolspeed = 0.5 - -/obj/item/crowbar/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." - icon_state = "jaws_pry" - item_state = "jawsoflife" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" - usesound = 'sound/items/jaws_pry.ogg' - force = 15 - toolspeed = 0.25 - -/obj/item/crowbar/power/suicide_act(mob/user) - user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power - to_chat(user, "You attach the cutting jaws to [src].") - qdel(src) - user.put_in_active_hand(cutjaws) - -#undef WELDER_FUEL_BURN_INTERVAL -#define WELDER_FUEL_BURN_INTERVAL 13 - -/* Tools! - * Note: Multitools are /obj/item/device - * - * Contains: - * Wrench - * Screwdriver - * Wirecutters - * Welding Tool - * Crowbar - */ - -/* - * Wrench - */ -/obj/item/wrench - name = "wrench" - desc = "A wrench with common uses. Can be found in your hand." - icon = 'icons/obj/tools.dmi' - icon_state = "wrench" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - usesound = 'sound/items/ratchet.ogg' - materials = list(MAT_METAL=150) - origin_tech = "materials=1;engineering=1" - attack_verb = list("bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/wrench/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wrench/cyborg - name = "automatic wrench" - desc = "An advanced robotic wrench. Can be found in construction cyborgs." - toolspeed = 0.5 - -/obj/item/wrench/brass - name = "brass wrench" - desc = "A brass wrench. It's faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "wrench_brass" - toolspeed = 0.5 - -/obj/item/wrench/abductor - name = "alien wrench" - desc = "A polarized wrench. It causes anything placed between the jaws to turn." - icon = 'icons/obj/abductor.dmi' - icon_state = "wrench" - usesound = 'sound/effects/empulse.ogg' - toolspeed = 0.1 - origin_tech = "materials=5;engineering=5;abductor=3" - -/obj/item/wrench/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a bolt bit." - icon_state = "drill_bolt" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/drill_use.ogg' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - attack_verb = list("drilled", "screwed", "jabbed") - toolspeed = 0.25 - -/obj/item/wrench/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power - to_chat(user, "You attach the screw driver bit to [src].") - qdel(src) - user.put_in_active_hand(s_drill) - -/obj/item/wrench/power/suicide_act(mob/user) - user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/wrench/medical - name = "medical wrench" - desc = "A medical wrench with common(medical?) uses. Can be found in your hand." - icon_state = "wrench_medical" - force = 2 //MEDICAL - throwforce = 4 - origin_tech = "materials=1;engineering=1;biotech=3" - attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") - -/obj/item/wrench/medical/suicide_act(mob/living/user) - user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") - // TODO Make them glow with the power of the M E D I C A L W R E N C H - // during their ascension - - // Stun stops them from wandering off - user.Stun(100, ignore_canstun = TRUE) - playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) - - // Let the sound effect finish playing - sleep(20) - - if(!user) - return - - for(var/obj/item/W in user) - user.dropItemToGround(W) - - var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) - W.add_fingerprint(user) - W.desc += " For some reason, it reminds you of [user.name]." - - if(!user) - return - - user.dust() - - return OXYLOSS - -/* - * Screwdriver - */ -/obj/item/screwdriver - name = "screwdriver" - desc = "You can be totally screwy with this." - icon = 'icons/obj/tools.dmi' - icon_state = "screwdriver" - item_state = "screwdriver" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - w_class = WEIGHT_CLASS_TINY - throwforce = 5 - throw_speed = 3 - throw_range = 5 - materials = list(MAT_METAL=75) - attack_verb = list("stabbed") - hitsound = 'sound/weapons/bladeslice.ogg' - usesound = 'sound/items/screwdriver.ogg' - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - var/random_color = TRUE //if the screwdriver uses random coloring - var/static/list/screwdriver_colors = list(\ - "blue" = rgb(24, 97, 213), \ - "red" = rgb(149, 23, 16), \ - "pink" = rgb(213, 24, 141), \ - "brown" = rgb(160, 82, 18), \ - "green" = rgb(14, 127, 27), \ - "cyan" = rgb(24, 162, 213), \ - "yellow" = rgb(213, 140, 24), \ - ) - -/obj/item/screwdriver/suicide_act(mob/user) - user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/Initialize() - . = ..() - if(random_color) //random colors! - var/our_color = pick(screwdriver_colors) - add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) - update_icon() - if(prob(75)) - pixel_y = rand(0, 16) - -/obj/item/screwdriver/update_icon() - if(!random_color) //icon override - return - cut_overlays() - var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") - base_overlay.appearance_flags = RESET_COLOR - add_overlay(base_overlay) - -/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) - . = list() - if(isinhands && random_color) - var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") - M.appearance_flags = RESET_COLOR - . += M - -/obj/item/screwdriver/get_belt_overlay() - if(random_color) - var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") - var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") - body.color = color - head.add_overlay(body) - return head - else - return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) - -/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M)) - return ..() - if(user.zone_selected != "eyes" && user.zone_selected != "head") - return ..() - if(user.disabilities & CLUMSY && prob(50)) - M = user - return eyestab(M,user) - -/obj/item/screwdriver/brass - name = "brass screwdriver" - desc = "A screwdriver made of brass. The handle feels freezing cold." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "screwdriver_brass" - item_state = "screwdriver_brass" - toolspeed = 0.5 - random_color = FALSE - -/obj/item/screwdriver/abductor - name = "alien screwdriver" - desc = "An ultrasonic screwdriver." - icon = 'icons/obj/abductor.dmi' - icon_state = "screwdriver_a" - item_state = "screwdriver_nuke" - usesound = 'sound/items/pshoom.ogg' - toolspeed = 0.1 - random_color = FALSE - -/obj/item/screwdriver/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a screw bit." - icon_state = "drill_screw" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - throw_speed = 2 - throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far - attack_verb = list("drilled", "screwed", "jabbed","whacked") - hitsound = 'sound/items/drill_hit.ogg' - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.25 - random_color = FALSE - -/obj/item/screwdriver/power/suicide_act(mob/user) - user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power - to_chat(user, "You attach the bolt driver bit to [src].") - qdel(src) - user.put_in_active_hand(b_drill) - -/obj/item/screwdriver/cyborg - name = "powered screwdriver" - desc = "An electrical screwdriver, designed to be both precise and quick." - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.5 - -/* - * Wirecutters - */ -/obj/item/wirecutters - name = "wirecutters" - desc = "This cuts wires." - icon = 'icons/obj/tools.dmi' - icon_state = null - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 6 - throw_speed = 3 - throw_range = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=80) - attack_verb = list("pinched", "nipped") - hitsound = 'sound/items/wirecutter.ogg' - usesound = 'sound/items/wirecutter.ogg' - origin_tech = "materials=1;engineering=1" - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - - -/obj/item/wirecutters/New(loc, var/param_color = null) - ..() - if(!icon_state) - if(!param_color) - param_color = pick("yellow","red") - icon_state = "cutters_[param_color]" - -/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) - if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) - user.visible_message("[user] cuts [C]'s restraints with [src]!") - qdel(C.handcuffed) - C.handcuffed = null - if(C.buckled && C.buckled.buckle_requires_restraints) - C.buckled.unbuckle_mob(C) - C.update_handcuffed() - return - else - ..() - -/obj/item/wirecutters/suicide_act(mob/user) - user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, usesound, 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/brass - name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" - toolspeed = 0.5 - -/obj/item/wirecutters/abductor - name = "alien wirecutters" - desc = "Extremely sharp wirecutters, made out of a silvery-green metal." - icon = 'icons/obj/abductor.dmi' - icon_state = "cutters" - toolspeed = 0.1 - origin_tech = "materials=5;engineering=4;abductor=3" - -/obj/item/wirecutters/cyborg - name = "wirecutters" - desc = "This cuts wires." - toolspeed = 0.5 - -/obj/item/wirecutters/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." - icon_state = "jaws_cutter" - item_state = "jawsoflife" - origin_tech = "materials=2;engineering=2" - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - usesound = 'sound/items/jaws_cut.ogg' - toolspeed = 0.25 - -/obj/item/wirecutters/power/suicide_act(mob/user) - user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") - playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/bodypart/BP = C.get_bodypart("head") - if(BP) - BP.drop_limb() - playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power - to_chat(user, "You attach the pry jaws to [src].") - qdel(src) - user.put_in_active_hand(pryjaws) -/* - * Welding Tool - */ -/obj/item/weldingtool - name = "welding tool" - desc = "A standard edition welder provided by Nanotrasen." - icon = 'icons/obj/tools.dmi' - icon_state = "welder" - item_state = "welder" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 3 - throwforce = 5 - hitsound = "swing_hit" - usesound = 'sound/items/welder.ogg' - var/acti_sound = 'sound/items/welderactivate.ogg' - var/deac_sound = 'sound/items/welderdeactivate.ogg' - throw_speed = 3 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) - resistance_flags = FIRE_PROOF - - materials = list(MAT_METAL=70, MAT_GLASS=30) - origin_tech = "engineering=1;plasmatech=1" - var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) - var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) - var/max_fuel = 20 //The max amount of fuel the welder can hold - var/change_icons = 1 - var/can_off_process = 0 - var/light_intensity = 2 //how powerful the emitted light is when used. - var/burned_fuel_for = 0 //when fuel was last removed - heat = 3800 - toolspeed = 1 - -/obj/item/weldingtool/Initialize() - . = ..() - create_reagents(max_fuel) - reagents.add_reagent("welding_fuel", max_fuel) - update_icon() - - -/obj/item/weldingtool/proc/update_torch() - if(welding) - add_overlay("[initial(icon_state)]-on") - item_state = "[initial(item_state)]1" - else - item_state = "[initial(item_state)]" - - -/obj/item/weldingtool/update_icon() - cut_overlays() - if(change_icons) - var/ratio = get_fuel() / max_fuel - ratio = Ceiling(ratio*4) * 25 - add_overlay("[initial(icon_state)][ratio]") - update_torch() - return - - -/obj/item/weldingtool/process() - switch(welding) - if(0) - force = 3 - damtype = "brute" - update_icon() - if(!can_off_process) - STOP_PROCESSING(SSobj, src) - return - //Welders left on now use up fuel, but lets not have them run out quite that fast - if(1) - force = 15 - damtype = "fire" - ++burned_fuel_for - if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) - remove_fuel(1) - update_icon() - - //This is to start fires. process() is only called if the welder is on. - open_flame() - - -/obj/item/weldingtool/suicide_act(mob/user) - user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") - return (FIRELOSS) - - -/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) - flamethrower_screwdriver(I, user) - else if(istype(I, /obj/item/stack/rods)) - flamethrower_rods(I, user) - else - return ..() - - -/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) - if(!istype(H)) - return ..() - - var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - - if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) - if(src.remove_fuel(1)) - playsound(loc, usesound, 50, 1) - if(user == H) - user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") - if(!do_mob(user, H, 50)) - return - item_heal_robotic(H, user, 15, 0) - else - return ..() - - -/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) - if(!proximity) return - - if(welding) - remove_fuel(1) - var/turf/location = get_turf(user) - location.hotspot_expose(700, 50, 1) - if(get_fuel() <= 0) - set_light(0) - - if(isliving(O)) - var/mob/living/L = O - if(L.IgniteMob()) - message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") - log_game("[key_name(user)] set [key_name(L)] on fire") - - -/obj/item/weldingtool/attack_self(mob/user) - switched_on(user) - if(welding) - set_light(light_intensity) - - update_icon() - - -//Returns the amount of fuel in the welder -/obj/item/weldingtool/proc/get_fuel() - return reagents.get_reagent_amount("welding_fuel") - - -//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() -/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) - if(!welding || !check_fuel()) - return 0 - if(amount) - burned_fuel_for = 0 - if(get_fuel() >= amount) - reagents.remove_reagent("welding_fuel", amount) - check_fuel() - if(M) - M.flash_act(light_intensity) - return TRUE - else - if(M) - to_chat(M, "You need more welding fuel to complete this task!") - return FALSE - - -//Turns off the welder if there is no more fuel (does this really need to be its own proc?) -/obj/item/weldingtool/proc/check_fuel(mob/user) - if(get_fuel() <= 0 && welding) - switched_on(user) - update_icon() - //mob icon update - if(ismob(loc)) - var/mob/M = loc - M.update_inv_hands(0) - - return 0 - return 1 - -//Switches the welder on -/obj/item/weldingtool/proc/switched_on(mob/user) - if(!status) - to_chat(user, "[src] can't be turned on while unsecured!") - return - welding = !welding - if(welding) - if(get_fuel() >= 1) - to_chat(user, "You switch [src] on.") - playsound(loc, acti_sound, 50, 1) - force = 15 - damtype = "fire" - hitsound = 'sound/items/welder.ogg' - update_icon() - START_PROCESSING(SSobj, src) - else - to_chat(user, "You need more fuel!") - switched_off(user) - else - to_chat(user, "You switch [src] off.") - playsound(loc, deac_sound, 50, 1) - switched_off(user) - -//Switches the welder off -/obj/item/weldingtool/proc/switched_off(mob/user) - welding = 0 - set_light(0) - - force = 3 - damtype = "brute" - hitsound = "swing_hit" - update_icon() - - -/obj/item/weldingtool/examine(mob/user) - ..() - to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") - -/obj/item/weldingtool/is_hot() - return welding * heat - -//Returns whether or not the welding tool is currently on. -/obj/item/weldingtool/proc/isOn() - return welding - - -/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) - if(welding) - to_chat(user, "Turn it off first!") - return - status = !status - if(status) - to_chat(user, "You resecure [src].") - else - to_chat(user, "[src] can now be attached and modified.") - add_fingerprint(user) - -/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) - if(!status) - var/obj/item/stack/rods/R = I - if (R.use(1)) - var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) - if(!remove_item_from_storage(F)) - user.transferItemToLoc(src, F, TRUE) - F.weldtool = src - add_fingerprint(user) - to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") - user.put_in_hands(F) - else - to_chat(user, "You need one rod to start building a flamethrower!") - -/obj/item/weldingtool/ignition_effect(atom/A, mob/user) - if(welding && remove_fuel(1, user)) - . = "[user] casually lights [A] with [src], what a badass." - else - . = "" - -/obj/item/weldingtool/largetank - name = "industrial welding tool" - desc = "A slightly larger welder with a larger tank." - icon_state = "indwelder" - max_fuel = 40 - materials = list(MAT_GLASS=60) - origin_tech = "engineering=2;plasmatech=2" - -/obj/item/weldingtool/largetank/cyborg - name = "integrated welding tool" - desc = "An advanced welder designed to be used in robotic systems." - toolspeed = 0.5 - -/obj/item/weldingtool/largetank/flamethrower_screwdriver() - return - - -/obj/item/weldingtool/mini - name = "emergency welding tool" - desc = "A miniature welder used during emergencies." - icon_state = "miniwelder" - max_fuel = 10 - w_class = WEIGHT_CLASS_TINY - materials = list(MAT_METAL=30, MAT_GLASS=10) - change_icons = 0 - -/obj/item/weldingtool/mini/flamethrower_screwdriver() - return - -/obj/item/weldingtool/abductor - name = "alien welding tool" - desc = "An alien welding tool. Whatever fuel it uses, it never runs out." - icon = 'icons/obj/abductor.dmi' - icon_state = "welder" - toolspeed = 0.1 - light_intensity = 0 - change_icons = 0 - origin_tech = "plasmatech=5;engineering=5;abductor=3" - -/obj/item/weldingtool/abductor/process() - if(get_fuel() <= max_fuel) - reagents.add_reagent("welding_fuel", 1) - ..() - -/obj/item/weldingtool/hugetank - name = "upgraded industrial welding tool" - desc = "An upgraded welder based of the industrial welder." - icon_state = "upindwelder" - item_state = "upindwelder" - max_fuel = 80 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "engineering=3;plasmatech=2" - -/obj/item/weldingtool/experimental - name = "experimental welding tool" - desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." - icon_state = "exwelder" - item_state = "exwelder" - max_fuel = 40 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" - var/last_gen = 0 - change_icons = 0 - can_off_process = 1 - light_intensity = 1 - toolspeed = 0.5 - var/nextrefueltick = 0 - -/obj/item/weldingtool/experimental/brass - name = "brass welding tool" - desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "brasswelder" - item_state = "brasswelder" - - -/obj/item/weldingtool/experimental/process() - ..() - if(get_fuel() < max_fuel && nextrefueltick < world.time) - nextrefueltick = world.time + 10 - reagents.add_reagent("welding_fuel", 1) - - -/* - * Crowbar - */ - -/obj/item/crowbar - name = "pocket crowbar" - desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." - icon = 'icons/obj/tools.dmi' - icon_state = "crowbar" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/crowbar.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - origin_tech = "engineering=1;combat=1" - attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/crowbar/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/red - icon_state = "crowbar_red" - force = 8 - -/obj/item/crowbar/brass - name = "brass crowbar" - desc = "A brass crowbar. It feels faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "crowbar_brass" - toolspeed = 0.5 - -/obj/item/crowbar/abductor - name = "alien crowbar" - desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." - icon = 'icons/obj/abductor.dmi' - usesound = 'sound/weapons/sonic_jackhammer.ogg' - icon_state = "crowbar" - toolspeed = 0.1 - origin_tech = "combat=4;engineering=4;abductor=3" - -/obj/item/crowbar/large - name = "crowbar" - desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." - force = 12 - w_class = WEIGHT_CLASS_NORMAL - throw_speed = 3 - throw_range = 3 - materials = list(MAT_METAL=70) - icon_state = "crowbar_large" - item_state = "crowbar" - toolspeed = 0.5 - -/obj/item/crowbar/cyborg - name = "hydraulic crowbar" - desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." - usesound = 'sound/items/jaws_pry.ogg' - force = 10 - toolspeed = 0.5 - -/obj/item/crowbar/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." - icon_state = "jaws_pry" - item_state = "jawsoflife" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" - usesound = 'sound/items/jaws_pry.ogg' - force = 15 - toolspeed = 0.25 - -/obj/item/crowbar/power/suicide_act(mob/user) - user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power - to_chat(user, "You attach the cutting jaws to [src].") - qdel(src) - user.put_in_active_hand(cutjaws) - -#undef WELDER_FUEL_BURN_INTERVAL From e5aed03bcb29a0865808e1b0e8777de585e17058 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 10 Sep 2017 15:20:58 -0500 Subject: [PATCH 035/102] all of my HATE --- code/game/objects/items/tools.dm | 789 +++++++++++++++++++++++++++++++ 1 file changed, 789 insertions(+) diff --git a/code/game/objects/items/tools.dm b/code/game/objects/items/tools.dm index d3f5a12faa..8bfc90decb 100644 --- a/code/game/objects/items/tools.dm +++ b/code/game/objects/items/tools.dm @@ -1 +1,790 @@ +#define WELDER_FUEL_BURN_INTERVAL 13 +/* Tools! + * Note: Multitools are /obj/item/device + * + * Contains: + * Wrench + * Screwdriver + * Wirecutters + * Welding Tool + * Crowbar + */ + +/* + * Wrench + */ +/obj/item/wrench + name = "wrench" + desc = "A wrench with common uses. Can be found in your hand." + icon = 'icons/obj/tools.dmi' + icon_state = "wrench" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + usesound = 'sound/items/ratchet.ogg' + materials = list(MAT_METAL=150) + origin_tech = "materials=1;engineering=1" + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/wrench/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wrench/cyborg + name = "automatic wrench" + desc = "An advanced robotic wrench. Can be found in construction cyborgs." + toolspeed = 0.5 + +/obj/item/wrench/brass + name = "brass wrench" + desc = "A brass wrench. It's faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "wrench_brass" + toolspeed = 0.5 + +/obj/item/wrench/abductor + name = "alien wrench" + desc = "A polarized wrench. It causes anything placed between the jaws to turn." + icon = 'icons/obj/abductor.dmi' + icon_state = "wrench" + usesound = 'sound/effects/empulse.ogg' + toolspeed = 0.1 + origin_tech = "materials=5;engineering=5;abductor=3" + +/obj/item/wrench/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a bolt bit." + icon_state = "drill_bolt" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/drill_use.ogg' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + attack_verb = list("drilled", "screwed", "jabbed") + toolspeed = 0.25 + +/obj/item/wrench/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power + to_chat(user, "You attach the screw driver bit to [src].") + qdel(src) + user.put_in_active_hand(s_drill) + +/obj/item/wrench/power/suicide_act(mob/user) + user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") + return (BRUTELOSS) + +/obj/item/wrench/medical + name = "medical wrench" + desc = "A medical wrench with common(medical?) uses. Can be found in your hand." + icon_state = "wrench_medical" + force = 2 //MEDICAL + throwforce = 4 + origin_tech = "materials=1;engineering=1;biotech=3" + attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") + +/obj/item/wrench/medical/suicide_act(mob/living/user) + user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") + // TODO Make them glow with the power of the M E D I C A L W R E N C H + // during their ascension + + // Stun stops them from wandering off + user.Stun(100, ignore_canstun = TRUE) + playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) + + // Let the sound effect finish playing + sleep(20) + + if(!user) + return + + for(var/obj/item/W in user) + user.dropItemToGround(W) + + var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) + W.add_fingerprint(user) + W.desc += " For some reason, it reminds you of [user.name]." + + if(!user) + return + + user.dust() + + return OXYLOSS + +/* + * Screwdriver + */ +/obj/item/screwdriver + name = "screwdriver" + desc = "You can be totally screwy with this." + icon = 'icons/obj/tools.dmi' + icon_state = "screwdriver" + item_state = "screwdriver" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + w_class = WEIGHT_CLASS_TINY + throwforce = 5 + throw_speed = 3 + throw_range = 5 + materials = list(MAT_METAL=75) + attack_verb = list("stabbed") + hitsound = 'sound/weapons/bladeslice.ogg' + usesound = 'sound/items/screwdriver.ogg' + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + var/random_color = TRUE //if the screwdriver uses random coloring + var/static/list/screwdriver_colors = list(\ + "blue" = rgb(24, 97, 213), \ + "red" = rgb(149, 23, 16), \ + "pink" = rgb(213, 24, 141), \ + "brown" = rgb(160, 82, 18), \ + "green" = rgb(14, 127, 27), \ + "cyan" = rgb(24, 162, 213), \ + "yellow" = rgb(213, 140, 24), \ + ) + +/obj/item/screwdriver/suicide_act(mob/user) + user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/Initialize() + . = ..() + if(random_color) //random colors! + var/our_color = pick(screwdriver_colors) + add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) + update_icon() + if(prob(75)) + pixel_y = rand(0, 16) + +/obj/item/screwdriver/update_icon() + if(!random_color) //icon override + return + cut_overlays() + var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") + base_overlay.appearance_flags = RESET_COLOR + add_overlay(base_overlay) + +/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) + . = list() + if(isinhands && random_color) + var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") + M.appearance_flags = RESET_COLOR + . += M + +/obj/item/screwdriver/get_belt_overlay() + if(random_color) + var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") + var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") + body.color = color + head.add_overlay(body) + return head + else + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) + +/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) + if(!istype(M)) + return ..() + if(user.zone_selected != "eyes" && user.zone_selected != "head") + return ..() + if(user.disabilities & CLUMSY && prob(50)) + M = user + return eyestab(M,user) + +/obj/item/screwdriver/brass + name = "brass screwdriver" + desc = "A screwdriver made of brass. The handle feels freezing cold." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "screwdriver_brass" + item_state = "screwdriver_brass" + toolspeed = 0.5 + random_color = FALSE + +/obj/item/screwdriver/abductor + name = "alien screwdriver" + desc = "An ultrasonic screwdriver." + icon = 'icons/obj/abductor.dmi' + icon_state = "screwdriver_a" + item_state = "screwdriver_nuke" + usesound = 'sound/items/pshoom.ogg' + toolspeed = 0.1 + random_color = FALSE + +/obj/item/screwdriver/power + name = "hand drill" + desc = "A simple powered hand drill. It's fitted with a screw bit." + icon_state = "drill_screw" + item_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get + force = 8 //might or might not be too high, subject to change + w_class = WEIGHT_CLASS_SMALL + throwforce = 8 + throw_speed = 2 + throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far + attack_verb = list("drilled", "screwed", "jabbed","whacked") + hitsound = 'sound/items/drill_hit.ogg' + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.25 + random_color = FALSE + +/obj/item/screwdriver/power/suicide_act(mob/user) + user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") + return(BRUTELOSS) + +/obj/item/screwdriver/power/attack_self(mob/user) + playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) + var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power + to_chat(user, "You attach the bolt driver bit to [src].") + qdel(src) + user.put_in_active_hand(b_drill) + +/obj/item/screwdriver/cyborg + name = "powered screwdriver" + desc = "An electrical screwdriver, designed to be both precise and quick." + usesound = 'sound/items/drill_use.ogg' + toolspeed = 0.5 + +/* + * Wirecutters + */ +/obj/item/wirecutters + name = "wirecutters" + desc = "This cuts wires." + icon = 'icons/obj/tools.dmi' + icon_state = null + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 6 + throw_speed = 3 + throw_range = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=80) + attack_verb = list("pinched", "nipped") + hitsound = 'sound/items/wirecutter.ogg' + usesound = 'sound/items/wirecutter.ogg' + origin_tech = "materials=1;engineering=1" + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + + +/obj/item/wirecutters/New(loc, var/param_color = null) + ..() + if(!icon_state) + if(!param_color) + param_color = pick("yellow","red") + icon_state = "cutters_[param_color]" + +/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) + if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) + user.visible_message("[user] cuts [C]'s restraints with [src]!") + qdel(C.handcuffed) + C.handcuffed = null + if(C.buckled && C.buckled.buckle_requires_restraints) + C.buckled.unbuckle_mob(C) + C.update_handcuffed() + return + else + ..() + +/obj/item/wirecutters/suicide_act(mob/user) + user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, usesound, 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/brass + name = "brass wirecutters" + desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "cutters_brass" + toolspeed = 0.5 + +/obj/item/wirecutters/abductor + name = "alien wirecutters" + desc = "Extremely sharp wirecutters, made out of a silvery-green metal." + icon = 'icons/obj/abductor.dmi' + icon_state = "cutters" + toolspeed = 0.1 + origin_tech = "materials=5;engineering=4;abductor=3" + +/obj/item/wirecutters/cyborg + name = "wirecutters" + desc = "This cuts wires." + toolspeed = 0.5 + +/obj/item/wirecutters/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." + icon_state = "jaws_cutter" + item_state = "jawsoflife" + origin_tech = "materials=2;engineering=2" + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + usesound = 'sound/items/jaws_cut.ogg' + toolspeed = 0.25 + +/obj/item/wirecutters/power/suicide_act(mob/user) + user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") + playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/obj/item/bodypart/BP = C.get_bodypart("head") + if(BP) + BP.drop_limb() + playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power + to_chat(user, "You attach the pry jaws to [src].") + qdel(src) + user.put_in_active_hand(pryjaws) +/* + * Welding Tool + */ +/obj/item/weldingtool + name = "welding tool" + desc = "A standard edition welder provided by Nanotrasen." + icon = 'icons/obj/tools.dmi' + icon_state = "welder" + item_state = "welder" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 3 + throwforce = 5 + hitsound = "swing_hit" + usesound = 'sound/items/welder.ogg' + var/acti_sound = 'sound/items/welderactivate.ogg' + var/deac_sound = 'sound/items/welderdeactivate.ogg' + throw_speed = 3 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) + resistance_flags = FIRE_PROOF + + materials = list(MAT_METAL=70, MAT_GLASS=30) + origin_tech = "engineering=1;plasmatech=1" + var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) + var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) + var/max_fuel = 20 //The max amount of fuel the welder can hold + var/change_icons = 1 + var/can_off_process = 0 + var/light_intensity = 2 //how powerful the emitted light is when used. + var/burned_fuel_for = 0 //when fuel was last removed + heat = 3800 + toolspeed = 1 + +/obj/item/weldingtool/Initialize() + . = ..() + create_reagents(max_fuel) + reagents.add_reagent("welding_fuel", max_fuel) + update_icon() + + +/obj/item/weldingtool/proc/update_torch() + if(welding) + add_overlay("[initial(icon_state)]-on") + item_state = "[initial(item_state)]1" + else + item_state = "[initial(item_state)]" + + +/obj/item/weldingtool/update_icon() + cut_overlays() + if(change_icons) + var/ratio = get_fuel() / max_fuel + ratio = Ceiling(ratio*4) * 25 + add_overlay("[initial(icon_state)][ratio]") + update_torch() + return + + +/obj/item/weldingtool/process() + switch(welding) + if(0) + force = 3 + damtype = "brute" + update_icon() + if(!can_off_process) + STOP_PROCESSING(SSobj, src) + return + //Welders left on now use up fuel, but lets not have them run out quite that fast + if(1) + force = 15 + damtype = "fire" + ++burned_fuel_for + if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) + remove_fuel(1) + update_icon() + + //This is to start fires. process() is only called if the welder is on. + open_flame() + + +/obj/item/weldingtool/suicide_act(mob/user) + user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") + return (FIRELOSS) + + +/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/screwdriver)) + flamethrower_screwdriver(I, user) + else if(istype(I, /obj/item/stack/rods)) + flamethrower_rods(I, user) + else + return ..() + + +/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return ..() + + var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) + + if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) + if(src.remove_fuel(1)) + playsound(loc, usesound, 50, 1) + if(user == H) + user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") + if(!do_mob(user, H, 50)) + return + item_heal_robotic(H, user, 15, 0) + else + return ..() + + +/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) + if(!proximity) return + + if(welding) + remove_fuel(1) + var/turf/location = get_turf(user) + location.hotspot_expose(700, 50, 1) + if(get_fuel() <= 0) + set_light(0) + + if(isliving(O)) + var/mob/living/L = O + if(L.IgniteMob()) + message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") + log_game("[key_name(user)] set [key_name(L)] on fire") + + +/obj/item/weldingtool/attack_self(mob/user) + switched_on(user) + if(welding) + set_light(light_intensity) + + update_icon() + + +//Returns the amount of fuel in the welder +/obj/item/weldingtool/proc/get_fuel() + return reagents.get_reagent_amount("welding_fuel") + + +//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() +/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) + if(!welding || !check_fuel()) + return 0 + if(amount) + burned_fuel_for = 0 + if(get_fuel() >= amount) + reagents.remove_reagent("welding_fuel", amount) + check_fuel() + if(M) + M.flash_act(light_intensity) + return TRUE + else + if(M) + to_chat(M, "You need more welding fuel to complete this task!") + return FALSE + + +//Turns off the welder if there is no more fuel (does this really need to be its own proc?) +/obj/item/weldingtool/proc/check_fuel(mob/user) + if(get_fuel() <= 0 && welding) + switched_on(user) + update_icon() + //mob icon update + if(ismob(loc)) + var/mob/M = loc + M.update_inv_hands(0) + + return 0 + return 1 + +//Switches the welder on +/obj/item/weldingtool/proc/switched_on(mob/user) + if(!status) + to_chat(user, "[src] can't be turned on while unsecured!") + return + welding = !welding + if(welding) + if(get_fuel() >= 1) + to_chat(user, "You switch [src] on.") + playsound(loc, acti_sound, 50, 1) + force = 15 + damtype = "fire" + hitsound = 'sound/items/welder.ogg' + update_icon() + START_PROCESSING(SSobj, src) + else + to_chat(user, "You need more fuel!") + switched_off(user) + else + to_chat(user, "You switch [src] off.") + playsound(loc, deac_sound, 50, 1) + switched_off(user) + +//Switches the welder off +/obj/item/weldingtool/proc/switched_off(mob/user) + welding = 0 + set_light(0) + + force = 3 + damtype = "brute" + hitsound = "swing_hit" + update_icon() + + +/obj/item/weldingtool/examine(mob/user) + ..() + to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") + +/obj/item/weldingtool/is_hot() + return welding * heat + +//Returns whether or not the welding tool is currently on. +/obj/item/weldingtool/proc/isOn() + return welding + + +/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) + if(welding) + to_chat(user, "Turn it off first!") + return + status = !status + if(status) + to_chat(user, "You resecure [src].") + else + to_chat(user, "[src] can now be attached and modified.") + add_fingerprint(user) + +/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) + if(!status) + var/obj/item/stack/rods/R = I + if (R.use(1)) + var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) + if(!remove_item_from_storage(F)) + user.transferItemToLoc(src, F, TRUE) + F.weldtool = src + add_fingerprint(user) + to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") + user.put_in_hands(F) + else + to_chat(user, "You need one rod to start building a flamethrower!") + +/obj/item/weldingtool/ignition_effect(atom/A, mob/user) + if(welding && remove_fuel(1, user)) + . = "[user] casually lights [A] with [src], what a badass." + else + . = "" + +/obj/item/weldingtool/largetank + name = "industrial welding tool" + desc = "A slightly larger welder with a larger tank." + icon_state = "indwelder" + max_fuel = 40 + materials = list(MAT_GLASS=60) + origin_tech = "engineering=2;plasmatech=2" + +/obj/item/weldingtool/largetank/cyborg + name = "integrated welding tool" + desc = "An advanced welder designed to be used in robotic systems." + toolspeed = 0.5 + +/obj/item/weldingtool/largetank/flamethrower_screwdriver() + return + + +/obj/item/weldingtool/mini + name = "emergency welding tool" + desc = "A miniature welder used during emergencies." + icon_state = "miniwelder" + max_fuel = 10 + w_class = WEIGHT_CLASS_TINY + materials = list(MAT_METAL=30, MAT_GLASS=10) + change_icons = 0 + +/obj/item/weldingtool/mini/flamethrower_screwdriver() + return + +/obj/item/weldingtool/abductor + name = "alien welding tool" + desc = "An alien welding tool. Whatever fuel it uses, it never runs out." + icon = 'icons/obj/abductor.dmi' + icon_state = "welder" + toolspeed = 0.1 + light_intensity = 0 + change_icons = 0 + origin_tech = "plasmatech=5;engineering=5;abductor=3" + +/obj/item/weldingtool/abductor/process() + if(get_fuel() <= max_fuel) + reagents.add_reagent("welding_fuel", 1) + ..() + +/obj/item/weldingtool/hugetank + name = "upgraded industrial welding tool" + desc = "An upgraded welder based of the industrial welder." + icon_state = "upindwelder" + item_state = "upindwelder" + max_fuel = 80 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "engineering=3;plasmatech=2" + +/obj/item/weldingtool/experimental + name = "experimental welding tool" + desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." + icon_state = "exwelder" + item_state = "exwelder" + max_fuel = 40 + materials = list(MAT_METAL=70, MAT_GLASS=120) + origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" + var/last_gen = 0 + change_icons = 0 + can_off_process = 1 + light_intensity = 1 + toolspeed = 0.5 + var/nextrefueltick = 0 + +/obj/item/weldingtool/experimental/brass + name = "brass welding tool" + desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "brasswelder" + item_state = "brasswelder" + + +/obj/item/weldingtool/experimental/process() + ..() + if(get_fuel() < max_fuel && nextrefueltick < world.time) + nextrefueltick = world.time + 10 + reagents.add_reagent("welding_fuel", 1) + + +/* + * Crowbar + */ + +/obj/item/crowbar + name = "pocket crowbar" + desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." + icon = 'icons/obj/tools.dmi' + icon_state = "crowbar" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + usesound = 'sound/items/crowbar.ogg' + flags_1 = CONDUCT_1 + slot_flags = SLOT_BELT + force = 5 + throwforce = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=50) + origin_tech = "engineering=1;combat=1" + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + toolspeed = 1 + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) + +/obj/item/crowbar/suicide_act(mob/user) + user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/red + icon_state = "crowbar_red" + force = 8 + +/obj/item/crowbar/brass + name = "brass crowbar" + desc = "A brass crowbar. It feels faintly warm to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "crowbar_brass" + toolspeed = 0.5 + +/obj/item/crowbar/abductor + name = "alien crowbar" + desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." + icon = 'icons/obj/abductor.dmi' + usesound = 'sound/weapons/sonic_jackhammer.ogg' + icon_state = "crowbar" + toolspeed = 0.1 + origin_tech = "combat=4;engineering=4;abductor=3" + +/obj/item/crowbar/large + name = "crowbar" + desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." + force = 12 + w_class = WEIGHT_CLASS_NORMAL + throw_speed = 3 + throw_range = 3 + materials = list(MAT_METAL=70) + icon_state = "crowbar_large" + item_state = "crowbar" + toolspeed = 0.5 + +/obj/item/crowbar/cyborg + name = "hydraulic crowbar" + desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." + usesound = 'sound/items/jaws_pry.ogg' + force = 10 + toolspeed = 0.5 + +/obj/item/crowbar/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." + icon_state = "jaws_pry" + item_state = "jawsoflife" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + origin_tech = "materials=2;engineering=2" + usesound = 'sound/items/jaws_pry.ogg' + force = 15 + toolspeed = 0.25 + +/obj/item/crowbar/power/suicide_act(mob/user) + user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) + return (BRUTELOSS) + +/obj/item/crowbar/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power + to_chat(user, "You attach the cutting jaws to [src].") + qdel(src) + user.put_in_active_hand(cutjaws) + +#undef WELDER_FUEL_BURN_INTERVAL From 5e3e52503696791e9100f681e9b9835d3294c10f Mon Sep 17 00:00:00 2001 From: AnturK Date: Sun, 10 Sep 2017 23:07:03 +0200 Subject: [PATCH 036/102] Fixes lockers alt-click --- code/game/objects/structures/crates_lockers/closets.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 78e672e49d..03168d42ea 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -388,7 +388,11 @@ /obj/structure/closet/AltClick(mob/user) ..() +<<<<<<< HEAD if(!user.canUseTopic(src, be_close=TRUE)) +======= + if(!user.canUseTopic(src, be_close=TRUE) || !isturf(loc)) +>>>>>>> 847e426... Fixes lockers alt-click (#30544) to_chat(user, "You can't do that right now!") return if(opened || !secure) From f63a75b137c1bdc22147d7646f4624135ac5b0e5 Mon Sep 17 00:00:00 2001 From: ExcessiveUseOfCobblestone <11748095+ExcessiveUseOfCobblestone@users.noreply.github.com> Date: Sun, 10 Sep 2017 18:08:20 -0400 Subject: [PATCH 037/102] Egyptian Clothing, Egyptian Null Rod, Craftable Mummy Costume! --- code/__DEFINES/construction.dm | 1 + code/game/objects/items/holy_weapons.dm | 11 +++++++++++ code/modules/clothing/head/misc.dm | 6 ++++++ code/modules/clothing/suits/miscellaneous.dm | 8 ++++++++ code/modules/clothing/under/miscellaneous.dm | 2 +- code/modules/crafting/craft.dm | 3 ++- code/modules/crafting/recipes.dm | 14 ++++++++++++++ icons/mob/inhands/weapons/staves_lefthand.dmi | Bin 2976 -> 3256 bytes .../mob/inhands/weapons/staves_righthand.dmi | Bin 2843 -> 3102 bytes icons/obj/guns/magic.dmi | Bin 10086 -> 10452 bytes 10 files changed, 43 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm index 46589408a2..ae3f9f6fe9 100644 --- a/code/__DEFINES/construction.dm +++ b/code/__DEFINES/construction.dm @@ -101,6 +101,7 @@ #define CAT_ROBOT "Robots" #define CAT_MISC "Misc" #define CAT_PRIMAL "Tribal" +#define CAT_CLOTHING "Clothing" #define CAT_FOOD "Foods" #define CAT_BREAD "Breads" #define CAT_BURGER "Burgers" diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index e82a40d10a..ac5519c698 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -405,3 +405,14 @@ attack_verb = list("poked", "impaled", "pierced", "jabbed") hitsound = 'sound/weapons/bladeslice.ogg' sharpness = IS_SHARP + +/obj/item/nullrod/egyptian + name = "egyptian staff" + desc = "A tutorial in mummification is carved into the staff. You could probably follow the steps yourself if you had some bandages." + icon = 'icons/obj/guns/magic.dmi' + icon_state = "pharoah_sceptre" + item_state = "pharoah_sceptre" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + w_class = WEIGHT_CLASS_NORMAL + attack_verb = list("bashes", "smacks", "whacks") diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 3a088ab1f2..db3bcd3538 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -302,3 +302,9 @@ desc = "A hat with bells, to add some merriness to the suit." icon_state = "jester_hat2" dynamic_hair_suffix = "" + +/obj/item/clothing/head/nemes + name = "headress of Nemes" + desc = "Lavish space tomb not included." + icon_state = "nemes_headdress" + icon_state = "nemes_headdress" \ No newline at end of file diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index fe6fe67b83..3540a7648c 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -423,6 +423,14 @@ flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT allowed = list(/obj/item/clothing/mask/facehugger/toy) +/obj/item/clothing/suit/nemes + name = "pharoah tunic" + desc = "Lavish space tomb not included." + icon_state = "pharoah" + icon_state = "pharoah" + body_parts_covered = CHEST|GROIN + + // WINTER COATS diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index ba5cd8b8d1..ea5300c692 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -702,4 +702,4 @@ body_parts_covered = CHEST|GROIN|ARMS|LEGS fitted = NO_FEMALE_UNIFORM can_adjust = FALSE - resistance_flags = NONE + resistance_flags = NONE \ No newline at end of file diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm index 9024f0845a..7efbe95ccd 100644 --- a/code/modules/crafting/craft.dm +++ b/code/modules/crafting/craft.dm @@ -7,7 +7,8 @@ CAT_ROBOT, CAT_MISC, CAT_PRIMAL, - CAT_FOOD) + CAT_FOOD, + CAT_CLOTHING) var/list/subcategories = list( list( //Weapon subcategories CAT_WEAPON, diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 1f12e671ec..d807d77b4b 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -569,3 +569,17 @@ tools = list(/obj/item/weldingtool, /obj/item/screwdriver, /obj/item/wrench) reqs = list(/obj/item/stack/sheet/metal = 15) category = CAT_MISC + +/datum/crafting_recipe/mummy/ + name = "Mummification Bandages (Mask)" + result = /obj/item/clothing/mask/mummy + time = 10 + tools = list(/obj/item/nullrod/egyptian) + reqs = list(/obj/item/stack/sheet/cloth = 2) + category = CAT_CLOTHING + + +/datum/crafting_recipe/mummy/body + name = "Mummification Bandages (Body)" + result = /obj/item/clothing/under/mummy + reqs = list(/obj/item/stack/sheet/cloth = 5) diff --git a/icons/mob/inhands/weapons/staves_lefthand.dmi b/icons/mob/inhands/weapons/staves_lefthand.dmi index 382e8e484821d6ae3fcff77354926b7773385321..1384624a58ab1bcd02c48e84e49c97129e1f22b7 100644 GIT binary patch delta 2857 zcmV+^3)b|Y7q}UaBmt+fC5-`p>9ZC7)+xGy36~iWwkZ{S3JEfFDZ*Bkpc$}4zF%H5o3`OVU6j50L zwZH%a3!*{{a0QeSw~nB31E*vmVAu(#yYS}mrj z6c1|xw#9rV1%jaOMMo+>Zu>ud0wAl(+(n{r+5i9v*GWV{RCt{2 zT8n=ZMG(HGNo{N)HAPdJmWqgP1wjybtN6g;`~4PtAoy$nTP&rqXv5yA@Bmq@RWj6!LepC2gMs`45HHcaoDBNH4 zo5lN8`P>y@0ZG7r)lzw+RQ3fZmqyV3hXo{mipZowakyi&JY2+UFrxAlQA>vQr2>*!5VbTK>i{wb+F0I#J)q>v#TE2vRd0=!miXvBOGr)^bv)IvlV%vVoBn}Nh_W%Gqv28z%0U84BYFFopZTqIscOc(E z+O~ZLgTY{bFc=I5gTY{6QOS{uk~=rp7NA1ffl9Z_zO?U@DixwWxJ1#Na0vGpsr@l5 zccoM+(S;z&2H~!Zjg1l7kFbHbMa+hXLg3O2l_V-Xw->Vq2<<-*#vICBAc)p@80B)rJ$4OfR@{~eeX7s9(Wvoig_5219t6)Pn+A%%x&8~#d0K_ zU@O>XFq~u>Qm)doycP7?etfi`Tc7~RY}=3BMQT5T0v7B??jp92R=|pV=`OH+csEfB zSh61u7GV7mal#CQw(K()3H+Ff=f>h=_M3`NYDk$4?VO?_qJRc_Y@%0pgKMtxz^_wq?ce++I0Sf+tz7YtBEdG z#ZMXqs#T$V#oO9|`e140GB{=*kgk^D-5{qq5}KmZ^uJWoJN zt$X@>0NM8rTNi!47GN+K3FEj4q;DKIJ647lsl6LnvIfcnHV+J9xv=xS+lYHEs5fCw9!d%7MvU9V5$ zY^$qATT3Eldk6*CBgY)g9SJ&C0Cm;qYiZI2&J>sn$sJ32v;xx#PeHXrrGSbD!)+*l zTtG4nfQLo_H4B_O5hOpAT`r_qd+wkn>0Yd?_t6eCOcz=sEv`@fp!%$`bnE*~G0Q3RieHcy#gTY`h z?sd#Oy!VlPkM5@>ee5w>z8vv?_{49Pn|w<_T^Vzr6oS`{LD;#@{*xls^?yN{f#%zzeUP?^3W3x zXP0+&R@KY_ow4e|+wZ*l9x3yw!%yzbEbr|5@6RTix#EKlKl=C+LcVi zedf{N5-V?gdN$afpGEJ_tE)y=OBXMF{{zxcIzD*&jhA1PCx4{8M*H*Xs?pZck3U`h z8D~h1D?eWR`tuLpdGnQjWAfaOl-F#3URgETTDo%e7m_a@ul{uDn=d|k_x!7onI9*w z@&3HRQ*AB%`Ww;L&zHad_REjoi_LmM-e2GpR`%zA|AXv=#^hIt5#N;;{Jg#W`TWi& zc=AFCEbhbJ>f8Of(gnrn6pYOl(3BBH*w|G9G zPxj~Solh_Y)&BfeJ)b}aKA*r~Fc=I5gTY`h7`?)uIWp04=Z3j?=Nb{!HD`V1+&vy@$do42HYi)H=&e~PMIxV!|%7C42 zyu(p119#j1%nC&PhbbVUG)Gedf@LlmZ!~wu|BMR6{f8;wj@}dsxE#rBM{%z#h3yOq zB>jgf;H35vu1mU~U$kg<|DrWPk{RX=gb3O1=??~@Mt04cIRo{x)}@xgTY`h z8228UYfWW;d%HmR-0FBOTH8*6R$6eqAlfrb1gCr;%9+q-ek%mt7yr8<9-W22_!YkqM}7?v}BiCtqtV! z?mQYphN%>RW#IRWP{cZm9l(Wt32$3?84=jjDX@t8N_!*TePrL&!OnFa+|)?0w6wSg z7a`#QuI~x`IxIP+fG5Gf-TuBL08~KX0H*Kh#h#+0ADYFL)E(Gla8>c%Ty>m(yXC*IgXj{>ZAFNKEqzk(YNdWwdN zwi>=Fj_Yg8*%aS>xT8VW;h^D-2iZH>Biy}vH|wLi0Z~?01?7r`Y9W_gAmo9~O_QgU zgBaBumg{PO1}T#mRmVGTNd1fTJIasyzvB!X27|$1Y%%-~8<6#Mn7^Ub00000NkvXX Hu0mjfE*@|a delta 2575 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 diff --git a/icons/mob/inhands/weapons/staves_righthand.dmi b/icons/mob/inhands/weapons/staves_righthand.dmi index 591b5d0a2cea8ba1f6c51fad9d55115ab8cbef59..94ee9bd6f1e224cdbb30d5d6cb280a74abd0f50b 100644 GIT binary patch delta 2726 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 diff --git a/icons/obj/guns/magic.dmi b/icons/obj/guns/magic.dmi index 45e7b49f4e15dc1cf2daf89cab721f8d27a7a152..b8e77530bef130ca79cd0c8789fa04d10ea52c74 100644 GIT binary patch literal 10452 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 WSeWQU7k;-QpsQ)1@m0+}^nU=1*~IJs literal 10086 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 Q`8hyW%Sf|I!{OEc00qC+=Kufz From 3aec72d4f45c928f2d683358fc36b18c46ed717c Mon Sep 17 00:00:00 2001 From: Militaires Date: Mon, 11 Sep 2017 01:10:33 +0300 Subject: [PATCH 038/102] Adds Gondoland and the rare Gondolas (#30530) A strange race of bear-like beings consisting of a head placed DIRECTLY on a pair of legs, their fur sells for extremely high prices. The gondoland asteroid is the last natural habitat for these rare creatures. --- .../SpaceRuins/gondolaasteroid.dmm | 1382 +++++++++++++++++ code/datums/ruins/space.dm | 9 +- .../objects/items/stacks/sheets/leather.dm | 7 + code/modules/cargo/exports/sheets.dm | 6 + .../living/simple_animal/friendly/gondola.dm | 29 + icons/mob/gondolas.dmi | Bin 0 -> 1020 bytes icons/obj/items_and_weapons.dmi | Bin 145318 -> 146373 bytes tgstation.dme | 1 + 8 files changed, 1433 insertions(+), 1 deletion(-) create mode 100644 _maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm create mode 100644 code/modules/mob/living/simple_animal/friendly/gondola.dm create mode 100644 icons/mob/gondolas.dmi diff --git a/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm b/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm new file mode 100644 index 0000000000..b7a5910b1e --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm @@ -0,0 +1,1382 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"b" = ( +/turf/closed/mineral/random, +/area/ruin/space/has_grav) +"c" = ( +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"d" = ( +/obj/structure/marker_beacon{ + light_color = "#FFE8AA"; + light_range = 20 + }, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"e" = ( +/obj/structure/flora/ausbushes/fullgrass, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"f" = ( +/obj/structure/flora/ausbushes/ywflowers, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"g" = ( +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav{ + dynamic_lighting = 1 + }) +"h" = ( +/mob/living/simple_animal/pet/gondola, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"i" = ( +/obj/structure/flora/ausbushes/sparsegrass, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"j" = ( +/obj/effect/overlay/coconut, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"k" = ( +/obj/effect/overlay/palmtree_l, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"l" = ( +/obj/structure/flora/ausbushes/stalkybush, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"m" = ( +/obj/structure/flora/ausbushes/grassybush, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"n" = ( +/obj/structure/flora/ausbushes/reedbush, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"o" = ( +/obj/structure/flora/ausbushes/lavendergrass, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"p" = ( +/obj/structure/flora/ausbushes/brflowers, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"q" = ( +/obj/structure/flora/ausbushes/fernybush, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"r" = ( +/obj/effect/overlay/palmtree_r, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"s" = ( +/obj/structure/flora/junglebush/large, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"t" = ( +/obj/structure/flora/ausbushes/sunnybush, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) +"u" = ( +/obj/machinery/door/airlock/survival_pod/vertical, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +a +a +a +"} +(2,1,1) = {" +a +a +a +a +b +b +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +a +a +"} +(3,1,1) = {" +a +a +b +b +b +b +b +a +a +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +"} +(4,1,1) = {" +a +b +b +b +b +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +b +b +b +b +b +"} +(5,1,1) = {" +a +b +b +b +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +c +c +c +b +b +b +"} +(6,1,1) = {" +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +f +c +c +c +h +c +b +b +"} +(7,1,1) = {" +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +o +c +r +c +b +b +b +b +b +c +"} +(8,1,1) = {" +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +c +b +c +c +c +c +c +c +c +c +j +c +c +c +c +b +b +b +c +"} +(9,1,1) = {" +a +a +a +a +a +b +b +b +b +b +b +b +b +c +k +c +c +q +c +c +j +c +c +k +c +c +c +c +m +c +c +b +b +b +c +"} +(10,1,1) = {" +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +c +s +c +c +c +c +c +c +i +c +c +c +b +b +b +c +"} +(11,1,1) = {" +a +a +b +b +b +b +b +b +b +b +b +b +b +b +c +i +n +f +c +c +d +c +c +j +c +h +c +l +c +d +c +b +b +b +c +"} +(12,1,1) = {" +a +a +b +b +b +b +b +b +b +b +b +b +c +c +c +c +o +o +c +h +c +c +c +c +c +c +c +i +o +c +c +b +b +b +c +"} +(13,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +i +c +q +c +c +c +c +c +c +s +c +c +c +c +b +b +b +b +c +"} +(14,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +h +c +c +c +c +l +c +c +c +m +i +c +c +c +c +c +c +c +b +b +b +b +b +c +"} +(15,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +c +i +o +c +c +c +c +c +c +c +c +b +b +b +b +c +"} +(16,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +c +c +o +p +c +c +c +c +r +c +c +c +c +b +b +b +c +"} +(17,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +e +n +c +c +c +c +c +c +c +c +c +c +c +b +b +c +"} +(18,1,1) = {" +a +b +b +b +b +b +b +b +b +b +c +e +c +b +b +b +b +b +c +c +c +c +c +c +i +t +c +c +c +i +c +c +b +b +b +"} +(19,1,1) = {" +a +b +b +b +b +b +b +b +b +g +c +c +c +c +c +b +b +b +b +c +r +j +c +c +c +f +c +c +c +c +c +c +u +c +u +"} +(20,1,1) = {" +a +c +b +b +b +b +b +b +b +h +c +c +d +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +b +b +b +b +"} +(21,1,1) = {" +a +c +c +b +b +b +b +b +b +c +c +c +k +c +i +i +c +c +q +c +c +c +c +c +d +c +h +c +c +c +c +c +b +b +b +"} +(22,1,1) = {" +a +c +c +b +b +b +b +b +b +c +c +c +c +c +c +l +c +c +c +c +c +c +c +c +c +c +c +c +c +r +c +c +b +b +b +"} +(23,1,1) = {" +a +c +c +b +b +b +b +b +b +c +c +j +c +c +c +c +c +c +c +c +c +h +s +c +c +c +s +c +c +c +c +c +b +b +b +"} +(24,1,1) = {" +a +a +c +c +b +b +b +b +e +c +c +c +c +c +h +c +c +c +c +c +c +c +c +c +m +c +c +c +c +c +c +c +b +b +b +"} +(25,1,1) = {" +a +a +c +c +b +b +b +c +c +c +c +c +c +c +c +c +i +l +c +c +c +c +c +c +n +m +c +c +c +c +c +b +b +b +a +"} +(26,1,1) = {" +a +a +c +c +b +b +b +c +c +c +c +c +c +c +c +m +p +i +c +f +c +c +c +c +c +c +k +c +c +j +c +b +b +b +a +"} +(27,1,1) = {" +a +a +c +c +b +b +b +b +c +c +c +c +c +c +c +c +c +c +c +d +m +i +c +c +c +c +c +c +c +c +b +b +b +a +a +"} +(28,1,1) = {" +a +a +a +c +c +b +b +b +c +c +c +c +c +e +c +c +c +c +c +c +i +l +p +c +c +c +c +c +c +b +b +b +b +a +a +"} +(29,1,1) = {" +a +a +a +c +c +b +b +c +c +c +e +c +c +c +c +c +c +c +c +c +c +c +c +c +c +i +c +c +c +b +b +b +c +c +a +"} +(30,1,1) = {" +a +a +a +c +b +b +c +d +f +c +i +c +c +c +b +c +c +c +c +c +j +c +c +c +c +c +c +c +b +b +b +c +c +c +a +"} +(31,1,1) = {" +a +a +a +b +b +b +b +c +c +c +c +c +c +b +b +b +c +c +c +r +c +c +c +c +c +c +b +b +b +b +c +c +c +b +b +"} +(32,1,1) = {" +a +a +a +b +b +b +c +c +c +c +c +c +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +c +b +b +b +"} +(33,1,1) = {" +a +a +a +b +b +c +c +c +c +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +b +b +b +a +"} +(34,1,1) = {" +a +a +a +b +b +b +b +b +b +b +b +b +b +b +c +c +c +c +c +b +b +b +b +b +a +a +a +a +a +a +a +b +b +b +a +"} +(35,1,1) = {" +a +a +a +a +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index 88beec629f..b3af867bb4 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -18,6 +18,7 @@ name = "Asteroid 1" description = "I-spy with my little eye, something beginning with R." + /datum/map_template/ruin/space/asteroid2 id = "asteroid2" suffix = "asteroid2.dmm" @@ -247,4 +248,10 @@ id = "miracle" suffix = "miracle.dmm" name = "Ordinary Space Tile" - description = "Absolutely nothing strange going on here please move along, plenty more space to see right this way!" \ No newline at end of file + description = "Absolutely nothing strange going on here please move along, plenty more space to see right this way!" + +/datum/map_template/ruin/space/gondoland + id = "gondolaasteroid" + suffix = "gondolaasteroid.dmm" + name = "Gondoland" + description = "Just an ordinary rock- wait, what's that thing?" diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 77e46235c8..4ad576fe34 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -32,6 +32,13 @@ GLOBAL_LIST_INIT(human_recipes, list( \ singular_name = "corgi hide piece" icon_state = "sheet-corgi" +/obj/item/stack/sheet/animalhide/gondola + name = "gondola hide" + desc = "The extremely valuable by-product of gondola hunting." + singular_name = "gondola hide piece" + icon_state = "sheet-gondola" + + GLOBAL_LIST_INIT(corgi_recipes, list ( \ new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3), \ )) diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm index a73529850d..a51d2e9c6e 100644 --- a/code/modules/cargo/exports/sheets.dm +++ b/code/modules/cargo/exports/sheets.dm @@ -57,6 +57,12 @@ unit_name = "lizard hide" export_types = list(/obj/item/stack/sheet/animalhide/lizard) +// Gondola hide. Mindbogglingly expensive. +/datum/export/stack/skin/gondola + cost = 10000 + unit_name = "gondola hide" + export_types = list(/obj/item/stack/sheet/animalhide/gondola) + // Alien hide. Extremely expensive. /datum/export/stack/skin/xeno cost = 3000 diff --git a/code/modules/mob/living/simple_animal/friendly/gondola.dm b/code/modules/mob/living/simple_animal/friendly/gondola.dm new file mode 100644 index 0000000000..e5dfd71e09 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/gondola.dm @@ -0,0 +1,29 @@ +//Gondolas + +/mob/living/simple_animal/pet/gondola + name = "gondola" + real_name = "gondola" + desc = "Gondola is the silent walker. Having no hands he embodies the Taoist principle of wu-wei (non-action) while his smiling facial expression shows his utter and complete acceptance of the world as it is. Its hide is extremely valuable." + response_help = "pets" + response_disarm = "bops" + response_harm = "kicks" + emote_see = list("watches.", "stares off into the distance.","contemplates.") + faction = list("gondola") + turns_per_move = 10 + icon = 'icons/mob/gondolas.dmi' + icon_state = "gondola" + icon_living = "gondola" + icon_dead = "gondola_dead" + butcher_results = list(/obj/item/stack/sheet/animalhide/gondola = 1) + //Gondolas aren't affected by cold. + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minbodytemp = 0 + maxbodytemp = 1500 + maxHealth = 200 + health = 200 + +/mob/living/simple_animal/pet/gondola/IsVocal() //Gondolas are the silent walker. + return FALSE + +/mob/living/simple_animal/pet/gondola/emote() + return \ No newline at end of file diff --git a/icons/mob/gondolas.dmi b/icons/mob/gondolas.dmi new file mode 100644 index 0000000000000000000000000000000000000000..15c83bad932810778ab807d118408864be8f8035 GIT binary patch literal 1020 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
    - - - - - -
    - - - - -
    - [sprite_text] -
    - [atomsnowflake.Join()] -
    -
    -
    - [formatted_type] - [marked] - [varedited_line] -
    -
    -
    - Refresh - - - -
    -
    -
    -
    - - E - Edit, tries to determine the variable type by itself.
    - C - Change, asks you for the var type first.
    - M - Mass modify: changes this variable for all objects of this type.
    -
    -
    - - - - - -
    -
    - Search: -
    -
    - -
    -
    -
      - [variable_html.Join()] -
    - - - -"} - - usr << browse(html, "window=variables[refid];size=475x650") - - -#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) -/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) - var/header - if(DA) - if (islist(DA)) - var/index = name - if (value) - name = DA[name] //name is really the index until this line - else - value = DA[name] - header = "
  • (E) (C) (-) " - else - header = "
  • (E) (C) (M) " - else - header = "
  • " - - var/item - if (isnull(value)) - item = "[VV_HTML_ENCODE(name)] = null" - - else if (istext(value)) - item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" - - else if (isicon(value)) - #ifdef VARSICON - var/icon/I = new/icon(value) - var/rnd = rand(1,10000) - var/rname = "tmp\ref[I][rnd].png" - usr << browse_rsc(I, rname) - item = "[VV_HTML_ENCODE(name)] = ([value]) " - #else - item = "[VV_HTML_ENCODE(name)] = /icon ([value])" - #endif - -/* else if (istype(value, /image)) - #ifdef VARSICON - var/rnd = rand(1, 10000) - var/image/I = value - - src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") - html += "[name] = " - #else - html += "[name] = /image ([value])" - #endif -*/ - else if (isfile(value)) - item = "[VV_HTML_ENCODE(name)] = '[value]'" - - //else if (istype(value, /client)) - // var/client/C = value - // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" - - else if (istype(value, /datum)) - var/datum/D = value - if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. - item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" - else - item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" - - else if (islist(value)) - var/list/L = value - var/list/items = list() - - if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) - for (var/i in 1 to L.len) - var/key = L[i] - var/val - if (IS_NORMAL_LIST(L) && !isnum(key)) - val = L[key] - if (!val) - val = key - key = i - - items += debug_variable(key, val, level + 1, sanitize = sanitize) - - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " - else - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" - - else - item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" - - return "[header][item]
  • " - -#undef VV_HTML_ENCODE - -/client/proc/view_var_Topic(href, href_list, hsrc) - if( (usr.client != src) || !src.holder ) - return - if(href_list["Vars"]) - debug_variables(locate(href_list["Vars"])) - - else if(href_list["datumrefresh"]) - var/datum/DAT = locate(href_list["datumrefresh"]) - if(!DAT) //can't be an istype() because /client etc aren't datums - return - src.debug_variables(DAT) - - else if(href_list["mob_player_panel"]) - if(!check_rights(0)) - return - -======= + var/atom/A = D + if(isliving(A)) + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
    << [dir2text(A.dir)] >>" + var/mob/living/M = A + atomsnowflake += {" +
    [M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"] +
    + BRUTE:[M.getBruteLoss()] + FIRE:[M.getFireLoss()] + TOXIN:[M.getToxLoss()] + OXY:[M.getOxyLoss()] + CLONE:[M.getCloneLoss()] + BRAIN:[M.getBrainLoss()] + STAMINA:[M.getStaminaLoss()] + + "} + else + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
    << [dir2text(A.dir)] >>" + else + atomsnowflake += "[D]" + + var/formatted_type = "[type]" + if(length(formatted_type) > 25) + var/middle_point = length(formatted_type) / 2 + var/splitpoint = findtext(formatted_type,"/",middle_point) + if(splitpoint) + formatted_type = "[copytext(formatted_type,1,splitpoint)]
    [copytext(formatted_type,splitpoint)]" + else + formatted_type = "Type too long" //No suitable splitpoint (/) found. + + var/marked + if(holder.marked_datum && holder.marked_datum == D) + marked = "
    Marked Object" + var/varedited_line = "" + if(!islist && D.var_edited) + varedited_line = "
    Var Edited" + + var/list/dropdownoptions = list() + if (islist) + dropdownoptions = list( + "---", + "Add Item" = "?_src_=vars;listadd=[refid]", + "Remove Nulls" = "?_src_=vars;listnulls=[refid]", + "Remove Dupes" = "?_src_=vars;listdupes=[refid]", + "Set len" = "?_src_=vars;listlen=[refid]", + "Shuffle" = "?_src_=vars;listshuffle=[refid]" + ) + else + dropdownoptions = D.vv_get_dropdown() + var/list/dropdownoptions_html = list() + + for (var/name in dropdownoptions) + var/link = dropdownoptions[name] + if (link) + dropdownoptions_html += "" + else + dropdownoptions_html += "" + + var/list/names = list() + if (!islist) + for (var/V in D.vars) + names += V + sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. + + var/list/variable_html = list() + if (islist) + var/list/L = D + for (var/i in 1 to L.len) + var/key = L[i] + var/value + if (IS_NORMAL_LIST(L) && !isnum(key)) + value = L[key] + variable_html += debug_variable(i, value, 0, D) + else + + names = sortList(names) + for (var/V in names) + if(D.can_vv_get(V)) + variable_html += D.vv_get_var(V) + + var/html = {" + + + [title] + + + + +
    + + + + + +
    + + + + +
    + [sprite_text] +
    + [atomsnowflake.Join()] +
    +
    +
    + [formatted_type] + [marked] + [varedited_line] +
    +
    +
    + Refresh +
    + +
    +
    +
    +
    +
    + + E - Edit, tries to determine the variable type by itself.
    + C - Change, asks you for the var type first.
    + M - Mass modify: changes this variable for all objects of this type.
    +
    +
    + + + + + +
    +
    + Search: +
    +
    + +
    +
    +
      + [variable_html.Join()] +
    + + + +"} + + usr << browse(html, "window=variables[refid];size=475x650") + + +#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) +/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) + var/header + if(DA) + if (islist(DA)) + var/index = name + if (value) + name = DA[name] //name is really the index until this line + else + value = DA[name] + header = "
  • (E) (C) (-) " + else + header = "
  • (E) (C) (M) " + else + header = "
  • " + + var/item + if (isnull(value)) + item = "[VV_HTML_ENCODE(name)] = null" + + else if (istext(value)) + item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" + + else if (isicon(value)) + #ifdef VARSICON + var/icon/I = new/icon(value) + var/rnd = rand(1,10000) + var/rname = "tmp\ref[I][rnd].png" + usr << browse_rsc(I, rname) + item = "[VV_HTML_ENCODE(name)] = ([value]) " + #else + item = "[VV_HTML_ENCODE(name)] = /icon ([value])" + #endif + +/* else if (istype(value, /image)) + #ifdef VARSICON + var/rnd = rand(1, 10000) + var/image/I = value + + src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") + html += "[name] = " + #else + html += "[name] = /image ([value])" + #endif +*/ + else if (isfile(value)) + item = "[VV_HTML_ENCODE(name)] = '[value]'" + + //else if (istype(value, /client)) + // var/client/C = value + // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" + + else if (istype(value, /datum)) + var/datum/D = value + if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" + else + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" + + else if (islist(value)) + var/list/L = value + var/list/items = list() + + if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) + for (var/i in 1 to L.len) + var/key = L[i] + var/val + if (IS_NORMAL_LIST(L) && !isnum(key)) + val = L[key] + if (!val) + val = key + key = i + + items += debug_variable(key, val, level + 1, sanitize = sanitize) + + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " + else + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + + else + item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" + + return "[header][item]
  • " + +#undef VV_HTML_ENCODE + +/client/proc/view_var_Topic(href, href_list, hsrc) + if( (usr.client != src) || !src.holder ) + return + if(href_list["Vars"]) + debug_variables(locate(href_list["Vars"])) + + else if(href_list["datumrefresh"]) + var/datum/DAT = locate(href_list["datumrefresh"]) + if(!DAT) //can't be an istype() because /client etc aren't datums + return + src.debug_variables(DAT) + + else if(href_list["mob_player_panel"]) + if(!check_rights(0)) + return + /datum/proc/vv_get_dropdown() . = list() . += "---" @@ -951,81 +949,78 @@ if(!check_rights(0)) return ->>>>>>> 6656ce6... Gives admins the ability to show a read only vv window to a player (#30463) var/mob/M = locate(href_list["mob_player_panel"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.holder.show_player_panel(M) - href_list["datumrefresh"] = href_list["mob_player_panel"] - - else if(href_list["godmode"]) - if(!check_rights(R_ADMIN)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.holder.show_player_panel(M) + href_list["datumrefresh"] = href_list["mob_player_panel"] + + else if(href_list["godmode"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["godmode"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.cmd_admin_godmode(M) - href_list["datumrefresh"] = href_list["godmode"] - - else if(href_list["mark_object"]) - if(!check_rights(0)) - return - - var/datum/D = locate(href_list["mark_object"]) - if(!istype(D)) - to_chat(usr, "This can only be done to instances of type /datum") - return - - src.holder.marked_datum = D - href_list["datumrefresh"] = href_list["mark_object"] - - else if(href_list["proc_call"]) - if(!check_rights(0)) - return - - var/T = locate(href_list["proc_call"]) - - if(T) - callproc_datum(T) - - else if(href_list["delete"]) - if(!check_rights(R_DEBUG, 0)) - return - - var/datum/D = locate(href_list["delete"]) - if(!D) - to_chat(usr, "Unable to locate item!") - admin_delete(D) - href_list["datumrefresh"] = href_list["delete"] - - else if(href_list["regenerateicons"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.cmd_admin_godmode(M) + href_list["datumrefresh"] = href_list["godmode"] + + else if(href_list["mark_object"]) + if(!check_rights(0)) + return + + var/datum/D = locate(href_list["mark_object"]) + if(!istype(D)) + to_chat(usr, "This can only be done to instances of type /datum") + return + + src.holder.marked_datum = D + href_list["datumrefresh"] = href_list["mark_object"] + + else if(href_list["proc_call"]) + if(!check_rights(0)) + return + + var/T = locate(href_list["proc_call"]) + + if(T) + callproc_datum(T) + + else if(href_list["delete"]) + if(!check_rights(R_DEBUG, 0)) + return + + var/datum/D = locate(href_list["delete"]) + if(!D) + to_chat(usr, "Unable to locate item!") + admin_delete(D) + href_list["datumrefresh"] = href_list["delete"] + + else if(href_list["regenerateicons"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["regenerateicons"]) in GLOB.mob_list -<<<<<<< HEAD - if(!ismob(M)) - to_chat(usr, "This can only be done to instances of type /mob") - return - M.regenerate_icons() - -//Needs +VAREDIT past this point - - else if(check_rights(R_VAREDIT)) - - - //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). - - if(href_list["rename"]) - if(!check_rights(0)) - return - -======= + if(!ismob(M)) + to_chat(usr, "This can only be done to instances of type /mob") + return + M.regenerate_icons() + +//Needs +VAREDIT past this point + + else if(check_rights(R_VAREDIT)) + + + //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). + + if(href_list["rename"]) + if(!check_rights(0)) + return + if(!ismob(M)) to_chat(usr, "This can only be done to instances of type /mob") return @@ -1062,379 +1057,378 @@ if(!check_rights(0)) return ->>>>>>> 6656ce6... Gives admins the ability to show a read only vv window to a player (#30463) var/mob/M = locate(href_list["rename"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN) - if( !new_name || !M ) - return - - message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].") - M.fully_replace_character_name(M.real_name,new_name) - href_list["datumrefresh"] = href_list["rename"] - - else if(href_list["varnameedit"] && href_list["datumedit"]) - if(!check_rights(0)) - return - - var/D = locate(href_list["datumedit"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN) + if( !new_name || !M ) + return + + message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].") + M.fully_replace_character_name(M.real_name,new_name) + href_list["datumrefresh"] = href_list["rename"] + + else if(href_list["varnameedit"] && href_list["datumedit"]) + if(!check_rights(0)) + return + + var/D = locate(href_list["datumedit"]) if(!istype(D, /datum)) - to_chat(usr, "This can only be used on datums") - return - - modify_variables(D, href_list["varnameedit"], 1) - - else if(href_list["varnamechange"] && href_list["datumchange"]) - if(!check_rights(0)) - return - - var/D = locate(href_list["datumchange"]) + to_chat(usr, "This can only be used on datums") + return + + modify_variables(D, href_list["varnameedit"], 1) + + else if(href_list["varnamechange"] && href_list["datumchange"]) + if(!check_rights(0)) + return + + var/D = locate(href_list["datumchange"]) if(!istype(D, /datum)) - to_chat(usr, "This can only be used on datums") - return - - modify_variables(D, href_list["varnamechange"], 0) - - else if(href_list["varnamemass"] && href_list["datummass"]) - if(!check_rights(0)) - return - - var/datum/D = locate(href_list["datummass"]) - if(!istype(D)) - to_chat(usr, "This can only be used on instances of type /datum") - return - - cmd_mass_modify_object_variables(D, href_list["varnamemass"]) - - else if(href_list["listedit"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listedit"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list(L, null, "list", "contents", index, autodetect_class = TRUE) - - else if(href_list["listchange"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listchange"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list(L, null, "list", "contents", index, autodetect_class = FALSE) - - else if(href_list["listremove"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listremove"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - var/variable = L[index] - var/prompt = alert("Do you want to remove item number [index] from list?", "Confirm", "Yes", "No") - if (prompt != "Yes") - return - L.Cut(index, index+1) - log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]") - log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]") - message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]") - - else if(href_list["listadd"]) - var/list/L = locate(href_list["listadd"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list_add(L, null, "list", "contents") - - else if(href_list["listdupes"]) - var/list/L = locate(href_list["listdupes"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - uniqueList_inplace(L) - log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES") - log_admin("[key_name(src)] modified list's contents: CLEAR DUPES") - message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES") - - else if(href_list["listnulls"]) - var/list/L = locate(href_list["listnulls"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - listclearnulls(L) - log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS") - log_admin("[key_name(src)] modified list's contents: CLEAR NULLS") - message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS") - - else if(href_list["listlen"]) - var/list/L = locate(href_list["listlen"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - var/value = vv_get_value(VV_NUM) - if (value["class"] != VV_NUM) - return - - L.len = value["value"] - log_world("### ListVarEdit by [src]: /list len: [L.len]") - log_admin("[key_name(src)] modified list's len: [L.len]") - message_admins("[key_name_admin(src)] modified list's len: [L.len]") - - else if(href_list["listshuffle"]) - var/list/L = locate(href_list["listshuffle"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - shuffle_inplace(L) - log_world("### ListVarEdit by [src]: /list contents: SHUFFLE") - log_admin("[key_name(src)] modified list's contents: SHUFFLE") - message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE") - - else if(href_list["give_spell"]) - if(!check_rights(0)) - return - + to_chat(usr, "This can only be used on datums") + return + + modify_variables(D, href_list["varnamechange"], 0) + + else if(href_list["varnamemass"] && href_list["datummass"]) + if(!check_rights(0)) + return + + var/datum/D = locate(href_list["datummass"]) + if(!istype(D)) + to_chat(usr, "This can only be used on instances of type /datum") + return + + cmd_mass_modify_object_variables(D, href_list["varnamemass"]) + + else if(href_list["listedit"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if (!index) + return + + var/list/L = locate(href_list["listedit"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + mod_list(L, null, "list", "contents", index, autodetect_class = TRUE) + + else if(href_list["listchange"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if (!index) + return + + var/list/L = locate(href_list["listchange"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + mod_list(L, null, "list", "contents", index, autodetect_class = FALSE) + + else if(href_list["listremove"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if (!index) + return + + var/list/L = locate(href_list["listremove"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + var/variable = L[index] + var/prompt = alert("Do you want to remove item number [index] from list?", "Confirm", "Yes", "No") + if (prompt != "Yes") + return + L.Cut(index, index+1) + log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]") + log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]") + message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]") + + else if(href_list["listadd"]) + var/list/L = locate(href_list["listadd"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + mod_list_add(L, null, "list", "contents") + + else if(href_list["listdupes"]) + var/list/L = locate(href_list["listdupes"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + uniqueList_inplace(L) + log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES") + log_admin("[key_name(src)] modified list's contents: CLEAR DUPES") + message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES") + + else if(href_list["listnulls"]) + var/list/L = locate(href_list["listnulls"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + listclearnulls(L) + log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS") + log_admin("[key_name(src)] modified list's contents: CLEAR NULLS") + message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS") + + else if(href_list["listlen"]) + var/list/L = locate(href_list["listlen"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + var/value = vv_get_value(VV_NUM) + if (value["class"] != VV_NUM) + return + + L.len = value["value"] + log_world("### ListVarEdit by [src]: /list len: [L.len]") + log_admin("[key_name(src)] modified list's len: [L.len]") + message_admins("[key_name_admin(src)] modified list's len: [L.len]") + + else if(href_list["listshuffle"]) + var/list/L = locate(href_list["listshuffle"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + shuffle_inplace(L) + log_world("### ListVarEdit by [src]: /list contents: SHUFFLE") + log_admin("[key_name(src)] modified list's contents: SHUFFLE") + message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE") + + else if(href_list["give_spell"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["give_spell"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_spell(M) - href_list["datumrefresh"] = href_list["give_spell"] - - else if(href_list["remove_spell"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_spell(M) + href_list["datumrefresh"] = href_list["give_spell"] + + else if(href_list["remove_spell"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["remove_spell"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - remove_spell(M) - href_list["datumrefresh"] = href_list["remove_spell"] - - else if(href_list["give_disease"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + remove_spell(M) + href_list["datumrefresh"] = href_list["remove_spell"] + + else if(href_list["give_disease"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["give_disease"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_disease(M) - href_list["datumrefresh"] = href_list["give_spell"] - - else if(href_list["gib"]) - if(!check_rights(R_FUN)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_disease(M) + href_list["datumrefresh"] = href_list["give_spell"] + + else if(href_list["gib"]) + if(!check_rights(R_FUN)) + return + var/mob/M = locate(href_list["gib"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.cmd_admin_gib(M) - - else if(href_list["build_mode"]) - if(!check_rights(R_BUILDMODE)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.cmd_admin_gib(M) + + else if(href_list["build_mode"]) + if(!check_rights(R_BUILDMODE)) + return + var/mob/M = locate(href_list["build_mode"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - togglebuildmode(M) - href_list["datumrefresh"] = href_list["build_mode"] - - else if(href_list["drop_everything"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + togglebuildmode(M) + href_list["datumrefresh"] = href_list["build_mode"] + + else if(href_list["drop_everything"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["drop_everything"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - if(usr.client) - usr.client.cmd_admin_drop_everything(M) - - else if(href_list["direct_control"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(usr.client) + usr.client.cmd_admin_drop_everything(M) + + else if(href_list["direct_control"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["direct_control"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - if(usr.client) - usr.client.cmd_assume_direct_control(M) - - else if(href_list["offer_control"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(usr.client) + usr.client.cmd_assume_direct_control(M) + + else if(href_list["offer_control"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["offer_control"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - offer_control(M) - - else if(href_list["delall"]) - if(!check_rights(R_DEBUG|R_SERVER)) - return - - var/obj/O = locate(href_list["delall"]) - if(!isobj(O)) - to_chat(usr, "This can only be used on instances of type /obj") - return - - var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") - if(action_type == "Cancel" || !action_type) - return - - if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") - return - - if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") - return - - var/O_type = O.type - switch(action_type) - if("Strict type") - var/i = 0 - for(var/obj/Obj in world) - if(Obj.type == O_type) - i++ - qdel(Obj) - CHECK_TICK - if(!i) - to_chat(usr, "No objects of this type exist") - return - log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") - message_admins("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") - if("Type and subtypes") - var/i = 0 - for(var/obj/Obj in world) - if(istype(Obj,O_type)) - i++ - qdel(Obj) - CHECK_TICK - if(!i) - to_chat(usr, "No objects of this type exist") - return - log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") - message_admins("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") - - else if(href_list["addreagent"]) - if(!check_rights(0)) - return - - var/atom/A = locate(href_list["addreagent"]) - - if(!A.reagents) - var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num - if(amount) - A.create_reagents(amount) - - if(A.reagents) - var/chosen_id - var/list/reagent_options = sortList(GLOB.chemical_reagents_list) - switch(alert(usr, "Choose a method.", "Add Reagents", "Enter ID", "Choose ID")) - if("Enter ID") - var/valid_id - while(!valid_id) - chosen_id = stripped_input(usr, "Enter the ID of the reagent you want to add.") - if(!chosen_id) //Get me out of here! - break - for(var/ID in reagent_options) - if(ID == chosen_id) - valid_id = 1 - if(!valid_id) - to_chat(usr, "A reagent with that ID doesn't exist!") - if("Choose ID") - chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in reagent_options - if(chosen_id) - var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num - if(amount) - A.reagents.add_reagent(chosen_id, amount) - log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") - message_admins("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") - - href_list["datumrefresh"] = href_list["addreagent"] - - else if(href_list["explode"]) - if(!check_rights(R_FUN)) - return - - var/atom/A = locate(href_list["explode"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) - to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") - return - - src.cmd_admin_explosion(A) - href_list["datumrefresh"] = href_list["explode"] - - else if(href_list["emp"]) - if(!check_rights(R_FUN)) - return - - var/atom/A = locate(href_list["emp"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) - to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") - return - - src.cmd_admin_emp(A) - href_list["datumrefresh"] = href_list["emp"] - - else if(href_list["rotatedatum"]) - if(!check_rights(0)) - return - - var/atom/A = locate(href_list["rotatedatum"]) - if(!istype(A)) - to_chat(usr, "This can only be done to instances of type /atom") - return - - switch(href_list["rotatedir"]) - if("right") - A.setDir(turn(A.dir, -45)) - if("left") - A.setDir(turn(A.dir, 45)) - href_list["datumrefresh"] = href_list["rotatedatum"] - - else if(href_list["editorgans"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + offer_control(M) + + else if(href_list["delall"]) + if(!check_rights(R_DEBUG|R_SERVER)) + return + + var/obj/O = locate(href_list["delall"]) + if(!isobj(O)) + to_chat(usr, "This can only be used on instances of type /obj") + return + + var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") + if(action_type == "Cancel" || !action_type) + return + + if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") + return + + if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") + return + + var/O_type = O.type + switch(action_type) + if("Strict type") + var/i = 0 + for(var/obj/Obj in world) + if(Obj.type == O_type) + i++ + qdel(Obj) + CHECK_TICK + if(!i) + to_chat(usr, "No objects of this type exist") + return + log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") + message_admins("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") + if("Type and subtypes") + var/i = 0 + for(var/obj/Obj in world) + if(istype(Obj,O_type)) + i++ + qdel(Obj) + CHECK_TICK + if(!i) + to_chat(usr, "No objects of this type exist") + return + log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") + message_admins("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") + + else if(href_list["addreagent"]) + if(!check_rights(0)) + return + + var/atom/A = locate(href_list["addreagent"]) + + if(!A.reagents) + var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num + if(amount) + A.create_reagents(amount) + + if(A.reagents) + var/chosen_id + var/list/reagent_options = sortList(GLOB.chemical_reagents_list) + switch(alert(usr, "Choose a method.", "Add Reagents", "Enter ID", "Choose ID")) + if("Enter ID") + var/valid_id + while(!valid_id) + chosen_id = stripped_input(usr, "Enter the ID of the reagent you want to add.") + if(!chosen_id) //Get me out of here! + break + for(var/ID in reagent_options) + if(ID == chosen_id) + valid_id = 1 + if(!valid_id) + to_chat(usr, "A reagent with that ID doesn't exist!") + if("Choose ID") + chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in reagent_options + if(chosen_id) + var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num + if(amount) + A.reagents.add_reagent(chosen_id, amount) + log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") + message_admins("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") + + href_list["datumrefresh"] = href_list["addreagent"] + + else if(href_list["explode"]) + if(!check_rights(R_FUN)) + return + + var/atom/A = locate(href_list["explode"]) + if(!isobj(A) && !ismob(A) && !isturf(A)) + to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") + return + + src.cmd_admin_explosion(A) + href_list["datumrefresh"] = href_list["explode"] + + else if(href_list["emp"]) + if(!check_rights(R_FUN)) + return + + var/atom/A = locate(href_list["emp"]) + if(!isobj(A) && !ismob(A) && !isturf(A)) + to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") + return + + src.cmd_admin_emp(A) + href_list["datumrefresh"] = href_list["emp"] + + else if(href_list["rotatedatum"]) + if(!check_rights(0)) + return + + var/atom/A = locate(href_list["rotatedatum"]) + if(!istype(A)) + to_chat(usr, "This can only be done to instances of type /atom") + return + + switch(href_list["rotatedir"]) + if("right") + A.setDir(turn(A.dir, -45)) + if("left") + A.setDir(turn(A.dir, 45)) + href_list["datumrefresh"] = href_list["rotatedatum"] + + else if(href_list["editorgans"]) + if(!check_rights(0)) + return + var/mob/living/carbon/C = locate(href_list["editorgans"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - manipulate_organs(C) - href_list["datumrefresh"] = href_list["editorgans"] - + if(!istype(C)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + manipulate_organs(C) + href_list["datumrefresh"] = href_list["editorgans"] + else if(href_list["hallucinate"]) if(!check_rights(0)) return @@ -1455,238 +1449,238 @@ if(result) new result(C, TRUE) - else if(href_list["makehuman"]) - if(!check_rights(R_SPAWN)) - return - + else if(href_list["makehuman"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list - if(!istype(Mo)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!Mo) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("humanone"=href_list["makehuman"])) - - else if(href_list["makemonkey"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(Mo)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!Mo) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("humanone"=href_list["makehuman"])) + + else if(href_list["makemonkey"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makemonkey"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) - - else if(href_list["makerobot"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) + + else if(href_list["makerobot"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makerobot"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makerobot"=href_list["makerobot"])) - - else if(href_list["makealien"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makerobot"=href_list["makerobot"])) + + else if(href_list["makealien"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makealien"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makealien"=href_list["makealien"])) - - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makealien"=href_list["makealien"])) + + else if(href_list["makeslime"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makeslime"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makeslime"=href_list["makeslime"])) - - else if(href_list["makeai"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makeslime"=href_list["makeslime"])) + + else if(href_list["makeai"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/H = locate(href_list["makeai"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makeai"=href_list["makeai"])) - - else if(href_list["setspecies"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makeai"=href_list["makeai"])) + + else if(href_list["setspecies"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["setspecies"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list - - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/newtype = GLOB.species_list[result] - admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [H] to [result]") - H.set_species(newtype) - - else if(href_list["editbodypart"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(result) + var/newtype = GLOB.species_list[result] + admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [H] to [result]") + H.set_species(newtype) + + else if(href_list["editbodypart"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/C = locate(href_list["editbodypart"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") - if(!edit_action) - return - var/list/limb_list = list("head", "l_arm", "r_arm", "l_leg", "r_leg") - if(edit_action == "augment") - limb_list += "chest" - var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list - - if(!C) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/obj/item/bodypart/BP = C.get_bodypart(result) - switch(edit_action) - if("remove") - if(BP) - BP.drop_limb() - else - to_chat(usr, "[C] doesn't have such bodypart.") - if("add") - if(BP) - to_chat(usr, "[C] already has such bodypart.") - else - if(!C.regenerate_limb(result)) - to_chat(usr, "[C] cannot have such bodypart.") - if("augment") - if(ishuman(C)) - if(BP) - BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) - else - to_chat(usr, "[C] doesn't have such bodypart.") - else - to_chat(usr, "Only humans can be augmented.") - admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [C]") - - - else if(href_list["purrbation"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(C)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") + if(!edit_action) + return + var/list/limb_list = list("head", "l_arm", "r_arm", "l_leg", "r_leg") + if(edit_action == "augment") + limb_list += "chest" + var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list + + if(!C) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(result) + var/obj/item/bodypart/BP = C.get_bodypart(result) + switch(edit_action) + if("remove") + if(BP) + BP.drop_limb() + else + to_chat(usr, "[C] doesn't have such bodypart.") + if("add") + if(BP) + to_chat(usr, "[C] already has such bodypart.") + else + if(!C.regenerate_limb(result)) + to_chat(usr, "[C] cannot have such bodypart.") + if("augment") + if(ishuman(C)) + if(BP) + BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) + else + to_chat(usr, "[C] doesn't have such bodypart.") + else + to_chat(usr, "Only humans can be augmented.") + admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [C]") + + + else if(href_list["purrbation"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["purrbation"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - if(!ishumanbasic(H)) - to_chat(usr, "This can only be done to the basic human species at the moment.") - return - - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - - var/success = purrbation_toggle(H) - if(success) - to_chat(usr, "Put [H] on purrbation.") - log_admin("[key_name(usr)] has put [key_name(H)] on purrbation.") - var/msg = "[key_name_admin(usr)] has put [key_name(H)] on purrbation." - message_admins(msg) - admin_ticket_log(H, msg) - - else - to_chat(usr, "Removed [H] from purrbation.") - log_admin("[key_name(usr)] has removed [key_name(H)] from purrbation.") - var/msg = "[key_name_admin(usr)] has removed [key_name(H)] from purrbation." - message_admins(msg) - admin_ticket_log(H, msg) - - else if(href_list["adjustDamage"] && href_list["mobToDamage"]) - if(!check_rights(0)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + if(!ishumanbasic(H)) + to_chat(usr, "This can only be done to the basic human species at the moment.") + return + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + var/success = purrbation_toggle(H) + if(success) + to_chat(usr, "Put [H] on purrbation.") + log_admin("[key_name(usr)] has put [key_name(H)] on purrbation.") + var/msg = "[key_name_admin(usr)] has put [key_name(H)] on purrbation." + message_admins(msg) + admin_ticket_log(H, msg) + + else + to_chat(usr, "Removed [H] from purrbation.") + log_admin("[key_name(usr)] has removed [key_name(H)] from purrbation.") + var/msg = "[key_name_admin(usr)] has removed [key_name(H)] from purrbation." + message_admins(msg) + admin_ticket_log(H, msg) + + else if(href_list["adjustDamage"] && href_list["mobToDamage"]) + if(!check_rights(0)) + return + var/mob/living/L = locate(href_list["mobToDamage"]) in GLOB.mob_list - if(!istype(L)) - return - - var/Text = href_list["adjustDamage"] - - var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num - - if(!L) - to_chat(usr, "Mob doesn't exist anymore") - return - - switch(Text) - if("brute") - L.adjustBruteLoss(amount) - if("fire") - L.adjustFireLoss(amount) - if("toxin") - L.adjustToxLoss(amount) - if("oxygen") - L.adjustOxyLoss(amount) - if("brain") - L.adjustBrainLoss(amount) - if("clone") - L.adjustCloneLoss(amount) - if("stamina") - L.adjustStaminaLoss(amount) - else - to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") - return - - if(amount != 0) - log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ") - var/msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [L] " - message_admins(msg) - admin_ticket_log(L, msg) - href_list["datumrefresh"] = href_list["mobToDamage"] - + if(!istype(L)) + return + + var/Text = href_list["adjustDamage"] + + var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num + + if(!L) + to_chat(usr, "Mob doesn't exist anymore") + return + + switch(Text) + if("brute") + L.adjustBruteLoss(amount) + if("fire") + L.adjustFireLoss(amount) + if("toxin") + L.adjustToxLoss(amount) + if("oxygen") + L.adjustOxyLoss(amount) + if("brain") + L.adjustBrainLoss(amount) + if("clone") + L.adjustCloneLoss(amount) + if("stamina") + L.adjustStaminaLoss(amount) + else + to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") + return + + if(amount != 0) + log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ") + var/msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [L] " + message_admins(msg) + admin_ticket_log(L, msg) + href_list["datumrefresh"] = href_list["mobToDamage"] + From 2f10e78ba7f8be726c18ecfecdd4738906bda2c8 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:56:28 -0500 Subject: [PATCH 053/102] Update on_move.dm --- code/modules/shuttle/on_move.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index e80b690737..f2c84a5aae 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -14,12 +14,9 @@ All ShuttleMove procs go here // Called from the new turf before anything has been moved // Only gets called if fromShuttleMove returns true first // returns the new move_mode (based on the old) -<<<<<<< HEAD /turf/proc/toShuttleMove(turf/oldT, shuttle_dir, move_mode) -======= /turf/proc/toShuttleMove(turf/oldT, move_mode, obj/docking_port/mobile/shuttle) var/shuttle_dir = shuttle.dir ->>>>>>> 9ac60a8... Typo for(var/i in contents) var/atom/movable/thing = i if(ismob(thing)) @@ -388,4 +385,4 @@ All ShuttleMove procs go here /obj/effect/abstract/proximity_checker/onShuttleMove(turf/newT, turf/oldT, rotation, list/movement_force, move_dir, old_dock) //timer so it only happens once - addtimer(CALLBACK(monitor, /datum/proximity_monitor/proc/SetRange, monitor.current_range, TRUE), 0, TIMER_UNIQUE) \ No newline at end of file + addtimer(CALLBACK(monitor, /datum/proximity_monitor/proc/SetRange, monitor.current_range, TRUE), 0, TIMER_UNIQUE) From ddd0d9a1fc71881596be7e274952a07893c2add8 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 11 Sep 2017 13:56:54 -0500 Subject: [PATCH 054/102] Automatic changelog generation for PR #2706 [ci skip] --- html/changelogs/AutoChangeLog-pr-2706.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2706.yml diff --git a/html/changelogs/AutoChangeLog-pr-2706.yml b/html/changelogs/AutoChangeLog-pr-2706.yml new file mode 100644 index 0000000000..4db678dd9b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2706.yml @@ -0,0 +1,4 @@ +author: "Xhuis" +delete-after: True +changes: + - rscadd: "You can now use metal rods and departmental jumpsuits to craft departments for each banner." From 14aefe2e64e20f57ced285e782aaf8cec2c992f8 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 14:01:42 -0500 Subject: [PATCH 055/102] commit --- .../kitchen_machinery/smartfridge.dm | 131 +++++++++--------- tgui/assets/tgui.css | 2 +- tgui/assets/tgui.js | 32 ++--- tgui/src/interfaces/smartvend.ract | 48 +++++++ 4 files changed, 131 insertions(+), 82 deletions(-) create mode 100644 tgui/src/interfaces/smartvend.ract diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index e996429939..53b899f696 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -142,69 +142,55 @@ user.set_machine(src) interact(user) -/******************* -* SmartFridge Menu -********************/ -/obj/machinery/smartfridge/interact(mob/user) - if(stat) - return FALSE - var/dat = "Select an item:
    " +/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "smartvend", name, 440, 550, master_ui, state) + ui.open() - if (contents.len == 0) - dat += "No product loaded!" - else - var/listofitems = list() - for (var/atom/movable/O in contents) - if (listofitems[O.name]) - listofitems[O.name]++ - else - listofitems[O.name] = 1 - sortList(listofitems) +/obj/machinery/smartfridge/ui_data(mob/user) + . = list() - for (var/O in listofitems) - if(listofitems[O] <= 0) - continue - var/N = listofitems[O] - var/itemName = url_encode(O) - dat += "[capitalize(O)]:" - dat += " [N] " - dat += "Vend " - if(N > 5) - dat += "(x5)" - if(N > 10) - dat += "(x10)" - if(N > 25) - dat += "(x25)" - if(N > 1) - dat += "(All)" + var/listofitems = list() + for (var/I in src) + var/atom/movable/O = I + if (listofitems[O.name]) + listofitems[O.name]["amount"]++ + else + listofitems[O.name] = list("name" = O.name, "type" = O.type, "amount" = 1) + sortList(listofitems) - dat += "
    " + .["contents"] = listofitems + .["name"] = name + .["isdryer"] = FALSE - dat += "
    " - user << browse("[src] supplies[dat]", "window=smartfridge") - onclose(user, "smartfridge") - return dat -/obj/machinery/smartfridge/Topic(var/href, var/list/href_list) - if(..()) +/obj/machinery/smartfridge/ui_act(action, params) + . = ..() + if(.) return - usr.set_machine(src) + switch(action) + if("Release") + var/desired = 0 - var/N = href_list["vend"] - var/amount = text2num(href_list["amount"]) + if (params["amount"]) + desired = text2num(params["amount"]) + else + desired = input("How many items?", "How many items would you like to take out?", 1) as null|num - var/i = amount - for(var/obj/O in contents) - if(i <= 0) - break - if(O.name == N) - O.loc = src.loc - i-- + if(QDELETED(src) || QDELETED(usr) || !usr.Adjacent(src)) // Sanity checkin' in case stupid stuff happens while we wait for input() + return FALSE - - updateUsrDialog() + for(var/obj/item/O in src) + if(desired <= 0) + break + if(O.name == params["name"]) + O.forceMove(drop_location()) + desired-- + return TRUE + return FALSE // ---------------------------- @@ -240,20 +226,35 @@ /obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(obj/item/crowbar/C, ignore_panel = 1) ..() -/obj/machinery/smartfridge/drying_rack/interact(mob/user) - var/dat = ..() - if(dat) - dat += "
    " - dat += "Toggle Drying " - user << browse("[src] supplies[dat]", "window=smartfridge") - onclose(user, "smartfridge") +/obj/machinery/smartfridge/drying_rack/ui_data(mob/user) + . = list() -/obj/machinery/smartfridge/drying_rack/Topic(href, list/href_list) - ..() - if(href_list["dry"]) - toggle_drying(FALSE) - updateUsrDialog() - update_icon() + var/listofitems = list() + for (var/I in src) + var/atom/movable/O = I + + if (listofitems[O.name]) + listofitems[O.name]["amount"]++ + else + listofitems[O.name] = list("name" = O.name, "type" = O.type, "amount" = 1) + sortList(listofitems) + + .["contents"] = listofitems + .["name"] = name + .["isdryer"] = TRUE + .["verb"] = "Take" + .["drying"] = drying + + +/obj/machinery/smartfridge/drying_rack/ui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("Dry") + toggle_drying(FALSE) + return TRUE + return FALSE /obj/machinery/smartfridge/drying_rack/power_change() if(powered() && anchored) diff --git a/tgui/assets/tgui.css b/tgui/assets/tgui.css index f19852971d..ffe61666b9 100644 --- a/tgui/assets/tgui.css +++ b/tgui/assets/tgui.css @@ -1 +1 @@ -@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2a2a2a',endColorstr='#ff202020',GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffb18b25',endColorstr='#ff5f380e',GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input::-webkit-input-placeholder{color:#999}body.clockwork input::-moz-placeholder{color:#999}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #5f380e;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(even){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgNDI1IDIwMCIgb3BhY2l0eT0iLjMzIj4NCiAgPHBhdGggZD0ibSAxNzguMDAzOTksMC4wMzg2OSAtNzEuMjAzOTMsMCBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgLTYuNzYxMzQsNi4wMjU1NSBsIDAsMTg3Ljg3MTQ3IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM0LDYuMDI1NTQgbCA1My4xMDcyLDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xMDEuNTQ0MDE4IDcyLjIxNjI4LDEwNC42OTkzOTggYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDUuNzYwMTUsMi44NzAxNiBsIDczLjU1NDg3LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xODcuODcxNDcgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTM1LC02LjAyNTU1IGwgLTU0LjcxNjQ0LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTMzLDYuMDI1NTUgbCAwLDEwMi42MTkzNSBMIDE4My43NjQxMywyLjkwODg2IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNS43NjAxNCwtMi44NzAxNyB6IiAvPg0KICA8cGF0aCBkPSJNIDQuODQ0NjMzMywyMi4xMDg3NSBBIDEzLjQxMjAzOSwxMi41MDE4NDIgMCAwIDEgMTMuNDc3NTg4LDAuMDM5MjQgbCA2Ni4xMTgzMTUsMCBhIDUuMzY0ODE1OCw1LjAwMDczNyAwIDAgMSA1LjM2NDgyMyw1LjAwMDczIGwgMCw3OS44NzkzMSB6IiAvPg0KICA8cGF0aCBkPSJtIDQyMC4xNTUzNSwxNzcuODkxMTkgYSAxMy40MTIwMzgsMTIuNTAxODQyIDAgMCAxIC04LjYzMjk1LDIyLjA2OTUxIGwgLTY2LjExODMyLDAgYSA1LjM2NDgxNTIsNS4wMDA3MzcgMCAwIDEgLTUuMzY0ODIsLTUuMDAwNzQgbCAwLC03OS44NzkzMSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2a2a2a',endColorstr='#ff202020',GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input::-webkit-input-placeholder{color:#999}body.nanotrasen input::-moz-placeholder{color:#999}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(even){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgMjAwIDI4OS43NDIiIG9wYWNpdHk9Ii4zMyI+DQogIDxwYXRoIGQ9Im0gOTMuNTM3Njc3LDAgYyAtMTguMTEzMTI1LDAgLTM0LjIyMDEzMywzLjExMTY0IC00OC4zMjM0ODQsOS4zMzQzNyAtMTMuOTY1MDkyLDYuMjIxNjcgLTI0LjYxMjQ0MiwxNS4wNzExNCAtMzEuOTQwNjUxLDI2LjU0NzEgLTcuMTg5OTM5OCwxMS4zMzc4OSAtMTAuMzAxMjI2NiwyNC43NDkxMSAtMTAuMzAxMjI2Niw0MC4yMzQ3OCAwLDEwLjY0NjYyIDIuNzI1MDAyNiwyMC40NjQ2NSA4LjE3NTExMTYsMjkuNDUyNTggNS42MTUyNzcsOC45ODY4NiAxNC4wMzgyNzcsMTcuMzUyMDQgMjUuMjY4ODIxLDI1LjA5NDM2IDExLjIzMDU0NCw3LjYwNTMxIDI2LjUwNzQyMSwxNS40MTgzNSA0NS44MzA1MTQsMjMuNDM3ODIgMTkuOTgzNzQ4LDguMjk1NTcgMzQuODQ4ODQ4LDE1LjU1NDcxIDQ0LjU5Mjk5OCwyMS43NzYzOCA5Ljc0NDE0LDYuMjIyNzMgMTYuNzYxNywxMi44NTg1IDIxLjA1NTcyLDE5LjkwOTUxIDQuMjk0MDQsNy4wNTIwOCA2LjQ0MTkzLDE1Ljc2NDA4IDYuNDQxOTMsMjYuMTM0NTkgMCwxNi4xNzcwMiAtNS4yMDE5NiwyOC40ODIyMiAtMTUuNjA2NzMsMzYuOTE2ODIgLTEwLjIzOTYsOC40MzQ3IC0yNS4wMjIwMywxMi42NTIzIC00NC4zNDUxNjksMTIuNjUyMyAtMTQuMDM4MTcxLDAgLTI1LjUxNTI0NywtMS42NTk0IC0zNC40MzM2MTgsLTQuOTc3NyAtOC45MTgzNywtMy40NTY2IC0xNi4xODU1NzIsLTguNzExMyAtMjEuODAwODM5LC0xNS43NjMzIC01LjYxNTI3NywtNy4wNTIxIC0xMC4wNzQ3OTUsLTE2LjY2MDg4IC0xMy4zNzc4OTksLTI4LjgyODEyIGwgLTI0Ljc3MzE2MjYyOTM5NDUsMCAwLDU2LjgyNjMyIEMgMzMuODU2NzY5LDI4Ni4wNzYwMSA2My43NDkwNCwyODkuNzQyMDEgODkuNjc4MzgzLDI4OS43NDIwMSBjIDE2LjAyMDAyNywwIDMwLjcxOTc4NywtMS4zODI3IDQ0LjA5NzMzNywtNC4xNDc5IDEzLjU0MjcyLC0yLjkwNDMgMjUuMTA0MSwtNy40Njc2IDM0LjY4MzA5LC0xMy42ODkzIDkuNzQ0MTMsLTYuMzU5NyAxNy4zNDA0MiwtMTQuNTE5NSAyMi43OTA1MiwtMjQuNDc0OCA1LjQ1MDEsLTEwLjA5MzMyIDguMTc1MTEsLTIyLjM5OTU5IDguMTc1MTEsLTM2LjkxNjgyIDAsLTEyLjk5NzY0IC0zLjMwMjEsLTI0LjMzNTM5IC05LjkwODI5LC0zNC4wMTQ2IC02LjQ0MTA1LC05LjgxNzI1IC0xNS41MjU0NSwtMTguNTI3MDcgLTI3LjI1MTQ2LC0yNi4xMzEzMyAtMTEuNTYwODUsLTcuNjA0MjcgLTI3LjkxMDgzLC0xNS44MzE0MiAtNDkuMDUwNjYsLTI0LjY4MDIyIC0xNy41MDY0NCwtNy4xOTAxMiAtMzAuNzE5NjY4LC0xMy42ODk0OCAtMzkuNjM4MDM4LC0xOS40OTcwMSAtOC45MTgzNzEsLTUuODA3NTIgLTE4LjYwNzQ3NCwtMTIuNDM0MDkgLTI0LjA5NjUyNCwtMTguODc0MTcgLTUuNDI2MDQzLC02LjM2NjE2IC05LjY1ODgyNiwtMTUuMDcwMDMgLTkuNjU4ODI2LC0yNC44ODcyOSAwLC05LjI2NDAxIDIuMDc1NDE0LC0xNy4yMTM0NSA2LjIyMzQ1NCwtMjMuODUwMzMgMTEuMDk4Mjk4LC0xNC4zOTc0OCA0MS4yODY2MzgsLTEuNzk1MDcgNDUuMDc1NjA5LDI0LjM0NzYyIDQuODM5MzkyLDYuNzc0OTEgOC44NDkzNSwxNi4yNDcyOSAxMi4wMjk1MTUsMjguNDE1NiBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNC40NzgyNSwtNS45MjQ0OCAtOS45NTQ4OCwtMTAuNjMyMjIgLTE1LjkwODM3LC0xNC4zNzQxMSAxLjY0MDU1LDAuNDc5MDUgMy4xOTAzOSwxLjAyMzc2IDQuNjM4NjUsMS42NDAyNCA2LjQ5ODYxLDIuNjI2MDcgMTIuMTY3OTMsNy4zMjc0NyAxNy4wMDczLDE0LjEwMzQ1IDQuODM5MzksNi43NzQ5MSA4Ljg0OTM1LDE2LjI0NTY3IDEyLjAyOTUyLDI4LjQxMzk3IDAsMCA4LjQ4MTI4LC0wLjEyODk0IDguNDg5NzgsLTAuMDAyIDAuNDE3NzYsNi40MTQ5NCAtMS43NTMzOSw5LjQ1Mjg2IC00LjEyMzQyLDEyLjU2MTA0IC0yLjQxNzQsMy4xNjk3OCAtNS4xNDQ4Niw2Ljc4OTczIC00LjAwMjc4LDEzLjAwMjkgMS41MDc4Niw4LjIwMzE4IDEwLjE4MzU0LDEwLjU5NjQyIDE0LjYyMTk0LDkuMzExNTQgLTMuMzE4NDIsLTAuNDk5MTEgLTUuMzE4NTUsLTEuNzQ5NDggLTUuMzE4NTUsLTEuNzQ5NDggMCwwIDEuODc2NDYsMC45OTg2OCA1LjY1MTE3LC0xLjM1OTgxIC0zLjI3Njk1LDAuOTU1NzEgLTEwLjcwNTI5LC0wLjc5NzM4IC0xMS44MDEyNSwtNi43NjMxMyAtMC45NTc1MiwtNS4yMDg2MSAwLjk0NjU0LC03LjI5NTE0IDMuNDAxMTMsLTEwLjUxNDgyIDIuNDU0NjIsLTMuMjE5NjggNS4yODQyNiwtNi45NTgzMSA0LjY4NDMsLTE0LjQ4ODI0IGwgMC4wMDMsMC4wMDIgOC45MjY3NiwwIDAsLTU1Ljk5OTY3IGMgLTE1LjA3MTI1LC0zLjg3MTY4IC0yNy42NTMxNCwtNi4zNjA0MiAtMzcuNzQ2NzEsLTcuNDY1ODYgLTkuOTU1MzEsLTEuMTA3NTUgLTIwLjE4ODIzLC0xLjY1OTgxIC0zMC42OTY2MTMsLTEuNjU5ODEgeiBtIDcwLjMyMTYwMywxNy4zMDg5MyAwLjIzODA1LDQwLjMwNDkgYyAxLjMxODA4LDEuMjI2NjYgMi40Mzk2NSwyLjI3ODE1IDMuMzQwODEsMy4xMDYwMiA0LjgzOTM5LDYuNzc0OTEgOC44NDkzNCwxNi4yNDU2NiAxMi4wMjk1MSwyOC40MTM5NyBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNi42NzczMSwtNC41OTM4MSAtMTkuODM2NDMsLTEwLjQ3MzA5IC0zNi4xNDA3MSwtMTUuODI1MjIgeiBtIC0yOC4xMjA0OSw1LjYwNTUxIDguNTY0NzksMTcuNzE2NTUgYyAtMTEuOTcwMzcsLTYuNDY2OTcgLTEzLjg0Njc4LC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk3MDUsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IG0gMTUuMjIxOTUsMjQuMDA4NDggOC41NjQ3OSwxNy43MTY1NSBjIC0xMS45NzAzOCwtNi40NjY5NyAtMTMuODQ2NzksLTkuNzE3MjYgLTguNTY0NzksLTE3LjcxNjU1IHogbSAyMi43OTcwNCwwIGMgMi43NzE1LDcuOTk5MjkgMS43ODc0MSwxMS4yNDk1OCAtNC40OTM1NCwxNy43MTY1NSBsIDQuNDkzNTQsLTE3LjcxNjU1IHogbSAtOTkuMTEzODQsMi4yMDc2NCA4LjU2NDc5LDE3LjcxNjU1IGMgLTExLjk3MDM4MiwtNi40NjY5NyAtMTMuODQ2NzgyLC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk1NDIsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff750000',endColorstr='#ff340404',GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input::-webkit-input-placeholder{color:#999}body.syndicate input::-moz-placeholder{color:#999}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(even){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}.no-icons header.titlebar .statusicon{font-size:20px}.no-icons header.titlebar .statusicon:after{content:"O"}.no-icons header.titlebar .minimize{top:-2px;font-size:20px}.no-icons header.titlebar .minimize:after{content:"—"}.no-icons header.titlebar .close{font-size:20px}.no-icons header.titlebar .close:after{content:"X"} \ No newline at end of file +@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffb18b25",endColorstr="#ff5f380e",GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input::-webkit-input-placeholder{color:#999}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #5f380e;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgNDI1IDIwMCIgb3BhY2l0eT0iLjMzIj4NCiAgPHBhdGggZD0ibSAxNzguMDAzOTksMC4wMzg2OSAtNzEuMjAzOTMsMCBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgLTYuNzYxMzQsNi4wMjU1NSBsIDAsMTg3Ljg3MTQ3IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM0LDYuMDI1NTQgbCA1My4xMDcyLDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xMDEuNTQ0MDE4IDcyLjIxNjI4LDEwNC42OTkzOTggYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDUuNzYwMTUsMi44NzAxNiBsIDczLjU1NDg3LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xODcuODcxNDcgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTM1LC02LjAyNTU1IGwgLTU0LjcxNjQ0LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTMzLDYuMDI1NTUgbCAwLDEwMi42MTkzNSBMIDE4My43NjQxMywyLjkwODg2IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNS43NjAxNCwtMi44NzAxNyB6IiAvPg0KICA8cGF0aCBkPSJNIDQuODQ0NjMzMywyMi4xMDg3NSBBIDEzLjQxMjAzOSwxMi41MDE4NDIgMCAwIDEgMTMuNDc3NTg4LDAuMDM5MjQgbCA2Ni4xMTgzMTUsMCBhIDUuMzY0ODE1OCw1LjAwMDczNyAwIDAgMSA1LjM2NDgyMyw1LjAwMDczIGwgMCw3OS44NzkzMSB6IiAvPg0KICA8cGF0aCBkPSJtIDQyMC4xNTUzNSwxNzcuODkxMTkgYSAxMy40MTIwMzgsMTIuNTAxODQyIDAgMCAxIC04LjYzMjk1LDIyLjA2OTUxIGwgLTY2LjExODMyLDAgYSA1LjM2NDgxNTIsNS4wMDA3MzcgMCAwIDEgLTUuMzY0ODIsLTUuMDAwNzQgbCAwLC03OS44NzkzMSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input::-webkit-input-placeholder{color:#999}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgMjAwIDI4OS43NDIiIG9wYWNpdHk9Ii4zMyI+DQogIDxwYXRoIGQ9Im0gOTMuNTM3Njc3LDAgYyAtMTguMTEzMTI1LDAgLTM0LjIyMDEzMywzLjExMTY0IC00OC4zMjM0ODQsOS4zMzQzNyAtMTMuOTY1MDkyLDYuMjIxNjcgLTI0LjYxMjQ0MiwxNS4wNzExNCAtMzEuOTQwNjUxLDI2LjU0NzEgLTcuMTg5OTM5OCwxMS4zMzc4OSAtMTAuMzAxMjI2NiwyNC43NDkxMSAtMTAuMzAxMjI2Niw0MC4yMzQ3OCAwLDEwLjY0NjYyIDIuNzI1MDAyNiwyMC40NjQ2NSA4LjE3NTExMTYsMjkuNDUyNTggNS42MTUyNzcsOC45ODY4NiAxNC4wMzgyNzcsMTcuMzUyMDQgMjUuMjY4ODIxLDI1LjA5NDM2IDExLjIzMDU0NCw3LjYwNTMxIDI2LjUwNzQyMSwxNS40MTgzNSA0NS44MzA1MTQsMjMuNDM3ODIgMTkuOTgzNzQ4LDguMjk1NTcgMzQuODQ4ODQ4LDE1LjU1NDcxIDQ0LjU5Mjk5OCwyMS43NzYzOCA5Ljc0NDE0LDYuMjIyNzMgMTYuNzYxNywxMi44NTg1IDIxLjA1NTcyLDE5LjkwOTUxIDQuMjk0MDQsNy4wNTIwOCA2LjQ0MTkzLDE1Ljc2NDA4IDYuNDQxOTMsMjYuMTM0NTkgMCwxNi4xNzcwMiAtNS4yMDE5NiwyOC40ODIyMiAtMTUuNjA2NzMsMzYuOTE2ODIgLTEwLjIzOTYsOC40MzQ3IC0yNS4wMjIwMywxMi42NTIzIC00NC4zNDUxNjksMTIuNjUyMyAtMTQuMDM4MTcxLDAgLTI1LjUxNTI0NywtMS42NTk0IC0zNC40MzM2MTgsLTQuOTc3NyAtOC45MTgzNywtMy40NTY2IC0xNi4xODU1NzIsLTguNzExMyAtMjEuODAwODM5LC0xNS43NjMzIC01LjYxNTI3NywtNy4wNTIxIC0xMC4wNzQ3OTUsLTE2LjY2MDg4IC0xMy4zNzc4OTksLTI4LjgyODEyIGwgLTI0Ljc3MzE2MjYyOTM5NDUsMCAwLDU2LjgyNjMyIEMgMzMuODU2NzY5LDI4Ni4wNzYwMSA2My43NDkwNCwyODkuNzQyMDEgODkuNjc4MzgzLDI4OS43NDIwMSBjIDE2LjAyMDAyNywwIDMwLjcxOTc4NywtMS4zODI3IDQ0LjA5NzMzNywtNC4xNDc5IDEzLjU0MjcyLC0yLjkwNDMgMjUuMTA0MSwtNy40Njc2IDM0LjY4MzA5LC0xMy42ODkzIDkuNzQ0MTMsLTYuMzU5NyAxNy4zNDA0MiwtMTQuNTE5NSAyMi43OTA1MiwtMjQuNDc0OCA1LjQ1MDEsLTEwLjA5MzMyIDguMTc1MTEsLTIyLjM5OTU5IDguMTc1MTEsLTM2LjkxNjgyIDAsLTEyLjk5NzY0IC0zLjMwMjEsLTI0LjMzNTM5IC05LjkwODI5LC0zNC4wMTQ2IC02LjQ0MTA1LC05LjgxNzI1IC0xNS41MjU0NSwtMTguNTI3MDcgLTI3LjI1MTQ2LC0yNi4xMzEzMyAtMTEuNTYwODUsLTcuNjA0MjcgLTI3LjkxMDgzLC0xNS44MzE0MiAtNDkuMDUwNjYsLTI0LjY4MDIyIC0xNy41MDY0NCwtNy4xOTAxMiAtMzAuNzE5NjY4LC0xMy42ODk0OCAtMzkuNjM4MDM4LC0xOS40OTcwMSAtOC45MTgzNzEsLTUuODA3NTIgLTE4LjYwNzQ3NCwtMTIuNDM0MDkgLTI0LjA5NjUyNCwtMTguODc0MTcgLTUuNDI2MDQzLC02LjM2NjE2IC05LjY1ODgyNiwtMTUuMDcwMDMgLTkuNjU4ODI2LC0yNC44ODcyOSAwLC05LjI2NDAxIDIuMDc1NDE0LC0xNy4yMTM0NSA2LjIyMzQ1NCwtMjMuODUwMzMgMTEuMDk4Mjk4LC0xNC4zOTc0OCA0MS4yODY2MzgsLTEuNzk1MDcgNDUuMDc1NjA5LDI0LjM0NzYyIDQuODM5MzkyLDYuNzc0OTEgOC44NDkzNSwxNi4yNDcyOSAxMi4wMjk1MTUsMjguNDE1NiBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNC40NzgyNSwtNS45MjQ0OCAtOS45NTQ4OCwtMTAuNjMyMjIgLTE1LjkwODM3LC0xNC4zNzQxMSAxLjY0MDU1LDAuNDc5MDUgMy4xOTAzOSwxLjAyMzc2IDQuNjM4NjUsMS42NDAyNCA2LjQ5ODYxLDIuNjI2MDcgMTIuMTY3OTMsNy4zMjc0NyAxNy4wMDczLDE0LjEwMzQ1IDQuODM5MzksNi43NzQ5MSA4Ljg0OTM1LDE2LjI0NTY3IDEyLjAyOTUyLDI4LjQxMzk3IDAsMCA4LjQ4MTI4LC0wLjEyODk0IDguNDg5NzgsLTAuMDAyIDAuNDE3NzYsNi40MTQ5NCAtMS43NTMzOSw5LjQ1Mjg2IC00LjEyMzQyLDEyLjU2MTA0IC0yLjQxNzQsMy4xNjk3OCAtNS4xNDQ4Niw2Ljc4OTczIC00LjAwMjc4LDEzLjAwMjkgMS41MDc4Niw4LjIwMzE4IDEwLjE4MzU0LDEwLjU5NjQyIDE0LjYyMTk0LDkuMzExNTQgLTMuMzE4NDIsLTAuNDk5MTEgLTUuMzE4NTUsLTEuNzQ5NDggLTUuMzE4NTUsLTEuNzQ5NDggMCwwIDEuODc2NDYsMC45OTg2OCA1LjY1MTE3LC0xLjM1OTgxIC0zLjI3Njk1LDAuOTU1NzEgLTEwLjcwNTI5LC0wLjc5NzM4IC0xMS44MDEyNSwtNi43NjMxMyAtMC45NTc1MiwtNS4yMDg2MSAwLjk0NjU0LC03LjI5NTE0IDMuNDAxMTMsLTEwLjUxNDgyIDIuNDU0NjIsLTMuMjE5NjggNS4yODQyNiwtNi45NTgzMSA0LjY4NDMsLTE0LjQ4ODI0IGwgMC4wMDMsMC4wMDIgOC45MjY3NiwwIDAsLTU1Ljk5OTY3IGMgLTE1LjA3MTI1LC0zLjg3MTY4IC0yNy42NTMxNCwtNi4zNjA0MiAtMzcuNzQ2NzEsLTcuNDY1ODYgLTkuOTU1MzEsLTEuMTA3NTUgLTIwLjE4ODIzLC0xLjY1OTgxIC0zMC42OTY2MTMsLTEuNjU5ODEgeiBtIDcwLjMyMTYwMywxNy4zMDg5MyAwLjIzODA1LDQwLjMwNDkgYyAxLjMxODA4LDEuMjI2NjYgMi40Mzk2NSwyLjI3ODE1IDMuMzQwODEsMy4xMDYwMiA0LjgzOTM5LDYuNzc0OTEgOC44NDkzNCwxNi4yNDU2NiAxMi4wMjk1MSwyOC40MTM5NyBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNi42NzczMSwtNC41OTM4MSAtMTkuODM2NDMsLTEwLjQ3MzA5IC0zNi4xNDA3MSwtMTUuODI1MjIgeiBtIC0yOC4xMjA0OSw1LjYwNTUxIDguNTY0NzksMTcuNzE2NTUgYyAtMTEuOTcwMzcsLTYuNDY2OTcgLTEzLjg0Njc4LC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk3MDUsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IG0gMTUuMjIxOTUsMjQuMDA4NDggOC41NjQ3OSwxNy43MTY1NSBjIC0xMS45NzAzOCwtNi40NjY5NyAtMTMuODQ2NzksLTkuNzE3MjYgLTguNTY0NzksLTE3LjcxNjU1IHogbSAyMi43OTcwNCwwIGMgMi43NzE1LDcuOTk5MjkgMS43ODc0MSwxMS4yNDk1OCAtNC40OTM1NCwxNy43MTY1NSBsIDQuNDkzNTQsLTE3LjcxNjU1IHogbSAtOTkuMTEzODQsMi4yMDc2NCA4LjU2NDc5LDE3LjcxNjU1IGMgLTExLjk3MDM4MiwtNi40NjY5NyAtMTMuODQ2NzgyLC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk1NDIsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff750000",endColorstr="#ff340404",GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input::-webkit-input-placeholder{color:#999}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}.no-icons header.titlebar .statusicon{font-size:20px}.no-icons header.titlebar .statusicon:after{content:"O"}.no-icons header.titlebar .minimize{top:-2px;font-size:20px}.no-icons header.titlebar .minimize:after{content:"—"}.no-icons header.titlebar .close{font-size:20px}.no-icons header.titlebar .close:after{content:"X"} \ No newline at end of file diff --git a/tgui/assets/tgui.js b/tgui/assets/tgui.js index 5d42acb654..a41d648fe1 100644 --- a/tgui/assets/tgui.js +++ b/tgui/assets/tgui.js @@ -1,16 +1,16 @@ -require=function t(e,n,a){function r(o,s){if(!n[o]){if(!e[o]){var u="function"==typeof require&&require;if(!s&&u)return u(o,!0);if(i)return i(o,!0);var p=Error("Cannot find module '"+o+"'");throw p.code="MODULE_NOT_FOUND",p}var c=n[o]={exports:{}};e[o][0].call(c.exports,function(t){var n=e[o][1][t];return r(n?n:t)},c,c.exports,t,e,n,a)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o2?p[2]:void 0,l=Math.min((void 0===c?o:r(c,o))-u,o-s),f=1;for(s>u&&u+l>s&&(f=-1,u+=l-1,s+=l-1);l-- >0;)u in n?n[s]=n[u]:delete n[s],s+=f,u+=f;return n}},{76:76,79:79,80:80}],6:[function(t,e,n){"use strict";var a=t(80),r=t(76),i=t(79);e.exports=[].fill||function(t){for(var e=a(this),n=i(e.length),o=arguments,s=o.length,u=r(s>1?o[1]:void 0,n),p=s>2?o[2]:void 0,c=void 0===p?n:r(p,n);c>u;)e[u++]=t;return e}},{76:76,79:79,80:80}],7:[function(t,e,n){var a=t(78),r=t(79),i=t(76);e.exports=function(t){return function(e,n,o){var s,u=a(e),p=r(u.length),c=i(o,p);if(t&&n!=n){for(;p>c;)if(s=u[c++],s!=s)return!0}else for(;p>c;c++)if((t||c in u)&&u[c]===n)return t||c;return!t&&-1}}},{76:76,78:78,79:79}],8:[function(t,e,n){var a=t(17),r=t(34),i=t(80),o=t(79),s=t(9);e.exports=function(t){var e=1==t,n=2==t,u=3==t,p=4==t,c=6==t,l=5==t||c;return function(f,d,h){for(var m,v,g=i(f),b=r(g),y=a(d,h,3),x=o(b.length),_=0,w=e?s(f,x):n?s(f,0):void 0;x>_;_++)if((l||_ in b)&&(m=b[_],v=y(m,_,g),t))if(e)w[_]=v;else if(v)switch(t){case 3:return!0;case 5:return m;case 6:return _;case 2:w.push(m)}else if(p)return!1;return c?-1:u||p?p:w}}},{17:17,34:34,79:79,80:80,9:9}],9:[function(t,e,n){var a=t(38),r=t(36),i=t(83)("species");e.exports=function(t,e){var n;return r(t)&&(n=t.constructor,"function"!=typeof n||n!==Array&&!r(n.prototype)||(n=void 0),a(n)&&(n=n[i],null===n&&(n=void 0))),new(void 0===n?Array:n)(e)}},{36:36,38:38,83:83}],10:[function(t,e,n){var a=t(11),r=t(83)("toStringTag"),i="Arguments"==a(function(){return arguments}());e.exports=function(t){var e,n,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=(e=Object(t))[r])?n:i?a(e):"Object"==(o=a(e))&&"function"==typeof e.callee?"Arguments":o}},{11:11,83:83}],11:[function(t,e,n){var a={}.toString;e.exports=function(t){return a.call(t).slice(8,-1)}},{}],12:[function(t,e,n){"use strict";var a=t(46),r=t(31),i=t(60),o=t(17),s=t(69),u=t(18),p=t(27),c=t(42),l=t(44),f=t(82)("id"),d=t(30),h=t(38),m=t(65),v=t(19),g=Object.isExtensible||h,b=v?"_s":"size",y=0,x=function(t,e){if(!h(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!d(t,f)){if(!g(t))return"F";if(!e)return"E";r(t,f,++y)}return"O"+t[f]},_=function(t,e){var n,a=x(e);if("F"!==a)return t._i[a];for(n=t._f;n;n=n.n)if(n.k==e)return n};e.exports={getConstructor:function(t,e,n,r){var c=t(function(t,i){s(t,c,e),t._i=a.create(null),t._f=void 0,t._l=void 0,t[b]=0,void 0!=i&&p(i,n,t[r],t)});return i(c.prototype,{clear:function(){for(var t=this,e=t._i,n=t._f;n;n=n.n)n.r=!0,n.p&&(n.p=n.p.n=void 0),delete e[n.i];t._f=t._l=void 0,t[b]=0},"delete":function(t){var e=this,n=_(e,t);if(n){var a=n.n,r=n.p;delete e._i[n.i],n.r=!0,r&&(r.n=a),a&&(a.p=r),e._f==n&&(e._f=a),e._l==n&&(e._l=r),e[b]--}return!!n},forEach:function(t){for(var e,n=o(t,arguments.length>1?arguments[1]:void 0,3);e=e?e.n:this._f;)for(n(e.v,e.k,this);e&&e.r;)e=e.p},has:function(t){return!!_(this,t)}}),v&&a.setDesc(c.prototype,"size",{get:function(){return u(this[b])}}),c},def:function(t,e,n){var a,r,i=_(t,e);return i?i.v=n:(t._l=i={i:r=x(e,!0),k:e,v:n,p:a=t._l,n:void 0,r:!1},t._f||(t._f=i),a&&(a.n=i),t[b]++,"F"!==r&&(t._i[r]=i)),t},getEntry:_,setStrong:function(t,e,n){c(t,e,function(t,e){this._t=t,this._k=e,this._l=void 0},function(){for(var t=this,e=t._k,n=t._l;n&&n.r;)n=n.p;return t._t&&(t._l=n=n?n.n:t._t._f)?"keys"==e?l(0,n.k):"values"==e?l(0,n.v):l(0,[n.k,n.v]):(t._t=void 0,l(1))},n?"entries":"values",!n,!0),m(e)}}},{17:17,18:18,19:19,27:27,30:30,31:31,38:38,42:42,44:44,46:46,60:60,65:65,69:69,82:82}],13:[function(t,e,n){var a=t(27),r=t(10);e.exports=function(t){return function(){if(r(this)!=t)throw TypeError(t+"#toJSON isn't generic");var e=[];return a(this,!1,e.push,e),e}}},{10:10,27:27}],14:[function(t,e,n){"use strict";var a=t(31),r=t(60),i=t(4),o=t(38),s=t(69),u=t(27),p=t(8),c=t(30),l=t(82)("weak"),f=Object.isExtensible||o,d=p(5),h=p(6),m=0,v=function(t){return t._l||(t._l=new g)},g=function(){this.a=[]},b=function(t,e){return d(t.a,function(t){return t[0]===e})};g.prototype={get:function(t){var e=b(this,t);return e?e[1]:void 0},has:function(t){return!!b(this,t)},set:function(t,e){var n=b(this,t);n?n[1]=e:this.a.push([t,e])},"delete":function(t){var e=h(this.a,function(e){return e[0]===t});return~e&&this.a.splice(e,1),!!~e}},e.exports={getConstructor:function(t,e,n,a){var i=t(function(t,r){s(t,i,e),t._i=m++,t._l=void 0,void 0!=r&&u(r,n,t[a],t)});return r(i.prototype,{"delete":function(t){return o(t)?f(t)?c(t,l)&&c(t[l],this._i)&&delete t[l][this._i]:v(this)["delete"](t):!1},has:function(t){return o(t)?f(t)?c(t,l)&&c(t[l],this._i):v(this).has(t):!1}}),i},def:function(t,e,n){return f(i(e))?(c(e,l)||a(e,l,{}),e[l][t._i]=n):v(t).set(e,n),t},frozenStore:v,WEAK:l}},{27:27,30:30,31:31,38:38,4:4,60:60,69:69,8:8,82:82}],15:[function(t,e,n){"use strict";var a=t(29),r=t(22),i=t(61),o=t(60),s=t(27),u=t(69),p=t(38),c=t(24),l=t(43),f=t(66);e.exports=function(t,e,n,d,h,m){var v=a[t],g=v,b=h?"set":"add",y=g&&g.prototype,x={},_=function(t){var e=y[t];i(y,t,"delete"==t?function(t){return m&&!p(t)?!1:e.call(this,0===t?0:t)}:"has"==t?function(t){return m&&!p(t)?!1:e.call(this,0===t?0:t)}:"get"==t?function(t){return m&&!p(t)?void 0:e.call(this,0===t?0:t)}:"add"==t?function(t){return e.call(this,0===t?0:t),this}:function(t,n){return e.call(this,0===t?0:t,n),this})};if("function"==typeof g&&(m||y.forEach&&!c(function(){(new g).entries().next()}))){var w,k=new g,E=k[b](m?{}:-0,1)!=k,S=c(function(){k.has(1)}),C=l(function(t){new g(t)});C||(g=e(function(e,n){u(e,g,t);var a=new v;return void 0!=n&&s(n,h,a[b],a),a}),g.prototype=y,y.constructor=g),m||k.forEach(function(t,e){w=1/e===-(1/0)}),(S||w)&&(_("delete"),_("has"),h&&_("get")),(w||E)&&_(b),m&&y.clear&&delete y.clear}else g=d.getConstructor(e,t,h,b),o(g.prototype,n);return f(g,t),x[t]=g,r(r.G+r.W+r.F*(g!=v),x),m||d.setStrong(g,t,h),g}},{22:22,24:24,27:27,29:29,38:38,43:43,60:60,61:61,66:66,69:69}],16:[function(t,e,n){var a=e.exports={version:"1.2.6"};"number"==typeof __e&&(__e=a)},{}],17:[function(t,e,n){var a=t(2);e.exports=function(t,e,n){if(a(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,a){return t.call(e,n,a)};case 3:return function(n,a,r){return t.call(e,n,a,r)}}return function(){return t.apply(e,arguments)}}},{2:2}],18:[function(t,e,n){e.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},{}],19:[function(t,e,n){e.exports=!t(24)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},{24:24}],20:[function(t,e,n){var a=t(38),r=t(29).document,i=a(r)&&a(r.createElement);e.exports=function(t){return i?r.createElement(t):{}}},{29:29,38:38}],21:[function(t,e,n){var a=t(46);e.exports=function(t){var e=a.getKeys(t),n=a.getSymbols;if(n)for(var r,i=n(t),o=a.isEnum,s=0;i.length>s;)o.call(t,r=i[s++])&&e.push(r);return e}},{46:46}],22:[function(t,e,n){var a=t(29),r=t(16),i=t(31),o=t(61),s=t(17),u="prototype",p=function(t,e,n){var c,l,f,d,h=t&p.F,m=t&p.G,v=t&p.S,g=t&p.P,b=t&p.B,y=m?a:v?a[e]||(a[e]={}):(a[e]||{})[u],x=m?r:r[e]||(r[e]={}),_=x[u]||(x[u]={});m&&(n=e);for(c in n)l=!h&&y&&c in y,f=(l?y:n)[c],d=b&&l?s(f,a):g&&"function"==typeof f?s(Function.call,f):f,y&&!l&&o(y,c,f),x[c]!=f&&i(x,c,d),g&&_[c]!=f&&(_[c]=f)};a.core=r,p.F=1,p.G=2,p.S=4,p.P=8,p.B=16,p.W=32,e.exports=p},{16:16,17:17,29:29,31:31,61:61}],23:[function(t,e,n){var a=t(83)("match");e.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[a]=!1,!"/./"[t](e)}catch(r){}}return!0}},{83:83}],24:[function(t,e,n){e.exports=function(t){try{return!!t()}catch(e){return!0}}},{}],25:[function(t,e,n){"use strict";var a=t(31),r=t(61),i=t(24),o=t(18),s=t(83);e.exports=function(t,e,n){var u=s(t),p=""[t];i(function(){var e={};return e[u]=function(){return 7},7!=""[t](e)})&&(r(String.prototype,t,n(o,u,p)),a(RegExp.prototype,u,2==e?function(t,e){return p.call(t,this,e)}:function(t){return p.call(t,this)}))}},{18:18,24:24,31:31,61:61,83:83}],26:[function(t,e,n){"use strict";var a=t(4);e.exports=function(){var t=a(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},{4:4}],27:[function(t,e,n){var a=t(17),r=t(40),i=t(35),o=t(4),s=t(79),u=t(84);e.exports=function(t,e,n,p){var c,l,f,d=u(t),h=a(n,p,e?2:1),m=0;if("function"!=typeof d)throw TypeError(t+" is not iterable!");if(i(d))for(c=s(t.length);c>m;m++)e?h(o(l=t[m])[0],l[1]):h(t[m]);else for(f=d.call(t);!(l=f.next()).done;)r(f,h,l.value,e)}},{17:17,35:35,4:4,40:40,79:79,84:84}],28:[function(t,e,n){var a=t(78),r=t(46).getNames,i={}.toString,o="object"==typeof window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(t){try{return r(t)}catch(e){return o.slice()}};e.exports.get=function(t){return o&&"[object Window]"==i.call(t)?s(t):r(a(t))}},{46:46,78:78}],29:[function(t,e,n){var a=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=a)},{}],30:[function(t,e,n){var a={}.hasOwnProperty;e.exports=function(t,e){return a.call(t,e)}},{}],31:[function(t,e,n){var a=t(46),r=t(59);e.exports=t(19)?function(t,e,n){return a.setDesc(t,e,r(1,n))}:function(t,e,n){return t[e]=n,t}},{19:19,46:46,59:59}],32:[function(t,e,n){e.exports=t(29).document&&document.documentElement},{29:29}],33:[function(t,e,n){e.exports=function(t,e,n){var a=void 0===n;switch(e.length){case 0:return a?t():t.call(n);case 1:return a?t(e[0]):t.call(n,e[0]);case 2:return a?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return a?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return a?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},{}],34:[function(t,e,n){var a=t(11);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==a(t)?t.split(""):Object(t)}},{11:11}],35:[function(t,e,n){var a=t(45),r=t(83)("iterator"),i=Array.prototype;e.exports=function(t){return void 0!==t&&(a.Array===t||i[r]===t)}},{45:45,83:83}],36:[function(t,e,n){var a=t(11);e.exports=Array.isArray||function(t){return"Array"==a(t)}},{11:11}],37:[function(t,e,n){var a=t(38),r=Math.floor;e.exports=function(t){return!a(t)&&isFinite(t)&&r(t)===t}},{38:38}],38:[function(t,e,n){e.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},{}],39:[function(t,e,n){var a=t(38),r=t(11),i=t(83)("match");e.exports=function(t){var e;return a(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==r(t))}},{11:11,38:38,83:83}],40:[function(t,e,n){var a=t(4);e.exports=function(t,e,n,r){try{return r?e(a(n)[0],n[1]):e(n)}catch(i){var o=t["return"];throw void 0!==o&&a(o.call(t)),i}}},{4:4}],41:[function(t,e,n){"use strict";var a=t(46),r=t(59),i=t(66),o={};t(31)(o,t(83)("iterator"),function(){return this}),e.exports=function(t,e,n){t.prototype=a.create(o,{next:r(1,n)}),i(t,e+" Iterator")}},{31:31,46:46,59:59,66:66,83:83}],42:[function(t,e,n){"use strict";var a=t(48),r=t(22),i=t(61),o=t(31),s=t(30),u=t(45),p=t(41),c=t(66),l=t(46).getProto,f=t(83)("iterator"),d=!([].keys&&"next"in[].keys()),h="@@iterator",m="keys",v="values",g=function(){return this};e.exports=function(t,e,n,b,y,x,_){p(n,e,b);var w,k,E=function(t){if(!d&&t in A)return A[t];switch(t){case m:return function(){return new n(this,t)};case v:return function(){return new n(this,t)}}return function(){return new n(this,t)}},S=e+" Iterator",C=y==v,P=!1,A=t.prototype,O=A[f]||A[h]||y&&A[y],T=O||E(y);if(O){var R=l(T.call(new t));c(R,S,!0),!a&&s(A,h)&&o(R,f,g),C&&O.name!==v&&(P=!0,T=function(){return O.call(this)})}if(a&&!_||!d&&!P&&A[f]||o(A,f,T),u[e]=T,u[S]=g,y)if(w={values:C?T:E(v),keys:x?T:E(m),entries:C?E("entries"):T},_)for(k in w)k in A||i(A,k,w[k]);else r(r.P+r.F*(d||P),e,w);return w}},{22:22,30:30,31:31,41:41,45:45,46:46,48:48,61:61,66:66,83:83}],43:[function(t,e,n){var a=t(83)("iterator"),r=!1;try{var i=[7][a]();i["return"]=function(){r=!0},Array.from(i,function(){throw 2})}catch(o){}e.exports=function(t,e){if(!e&&!r)return!1;var n=!1;try{var i=[7],o=i[a]();o.next=function(){return{done:n=!0}},i[a]=function(){return o},t(i)}catch(s){}return n}},{83:83}],44:[function(t,e,n){e.exports=function(t,e){return{value:e,done:!!t}}},{}],45:[function(t,e,n){e.exports={}},{}],46:[function(t,e,n){var a=Object;e.exports={create:a.create,getProto:a.getPrototypeOf,isEnum:{}.propertyIsEnumerable,getDesc:a.getOwnPropertyDescriptor,setDesc:a.defineProperty,setDescs:a.defineProperties,getKeys:a.keys,getNames:a.getOwnPropertyNames,getSymbols:a.getOwnPropertySymbols,each:[].forEach}},{}],47:[function(t,e,n){var a=t(46),r=t(78);e.exports=function(t,e){for(var n,i=r(t),o=a.getKeys(i),s=o.length,u=0;s>u;)if(i[n=o[u++]]===e)return n}},{46:46,78:78}],48:[function(t,e,n){e.exports=!1},{}],49:[function(t,e,n){e.exports=Math.expm1||function(t){return 0==(t=+t)?t:t>-1e-6&&1e-6>t?t+t*t/2:Math.exp(t)-1}},{}],50:[function(t,e,n){e.exports=Math.log1p||function(t){return(t=+t)>-1e-8&&1e-8>t?t-t*t/2:Math.log(1+t)}},{}],51:[function(t,e,n){e.exports=Math.sign||function(t){return 0==(t=+t)||t!=t?t:0>t?-1:1}},{}],52:[function(t,e,n){var a,r,i,o=t(29),s=t(75).set,u=o.MutationObserver||o.WebKitMutationObserver,p=o.process,c=o.Promise,l="process"==t(11)(p),f=function(){var t,e,n;for(l&&(t=p.domain)&&(p.domain=null,t.exit());a;)e=a.domain,n=a.fn,e&&e.enter(),n(),e&&e.exit(),a=a.next;r=void 0,t&&t.enter()};if(l)i=function(){p.nextTick(f)};else if(u){var d=1,h=document.createTextNode("");new u(f).observe(h,{characterData:!0}),i=function(){h.data=d=-d}}else i=c&&c.resolve?function(){c.resolve().then(f)}:function(){s.call(o,f)};e.exports=function(t){var e={fn:t,next:void 0,domain:l&&p.domain};r&&(r.next=e),a||(a=e,i()),r=e}},{11:11,29:29,75:75}],53:[function(t,e,n){var a=t(46),r=t(80),i=t(34);e.exports=t(24)(function(){var t=Object.assign,e={},n={},a=Symbol(),r="abcdefghijklmnopqrst";return e[a]=7,r.split("").forEach(function(t){n[t]=t}),7!=t({},e)[a]||Object.keys(t({},n)).join("")!=r})?function(t,e){for(var n=r(t),o=arguments,s=o.length,u=1,p=a.getKeys,c=a.getSymbols,l=a.isEnum;s>u;)for(var f,d=i(o[u++]),h=c?p(d).concat(c(d)):p(d),m=h.length,v=0;m>v;)l.call(d,f=h[v++])&&(n[f]=d[f]);return n}:Object.assign},{24:24,34:34,46:46,80:80}],54:[function(t,e,n){var a=t(22),r=t(16),i=t(24);e.exports=function(t,e){var n=(r.Object||{})[t]||Object[t],o={};o[t]=e(n),a(a.S+a.F*i(function(){n(1)}),"Object",o)}},{16:16,22:22,24:24}],55:[function(t,e,n){var a=t(46),r=t(78),i=a.isEnum;e.exports=function(t){return function(e){for(var n,o=r(e),s=a.getKeys(o),u=s.length,p=0,c=[];u>p;)i.call(o,n=s[p++])&&c.push(t?[n,o[n]]:o[n]);return c}}},{46:46,78:78}],56:[function(t,e,n){var a=t(46),r=t(4),i=t(29).Reflect;e.exports=i&&i.ownKeys||function(t){var e=a.getNames(r(t)),n=a.getSymbols;return n?e.concat(n(t)):e}},{29:29,4:4,46:46}],57:[function(t,e,n){"use strict";var a=t(58),r=t(33),i=t(2);e.exports=function(){for(var t=i(this),e=arguments.length,n=Array(e),o=0,s=a._,u=!1;e>o;)(n[o]=arguments[o++])===s&&(u=!0);return function(){var a,i=this,o=arguments,p=o.length,c=0,l=0;if(!u&&!p)return r(t,n,i);if(a=n.slice(),u)for(;e>c;c++)a[c]===s&&(a[c]=o[l++]);for(;p>l;)a.push(o[l++]);return r(t,a,i)}}},{2:2,33:33,58:58}],58:[function(t,e,n){e.exports=t(29)},{29:29}],59:[function(t,e,n){e.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},{}],60:[function(t,e,n){var a=t(61);e.exports=function(t,e){for(var n in e)a(t,n,e[n]);return t}},{61:61}],61:[function(t,e,n){var a=t(29),r=t(31),i=t(82)("src"),o="toString",s=Function[o],u=(""+s).split(o);t(16).inspectSource=function(t){return s.call(t)},(e.exports=function(t,e,n,o){"function"==typeof n&&(n.hasOwnProperty(i)||r(n,i,t[e]?""+t[e]:u.join(e+"")),n.hasOwnProperty("name")||r(n,"name",e)),t===a?t[e]=n:(o||delete t[e],r(t,e,n))})(Function.prototype,o,function(){return"function"==typeof this&&this[i]||s.call(this)})},{16:16,29:29,31:31,82:82}],62:[function(t,e,n){e.exports=function(t,e){var n=e===Object(e)?function(t){return e[t]}:e;return function(e){return(e+"").replace(t,n)}}},{}],63:[function(t,e,n){e.exports=Object.is||function(t,e){return t===e?0!==t||1/t===1/e:t!=t&&e!=e}},{}],64:[function(t,e,n){var a=t(46).getDesc,r=t(38),i=t(4),o=function(t,e){if(i(t),!r(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,n,r){try{r=t(17)(Function.call,a(Object.prototype,"__proto__").set,2),r(e,[]),n=!(e instanceof Array)}catch(i){n=!0}return function(t,e){return o(t,e),n?t.__proto__=e:r(t,e),t}}({},!1):void 0),check:o}},{17:17,38:38,4:4,46:46}],65:[function(t,e,n){"use strict";var a=t(29),r=t(46),i=t(19),o=t(83)("species");e.exports=function(t){var e=a[t];i&&e&&!e[o]&&r.setDesc(e,o,{configurable:!0,get:function(){return this}})}},{19:19,29:29,46:46,83:83}],66:[function(t,e,n){var a=t(46).setDesc,r=t(30),i=t(83)("toStringTag");e.exports=function(t,e,n){t&&!r(t=n?t:t.prototype,i)&&a(t,i,{configurable:!0,value:e})}},{30:30,46:46,83:83}],67:[function(t,e,n){var a=t(29),r="__core-js_shared__",i=a[r]||(a[r]={});e.exports=function(t){return i[t]||(i[t]={})}},{29:29}],68:[function(t,e,n){var a=t(4),r=t(2),i=t(83)("species");e.exports=function(t,e){var n,o=a(t).constructor;return void 0===o||void 0==(n=a(o)[i])?e:r(n)}},{2:2,4:4,83:83}],69:[function(t,e,n){e.exports=function(t,e,n){if(!(t instanceof e))throw TypeError(n+": use the 'new' operator!");return t}},{}],70:[function(t,e,n){var a=t(77),r=t(18);e.exports=function(t){return function(e,n){var i,o,s=r(e)+"",u=a(n),p=s.length;return 0>u||u>=p?t?"":void 0:(i=s.charCodeAt(u),55296>i||i>56319||u+1===p||(o=s.charCodeAt(u+1))<56320||o>57343?t?s.charAt(u):i:t?s.slice(u,u+2):(i-55296<<10)+(o-56320)+65536)}}},{18:18,77:77}],71:[function(t,e,n){var a=t(39),r=t(18);e.exports=function(t,e,n){if(a(e))throw TypeError("String#"+n+" doesn't accept regex!");return r(t)+""}},{18:18,39:39}],72:[function(t,e,n){var a=t(79),r=t(73),i=t(18);e.exports=function(t,e,n,o){var s=i(t)+"",u=s.length,p=void 0===n?" ":n+"",c=a(e);if(u>=c)return s;""==p&&(p=" ");var l=c-u,f=r.call(p,Math.ceil(l/p.length));return f.length>l&&(f=f.slice(0,l)),o?f+s:s+f}},{18:18,73:73,79:79}],73:[function(t,e,n){"use strict";var a=t(77),r=t(18);e.exports=function(t){var e=r(this)+"",n="",i=a(t);if(0>i||i==1/0)throw RangeError("Count can't be negative");for(;i>0;(i>>>=1)&&(e+=e))1&i&&(n+=e);return n}},{18:18,77:77}],74:[function(t,e,n){var a=t(22),r=t(18),i=t(24),o=" \n\x0B\f\r  ᠎              \u2028\u2029\ufeff",s="["+o+"]",u="​…",p=RegExp("^"+s+s+"*"),c=RegExp(s+s+"*$"),l=function(t,e){var n={};n[t]=e(f),a(a.P+a.F*i(function(){return!!o[t]()||u[t]()!=u}),"String",n)},f=l.trim=function(t,e){return t=r(t)+"",1&e&&(t=t.replace(p,"")),2&e&&(t=t.replace(c,"")),t};e.exports=l},{18:18,22:22,24:24}],75:[function(t,e,n){var a,r,i,o=t(17),s=t(33),u=t(32),p=t(20),c=t(29),l=c.process,f=c.setImmediate,d=c.clearImmediate,h=c.MessageChannel,m=0,v={},g="onreadystatechange",b=function(){var t=+this;if(v.hasOwnProperty(t)){var e=v[t];delete v[t],e()}},y=function(t){b.call(t.data)};f&&d||(f=function(t){for(var e=[],n=1;arguments.length>n;)e.push(arguments[n++]);return v[++m]=function(){s("function"==typeof t?t:Function(t),e)},a(m),m},d=function(t){delete v[t]},"process"==t(11)(l)?a=function(t){l.nextTick(o(b,t,1))}:h?(r=new h,i=r.port2,r.port1.onmessage=y,a=o(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(a=function(t){c.postMessage(t+"","*")},c.addEventListener("message",y,!1)):a=g in p("script")?function(t){u.appendChild(p("script"))[g]=function(){u.removeChild(this),b.call(t)}}:function(t){setTimeout(o(b,t,1),0)}),e.exports={set:f,clear:d}},{11:11,17:17,20:20,29:29,32:32,33:33}],76:[function(t,e,n){var a=t(77),r=Math.max,i=Math.min;e.exports=function(t,e){return t=a(t),0>t?r(t+e,0):i(t,e)}},{77:77}],77:[function(t,e,n){var a=Math.ceil,r=Math.floor;e.exports=function(t){return isNaN(t=+t)?0:(t>0?r:a)(t)}},{}],78:[function(t,e,n){var a=t(34),r=t(18);e.exports=function(t){return a(r(t))}},{18:18,34:34}],79:[function(t,e,n){var a=t(77),r=Math.min;e.exports=function(t){return t>0?r(a(t),9007199254740991):0}},{77:77}],80:[function(t,e,n){var a=t(18);e.exports=function(t){return Object(a(t))}},{18:18}],81:[function(t,e,n){var a=t(38);e.exports=function(t,e){if(!a(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!a(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!a(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!a(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")}},{38:38}],82:[function(t,e,n){var a=0,r=Math.random();e.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++a+r).toString(36))}},{}],83:[function(t,e,n){var a=t(67)("wks"),r=t(82),i=t(29).Symbol;e.exports=function(t){return a[t]||(a[t]=i&&i[t]||(i||r)("Symbol."+t))}},{29:29,67:67,82:82}],84:[function(t,e,n){var a=t(10),r=t(83)("iterator"),i=t(45);e.exports=t(16).getIteratorMethod=function(t){return void 0!=t?t[r]||t["@@iterator"]||i[a(t)]:void 0}},{10:10,16:16,45:45,83:83}],85:[function(t,e,n){"use strict";var a,r=t(46),i=t(22),o=t(19),s=t(59),u=t(32),p=t(20),c=t(30),l=t(11),f=t(33),d=t(24),h=t(4),m=t(2),v=t(38),g=t(80),b=t(78),y=t(77),x=t(76),_=t(79),w=t(34),k=t(82)("__proto__"),E=t(8),S=t(7)(!1),C=Object.prototype,P=Array.prototype,A=P.slice,O=P.join,T=r.setDesc,R=r.getDesc,j=r.setDescs,M={};o||(a=!d(function(){return 7!=T(p("div"),"a",{get:function(){return 7}}).a}),r.setDesc=function(t,e,n){if(a)try{return T(t,e,n)}catch(r){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(h(t)[e]=n.value),t},r.getDesc=function(t,e){if(a)try{return R(t,e)}catch(n){}return c(t,e)?s(!C.propertyIsEnumerable.call(t,e),t[e]):void 0},r.setDescs=j=function(t,e){h(t);for(var n,a=r.getKeys(e),i=a.length,o=0;i>o;)r.setDesc(t,n=a[o++],e[n]);return t}),i(i.S+i.F*!o,"Object",{getOwnPropertyDescriptor:r.getDesc,defineProperty:r.setDesc,defineProperties:j});var L="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),D=L.concat("length","prototype"),N=L.length,F=function(){var t,e=p("iframe"),n=N,a=">";for(e.style.display="none",u.appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write(" -
    - - - - - -
    - - - - -
    - [sprite_text] -
    - [atomsnowflake.Join()] -
    -
    -
    - [formatted_type] - [marked] - [varedited_line] -
    -
    -
    - Refresh -
    - -
    -
    -
    -
    -
    - - E - Edit, tries to determine the variable type by itself.
    - C - Change, asks you for the var type first.
    - M - Mass modify: changes this variable for all objects of this type.
    -
    -
    - - - - - -
    -
    - Search: -
    -
    - -
    -
    -
      - [variable_html.Join()] -
    - - - -"} - - usr << browse(html, "window=variables[refid];size=475x650") - - -#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) -/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) - var/header - if(DA) - if (islist(DA)) - var/index = name - if (value) - name = DA[name] //name is really the index until this line - else - value = DA[name] - header = "
  • (E) (C) (-) " - else - header = "
  • (E) (C) (M) " - else - header = "
  • " - - var/item - if (isnull(value)) - item = "[VV_HTML_ENCODE(name)] = null" - - else if (istext(value)) - item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" - - else if (isicon(value)) - #ifdef VARSICON - var/icon/I = new/icon(value) - var/rnd = rand(1,10000) - var/rname = "tmp\ref[I][rnd].png" - usr << browse_rsc(I, rname) - item = "[VV_HTML_ENCODE(name)] = ([value]) " - #else - item = "[VV_HTML_ENCODE(name)] = /icon ([value])" - #endif - -/* else if (istype(value, /image)) - #ifdef VARSICON - var/rnd = rand(1, 10000) - var/image/I = value - - src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") - html += "[name] = " - #else - html += "[name] = /image ([value])" - #endif -*/ - else if (isfile(value)) - item = "[VV_HTML_ENCODE(name)] = '[value]'" - - //else if (istype(value, /client)) - // var/client/C = value - // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" - - else if (istype(value, /datum)) - var/datum/D = value - if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. - item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" - else - item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" - - else if (islist(value)) - var/list/L = value - var/list/items = list() - - if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) - for (var/i in 1 to L.len) - var/key = L[i] - var/val - if (IS_NORMAL_LIST(L) && !isnum(key)) - val = L[key] - if (!val) - val = key - key = i - - items += debug_variable(key, val, level + 1, sanitize = sanitize) - - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " - else - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" - - else - item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" - - return "[header][item]
  • " - -#undef VV_HTML_ENCODE - -/client/proc/view_var_Topic(href, href_list, hsrc) - if( (usr.client != src) || !src.holder ) - return - if(href_list["Vars"]) - debug_variables(locate(href_list["Vars"])) - - else if(href_list["datumrefresh"]) - var/datum/DAT = locate(href_list["datumrefresh"]) - if(!DAT) //can't be an istype() because /client etc aren't datums - return - src.debug_variables(DAT) - - else if(href_list["mob_player_panel"]) - if(!check_rights(0)) - return - /datum/proc/vv_get_dropdown() . = list() . += "---" @@ -1009,22 +546,6 @@ to_chat(usr, "This can only be done to instances of type /mob") return M.regenerate_icons() - -//Needs +VAREDIT past this point - - else if(check_rights(R_VAREDIT)) - - - //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). - - if(href_list["rename"]) - if(!check_rights(0)) - return - - if(!ismob(M)) - to_chat(usr, "This can only be done to instances of type /mob") - return - M.regenerate_icons() else if(href_list["expose"]) if(!check_rights(R_ADMIN, FALSE)) return From 726b86f3a4d48ddb1d8ce61411fd1487a812c416 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 14:18:28 -0500 Subject: [PATCH 062/102] Update on_move.dm --- code/modules/shuttle/on_move.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index f2c84a5aae..77eec512d8 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -14,7 +14,6 @@ All ShuttleMove procs go here // Called from the new turf before anything has been moved // Only gets called if fromShuttleMove returns true first // returns the new move_mode (based on the old) -/turf/proc/toShuttleMove(turf/oldT, shuttle_dir, move_mode) /turf/proc/toShuttleMove(turf/oldT, move_mode, obj/docking_port/mobile/shuttle) var/shuttle_dir = shuttle.dir for(var/i in contents) From 7cdd5eaa02a2b8eb64aa8b7b86006edca55f3a46 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 14:22:23 -0500 Subject: [PATCH 063/102] Update admin.dm --- code/__DEFINES/admin.dm | 151 ++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 77 deletions(-) diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 00d81fe7c7..c5c79b9610 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -1,79 +1,77 @@ -<<<<<<< HEAD -//A set of constants used to determine which type of mute an admin wishes to apply: -//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) -//Therefore there needs to be a gap between the flags_1 for the automute flags_1 -#define MUTE_IC 1 -#define MUTE_OOC 2 -#define MUTE_PRAY 4 -#define MUTE_ADMINHELP 8 -#define MUTE_DEADCHAT 16 -#define MUTE_ALL 31 - -//Some constants for DB_Ban -#define BANTYPE_PERMA 1 -#define BANTYPE_TEMP 2 -#define BANTYPE_JOB_PERMA 3 -#define BANTYPE_JOB_TEMP 4 -#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban. - -#define BANTYPE_ADMIN_PERMA 7 -#define BANTYPE_ADMIN_TEMP 8 -#define BANTYPE_ANY_JOB 9 //used to remove jobbans - -//Please don't edit these values without speaking to Errorage first ~Carn -//Admin Permissions -#define R_BUILDMODE 1 -#define R_ADMIN 2 -#define R_BAN 4 -#define R_FUN 8 -#define R_SERVER 16 -#define R_DEBUG 32 -#define R_POSSESS 64 -#define R_PERMISSIONS 128 -#define R_STEALTH 256 -#define R_POLL 512 -#define R_VAREDIT 1024 -#define R_SOUNDS 2048 -#define R_SPAWN 4096 - -#if DM_VERSION > 512 -#error Remove the flag below , its been long enough -#endif -//legacy , remove post 512, it was replaced by R_POLL -#define R_REJUVINATE 2 - -#define R_MAXPERMISSION 4096 //This holds the maximum value for a permission. It is used in iteration, so keep it updated. - -#define ADMIN_QUE(user) "(?)" -#define ADMIN_FLW(user) "(FLW)" -#define ADMIN_PP(user) "(PP)" -#define ADMIN_VV(atom) "(VV)" -#define ADMIN_SM(user) "(SM)" -#define ADMIN_TP(user) "(TP)" -#define ADMIN_KICK(user) "(KICK)" -#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" -#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" -#define ADMIN_SC(user) "(SC)" -#define ADMIN_SMITE(user) "(SMITE)" -#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" -#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" -#define ADMIN_SET_SD_CODE "(SETCODE)" -#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" -#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" -#define ADMIN_JMP(src) "(JMP)" -#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" -#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" -#define ADMIN_INDIVIDUALLOG(user) "(LOGS)" - -#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt" -#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage" -#define ADMIN_PUNISHMENT_GIB "Gib" -#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device" - -#define AHELP_ACTIVE 1 -#define AHELP_CLOSED 2 -#define AHELP_RESOLVED 3 -======= +//A set of constants used to determine which type of mute an admin wishes to apply: +//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) +//Therefore there needs to be a gap between the flags_1 for the automute flags_1 +#define MUTE_IC 1 +#define MUTE_OOC 2 +#define MUTE_PRAY 4 +#define MUTE_ADMINHELP 8 +#define MUTE_DEADCHAT 16 +#define MUTE_ALL 31 + +//Some constants for DB_Ban +#define BANTYPE_PERMA 1 +#define BANTYPE_TEMP 2 +#define BANTYPE_JOB_PERMA 3 +#define BANTYPE_JOB_TEMP 4 +#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban. + +#define BANTYPE_ADMIN_PERMA 7 +#define BANTYPE_ADMIN_TEMP 8 +#define BANTYPE_ANY_JOB 9 //used to remove jobbans + +//Please don't edit these values without speaking to Errorage first ~Carn +//Admin Permissions +#define R_BUILDMODE 1 +#define R_ADMIN 2 +#define R_BAN 4 +#define R_FUN 8 +#define R_SERVER 16 +#define R_DEBUG 32 +#define R_POSSESS 64 +#define R_PERMISSIONS 128 +#define R_STEALTH 256 +#define R_POLL 512 +#define R_VAREDIT 1024 +#define R_SOUNDS 2048 +#define R_SPAWN 4096 + +#if DM_VERSION > 512 +#error Remove the flag below , its been long enough +#endif +//legacy , remove post 512, it was replaced by R_POLL +#define R_REJUVINATE 2 + +#define R_MAXPERMISSION 4096 //This holds the maximum value for a permission. It is used in iteration, so keep it updated. + +#define ADMIN_QUE(user) "(?)" +#define ADMIN_FLW(user) "(FLW)" +#define ADMIN_PP(user) "(PP)" +#define ADMIN_VV(atom) "(VV)" +#define ADMIN_SM(user) "(SM)" +#define ADMIN_TP(user) "(TP)" +#define ADMIN_KICK(user) "(KICK)" +#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" +#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" +#define ADMIN_SC(user) "(SC)" +#define ADMIN_SMITE(user) "(SMITE)" +#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" +#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" +#define ADMIN_SET_SD_CODE "(SETCODE)" +#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" +#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" +#define ADMIN_JMP(src) "(JMP)" +#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" +#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" +#define ADMIN_INDIVIDUALLOG(user) "(LOGS)" + +#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt" +#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage" +#define ADMIN_PUNISHMENT_GIB "Gib" +#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device" + +#define AHELP_ACTIVE 1 +#define AHELP_CLOSED 2 +#define AHELP_RESOLVED 3 //A set of constants used to determine which type of mute an admin wishes to apply: //Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) //Therefore there needs to be a gap between the flags for the automute flags @@ -148,4 +146,3 @@ #define AHELP_ACTIVE 1 #define AHELP_CLOSED 2 #define AHELP_RESOLVED 3 ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) From 7b157a9a6ae0417cd46bbac29b462d892b71c2fe Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 14:23:15 -0500 Subject: [PATCH 064/102] Update datumvars.dm --- code/datums/datumvars.dm | 2282 +++++++++++++++++++------------------- 1 file changed, 1138 insertions(+), 1144 deletions(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 44661316ab..2fcb496526 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -1,69 +1,67 @@ -/datum - var/var_edited = FALSE //Warrenty void if seal is broken - var/fingerprintslast = null - -/datum/proc/can_vv_get(var_name) - return TRUE - -/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited - switch(var_name) - if ("vars") - return FALSE - if ("var_edited") - return FALSE - var_edited = TRUE - vars[var_name] = var_value - -/datum/proc/vv_get_var(var_name) - switch(var_name) - if ("vars") - return debug_variable(var_name, list(), 0, src) - return debug_variable(var_name, vars[var_name], 0, src) - -//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down +/datum + var/var_edited = FALSE //Warrenty void if seal is broken + var/fingerprintslast = null + +/datum/proc/can_vv_get(var_name) + return TRUE + +/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited + switch(var_name) + if ("vars") + return FALSE + if ("var_edited") + return FALSE + var_edited = TRUE + vars[var_name] = var_value + +/datum/proc/vv_get_var(var_name) + switch(var_name) + if ("vars") + return debug_variable(var_name, list(), 0, src) + return debug_variable(var_name, vars[var_name], 0, src) + +//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down //add separaters by doing . += "---" -<<<<<<< HEAD -/datum/proc/vv_get_dropdown() - . = list() - . += "---" - .["Call Proc"] = "?_src_=vars;proc_call=\ref[src]" - .["Mark Object"] = "?_src_=vars;mark_object=\ref[src]" - .["Delete"] = "?_src_=vars;delete=\ref[src]" - - -/datum/proc/on_reagent_change() - return - - -/client/proc/debug_variables(datum/D in world) - set category = "Debug" - set name = "View Variables" - //set src in world - var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. - - if(!usr.client || !usr.client.holder) - to_chat(usr, "You need to be an administrator to access this.") - return - - if(!D) - return - - var/islist = islist(D) - if (!islist && !istype(D)) - return - - var/title = "" - var/refid = "\ref[D]" - var/icon/sprite - var/hash - - var/type = /list - if (!islist) - type = D.type - - - -======= +/datum/proc/vv_get_dropdown() + . = list() + . += "---" + .["Call Proc"] = "?_src_=vars;proc_call=\ref[src]" + .["Mark Object"] = "?_src_=vars;mark_object=\ref[src]" + .["Delete"] = "?_src_=vars;delete=\ref[src]" + + +/datum/proc/on_reagent_change() + return + + +/client/proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + //set src in world + var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. + + if(!usr.client || !usr.client.holder) + to_chat(usr, "You need to be an administrator to access this.") + return + + if(!D) + return + + var/islist = islist(D) + if (!islist && !istype(D)) + return + + var/title = "" + var/refid = "\ref[D]" + var/icon/sprite + var/hash + + var/type = /list + if (!islist) + type = D.type + + + /datum/proc/vv_get_dropdown() . = list() . += "---" @@ -107,430 +105,428 @@ >>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) if(istype(D, /atom)) - var/atom/AT = D - if(AT.icon && AT.icon_state) - sprite = new /icon(AT.icon, AT.icon_state) - hash = md5(AT.icon) - hash = md5(hash + AT.icon_state) - usr << browse_rsc(sprite, "vv[hash].png") - - title = "[D] (\ref[D]) = [type]" - - var/sprite_text - if(sprite) - sprite_text = "" - var/list/atomsnowflake = list() - + var/atom/AT = D + if(AT.icon && AT.icon_state) + sprite = new /icon(AT.icon, AT.icon_state) + hash = md5(AT.icon) + hash = md5(hash + AT.icon_state) + usr << browse_rsc(sprite, "vv[hash].png") + + title = "[D] (\ref[D]) = [type]" + + var/sprite_text + if(sprite) + sprite_text = "" + var/list/atomsnowflake = list() + if(istype(D, /atom)) -<<<<<<< HEAD - var/atom/A = D - if(isliving(A)) - atomsnowflake += "[D]" - if(A.dir) - atomsnowflake += "
    << [dir2text(A.dir)] >>" - var/mob/living/M = A - atomsnowflake += {" -
    [M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"] -
    - BRUTE:[M.getBruteLoss()] - FIRE:[M.getFireLoss()] - TOXIN:[M.getToxLoss()] - OXY:[M.getOxyLoss()] - CLONE:[M.getCloneLoss()] - BRAIN:[M.getBrainLoss()] - STAMINA:[M.getStaminaLoss()] - - "} - else - atomsnowflake += "[D]" - if(A.dir) - atomsnowflake += "
    << [dir2text(A.dir)] >>" - else - atomsnowflake += "[D]" - - var/formatted_type = "[type]" - if(length(formatted_type) > 25) - var/middle_point = length(formatted_type) / 2 - var/splitpoint = findtext(formatted_type,"/",middle_point) - if(splitpoint) - formatted_type = "[copytext(formatted_type,1,splitpoint)]
    [copytext(formatted_type,splitpoint)]" - else - formatted_type = "Type too long" //No suitable splitpoint (/) found. - - var/marked - if(holder.marked_datum && holder.marked_datum == D) - marked = "
    Marked Object" - var/varedited_line = "" - if(!islist && D.var_edited) - varedited_line = "
    Var Edited" - - var/list/dropdownoptions = list() - if (islist) - dropdownoptions = list( - "---", - "Add Item" = "?_src_=vars;listadd=[refid]", - "Remove Nulls" = "?_src_=vars;listnulls=[refid]", - "Remove Dupes" = "?_src_=vars;listdupes=[refid]", - "Set len" = "?_src_=vars;listlen=[refid]", - "Shuffle" = "?_src_=vars;listshuffle=[refid]" - ) - else - dropdownoptions = D.vv_get_dropdown() - var/list/dropdownoptions_html = list() - - for (var/name in dropdownoptions) - var/link = dropdownoptions[name] - if (link) - dropdownoptions_html += "" - else - dropdownoptions_html += "" - - var/list/names = list() - if (!islist) - for (var/V in D.vars) - names += V - sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. - - var/list/variable_html = list() - if (islist) - var/list/L = D - for (var/i in 1 to L.len) - var/key = L[i] - var/value - if (IS_NORMAL_LIST(L) && !isnum(key)) - value = L[key] - variable_html += debug_variable(i, value, 0, D) - else - - names = sortList(names) - for (var/V in names) - if(D.can_vv_get(V)) - variable_html += D.vv_get_var(V) - - var/html = {" - - - [title] - - - - -
    - - - - - -
    - - - - -
    - [sprite_text] -
    - [atomsnowflake.Join()] -
    -
    -
    - [formatted_type] - [marked] - [varedited_line] -
    -
    -
    - Refresh -
    - -
    -
    -
    -
    -
    - - E - Edit, tries to determine the variable type by itself.
    - C - Change, asks you for the var type first.
    - M - Mass modify: changes this variable for all objects of this type.
    -
    -
    - - - - - -
    -
    - Search: -
    -
    - -
    -
    -
      - [variable_html.Join()] -
    - - - -"} - - usr << browse(html, "window=variables[refid];size=475x650") - - -#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) -/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) - var/header - if(DA) - if (islist(DA)) - var/index = name - if (value) - name = DA[name] //name is really the index until this line - else - value = DA[name] - header = "
  • (E) (C) (-) " - else - header = "
  • (E) (C) (M) " - else - header = "
  • " - - var/item - if (isnull(value)) - item = "[VV_HTML_ENCODE(name)] = null" - - else if (istext(value)) - item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" - - else if (isicon(value)) - #ifdef VARSICON - var/icon/I = new/icon(value) - var/rnd = rand(1,10000) - var/rname = "tmp\ref[I][rnd].png" - usr << browse_rsc(I, rname) - item = "[VV_HTML_ENCODE(name)] = ([value]) " - #else - item = "[VV_HTML_ENCODE(name)] = /icon ([value])" - #endif - -/* else if (istype(value, /image)) - #ifdef VARSICON - var/rnd = rand(1, 10000) - var/image/I = value - - src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") - html += "[name] = " - #else - html += "[name] = /image ([value])" - #endif -*/ - else if (isfile(value)) - item = "[VV_HTML_ENCODE(name)] = '[value]'" - - //else if (istype(value, /client)) - // var/client/C = value - // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" - - else if (istype(value, /datum)) - var/datum/D = value - if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. - item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" - else - item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" - - else if (islist(value)) - var/list/L = value - var/list/items = list() - - if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) - for (var/i in 1 to L.len) - var/key = L[i] - var/val - if (IS_NORMAL_LIST(L) && !isnum(key)) - val = L[key] - if (!val) - val = key - key = i - - items += debug_variable(key, val, level + 1, sanitize = sanitize) - - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " - else - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" - - else - item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" - - return "[header][item]
  • " - -#undef VV_HTML_ENCODE - -/client/proc/view_var_Topic(href, href_list, hsrc) - if( (usr.client != src) || !src.holder ) - return - if(href_list["Vars"]) - debug_variables(locate(href_list["Vars"])) - - else if(href_list["datumrefresh"]) - var/datum/DAT = locate(href_list["datumrefresh"]) - if(!DAT) //can't be an istype() because /client etc aren't datums - return - src.debug_variables(DAT) - - else if(href_list["mob_player_panel"]) - if(!check_rights(0)) - return - -======= + var/atom/A = D + if(isliving(A)) + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
    << [dir2text(A.dir)] >>" + var/mob/living/M = A + atomsnowflake += {" +
    [M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"] +
    + BRUTE:[M.getBruteLoss()] + FIRE:[M.getFireLoss()] + TOXIN:[M.getToxLoss()] + OXY:[M.getOxyLoss()] + CLONE:[M.getCloneLoss()] + BRAIN:[M.getBrainLoss()] + STAMINA:[M.getStaminaLoss()] + + "} + else + atomsnowflake += "[D]" + if(A.dir) + atomsnowflake += "
    << [dir2text(A.dir)] >>" + else + atomsnowflake += "[D]" + + var/formatted_type = "[type]" + if(length(formatted_type) > 25) + var/middle_point = length(formatted_type) / 2 + var/splitpoint = findtext(formatted_type,"/",middle_point) + if(splitpoint) + formatted_type = "[copytext(formatted_type,1,splitpoint)]
    [copytext(formatted_type,splitpoint)]" + else + formatted_type = "Type too long" //No suitable splitpoint (/) found. + + var/marked + if(holder.marked_datum && holder.marked_datum == D) + marked = "
    Marked Object" + var/varedited_line = "" + if(!islist && D.var_edited) + varedited_line = "
    Var Edited" + + var/list/dropdownoptions = list() + if (islist) + dropdownoptions = list( + "---", + "Add Item" = "?_src_=vars;listadd=[refid]", + "Remove Nulls" = "?_src_=vars;listnulls=[refid]", + "Remove Dupes" = "?_src_=vars;listdupes=[refid]", + "Set len" = "?_src_=vars;listlen=[refid]", + "Shuffle" = "?_src_=vars;listshuffle=[refid]" + ) + else + dropdownoptions = D.vv_get_dropdown() + var/list/dropdownoptions_html = list() + + for (var/name in dropdownoptions) + var/link = dropdownoptions[name] + if (link) + dropdownoptions_html += "" + else + dropdownoptions_html += "" + + var/list/names = list() + if (!islist) + for (var/V in D.vars) + names += V + sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. + + var/list/variable_html = list() + if (islist) + var/list/L = D + for (var/i in 1 to L.len) + var/key = L[i] + var/value + if (IS_NORMAL_LIST(L) && !isnum(key)) + value = L[key] + variable_html += debug_variable(i, value, 0, D) + else + + names = sortList(names) + for (var/V in names) + if(D.can_vv_get(V)) + variable_html += D.vv_get_var(V) + + var/html = {" + + + [title] + + + + +
    + + + + + +
    + + + + +
    + [sprite_text] +
    + [atomsnowflake.Join()] +
    +
    +
    + [formatted_type] + [marked] + [varedited_line] +
    +
    +
    + Refresh +
    + +
    +
    +
    +
    +
    + + E - Edit, tries to determine the variable type by itself.
    + C - Change, asks you for the var type first.
    + M - Mass modify: changes this variable for all objects of this type.
    +
    +
    + + + + + +
    +
    + Search: +
    +
    + +
    +
    +
      + [variable_html.Join()] +
    + + + +"} + + usr << browse(html, "window=variables[refid];size=475x650") + + +#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) +/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) + var/header + if(DA) + if (islist(DA)) + var/index = name + if (value) + name = DA[name] //name is really the index until this line + else + value = DA[name] + header = "
  • (E) (C) (-) " + else + header = "
  • (E) (C) (M) " + else + header = "
  • " + + var/item + if (isnull(value)) + item = "[VV_HTML_ENCODE(name)] = null" + + else if (istext(value)) + item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" + + else if (isicon(value)) + #ifdef VARSICON + var/icon/I = new/icon(value) + var/rnd = rand(1,10000) + var/rname = "tmp\ref[I][rnd].png" + usr << browse_rsc(I, rname) + item = "[VV_HTML_ENCODE(name)] = ([value]) " + #else + item = "[VV_HTML_ENCODE(name)] = /icon ([value])" + #endif + +/* else if (istype(value, /image)) + #ifdef VARSICON + var/rnd = rand(1, 10000) + var/image/I = value + + src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") + html += "[name] = " + #else + html += "[name] = /image ([value])" + #endif +*/ + else if (isfile(value)) + item = "[VV_HTML_ENCODE(name)] = '[value]'" + + //else if (istype(value, /client)) + // var/client/C = value + // item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" + + else if (istype(value, /datum)) + var/datum/D = value + if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D] [D.type]" + else + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" + + else if (islist(value)) + var/list/L = value + var/list/items = list() + + if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) + for (var/i in 1 to L.len) + var/key = L[i] + var/val + if (IS_NORMAL_LIST(L) && !isnum(key)) + val = L[key] + if (!val) + val = key + key = i + + items += debug_variable(key, val, level + 1, sanitize = sanitize) + + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " + else + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + + else + item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" + + return "[header][item]
  • " + +#undef VV_HTML_ENCODE + +/client/proc/view_var_Topic(href, href_list, hsrc) + if( (usr.client != src) || !src.holder ) + return + if(href_list["Vars"]) + debug_variables(locate(href_list["Vars"])) + + else if(href_list["datumrefresh"]) + var/datum/DAT = locate(href_list["datumrefresh"]) + if(!DAT) //can't be an istype() because /client etc aren't datums + return + src.debug_variables(DAT) + + else if(href_list["mob_player_panel"]) + if(!check_rights(0)) + return + var/atom/A = D if(isliving(A)) atomsnowflake += "[D]" @@ -940,79 +936,77 @@ >>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) var/mob/M = locate(href_list["mob_player_panel"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.holder.show_player_panel(M) - href_list["datumrefresh"] = href_list["mob_player_panel"] - - else if(href_list["godmode"]) - if(!check_rights(R_ADMIN)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.holder.show_player_panel(M) + href_list["datumrefresh"] = href_list["mob_player_panel"] + + else if(href_list["godmode"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["godmode"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.cmd_admin_godmode(M) - href_list["datumrefresh"] = href_list["godmode"] - - else if(href_list["mark_object"]) - if(!check_rights(0)) - return - - var/datum/D = locate(href_list["mark_object"]) - if(!istype(D)) - to_chat(usr, "This can only be done to instances of type /datum") - return - - src.holder.marked_datum = D - href_list["datumrefresh"] = href_list["mark_object"] - - else if(href_list["proc_call"]) - if(!check_rights(0)) - return - - var/T = locate(href_list["proc_call"]) - - if(T) - callproc_datum(T) - - else if(href_list["delete"]) - if(!check_rights(R_DEBUG, 0)) - return - - var/datum/D = locate(href_list["delete"]) - if(!D) - to_chat(usr, "Unable to locate item!") - admin_delete(D) - href_list["datumrefresh"] = href_list["delete"] - - else if(href_list["regenerateicons"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.cmd_admin_godmode(M) + href_list["datumrefresh"] = href_list["godmode"] + + else if(href_list["mark_object"]) + if(!check_rights(0)) + return + + var/datum/D = locate(href_list["mark_object"]) + if(!istype(D)) + to_chat(usr, "This can only be done to instances of type /datum") + return + + src.holder.marked_datum = D + href_list["datumrefresh"] = href_list["mark_object"] + + else if(href_list["proc_call"]) + if(!check_rights(0)) + return + + var/T = locate(href_list["proc_call"]) + + if(T) + callproc_datum(T) + + else if(href_list["delete"]) + if(!check_rights(R_DEBUG, 0)) + return + + var/datum/D = locate(href_list["delete"]) + if(!D) + to_chat(usr, "Unable to locate item!") + admin_delete(D) + href_list["datumrefresh"] = href_list["delete"] + + else if(href_list["regenerateicons"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["regenerateicons"]) in GLOB.mob_list -<<<<<<< HEAD - if(!ismob(M)) - to_chat(usr, "This can only be done to instances of type /mob") - return - M.regenerate_icons() - -//Needs +VAREDIT past this point - - else if(check_rights(R_VAREDIT)) - - - //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). - - if(href_list["rename"]) - if(!check_rights(0)) - return - -======= + if(!ismob(M)) + to_chat(usr, "This can only be done to instances of type /mob") + return + M.regenerate_icons() + +//Needs +VAREDIT past this point + + else if(check_rights(R_VAREDIT)) + + + //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). + + if(href_list["rename"]) + if(!check_rights(0)) + return + if(!ismob(M)) to_chat(usr, "This can only be done to instances of type /mob") return @@ -1051,377 +1045,377 @@ >>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) var/mob/M = locate(href_list["rename"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN) - if( !new_name || !M ) - return - - message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].") - M.fully_replace_character_name(M.real_name,new_name) - href_list["datumrefresh"] = href_list["rename"] - - else if(href_list["varnameedit"] && href_list["datumedit"]) - if(!check_rights(0)) - return - - var/D = locate(href_list["datumedit"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN) + if( !new_name || !M ) + return + + message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].") + M.fully_replace_character_name(M.real_name,new_name) + href_list["datumrefresh"] = href_list["rename"] + + else if(href_list["varnameedit"] && href_list["datumedit"]) + if(!check_rights(0)) + return + + var/D = locate(href_list["datumedit"]) if(!istype(D, /datum)) - to_chat(usr, "This can only be used on datums") - return - - modify_variables(D, href_list["varnameedit"], 1) - - else if(href_list["varnamechange"] && href_list["datumchange"]) - if(!check_rights(0)) - return - - var/D = locate(href_list["datumchange"]) + to_chat(usr, "This can only be used on datums") + return + + modify_variables(D, href_list["varnameedit"], 1) + + else if(href_list["varnamechange"] && href_list["datumchange"]) + if(!check_rights(0)) + return + + var/D = locate(href_list["datumchange"]) if(!istype(D, /datum)) - to_chat(usr, "This can only be used on datums") - return - - modify_variables(D, href_list["varnamechange"], 0) - - else if(href_list["varnamemass"] && href_list["datummass"]) - if(!check_rights(0)) - return - - var/datum/D = locate(href_list["datummass"]) - if(!istype(D)) - to_chat(usr, "This can only be used on instances of type /datum") - return - - cmd_mass_modify_object_variables(D, href_list["varnamemass"]) - - else if(href_list["listedit"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listedit"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list(L, null, "list", "contents", index, autodetect_class = TRUE) - - else if(href_list["listchange"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listchange"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list(L, null, "list", "contents", index, autodetect_class = FALSE) - - else if(href_list["listremove"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listremove"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - var/variable = L[index] - var/prompt = alert("Do you want to remove item number [index] from list?", "Confirm", "Yes", "No") - if (prompt != "Yes") - return - L.Cut(index, index+1) - log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]") - log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]") - message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]") - - else if(href_list["listadd"]) - var/list/L = locate(href_list["listadd"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list_add(L, null, "list", "contents") - - else if(href_list["listdupes"]) - var/list/L = locate(href_list["listdupes"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - uniqueList_inplace(L) - log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES") - log_admin("[key_name(src)] modified list's contents: CLEAR DUPES") - message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES") - - else if(href_list["listnulls"]) - var/list/L = locate(href_list["listnulls"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - listclearnulls(L) - log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS") - log_admin("[key_name(src)] modified list's contents: CLEAR NULLS") - message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS") - - else if(href_list["listlen"]) - var/list/L = locate(href_list["listlen"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - var/value = vv_get_value(VV_NUM) - if (value["class"] != VV_NUM) - return - - L.len = value["value"] - log_world("### ListVarEdit by [src]: /list len: [L.len]") - log_admin("[key_name(src)] modified list's len: [L.len]") - message_admins("[key_name_admin(src)] modified list's len: [L.len]") - - else if(href_list["listshuffle"]) - var/list/L = locate(href_list["listshuffle"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - shuffle_inplace(L) - log_world("### ListVarEdit by [src]: /list contents: SHUFFLE") - log_admin("[key_name(src)] modified list's contents: SHUFFLE") - message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE") - - else if(href_list["give_spell"]) - if(!check_rights(0)) - return - + to_chat(usr, "This can only be used on datums") + return + + modify_variables(D, href_list["varnamechange"], 0) + + else if(href_list["varnamemass"] && href_list["datummass"]) + if(!check_rights(0)) + return + + var/datum/D = locate(href_list["datummass"]) + if(!istype(D)) + to_chat(usr, "This can only be used on instances of type /datum") + return + + cmd_mass_modify_object_variables(D, href_list["varnamemass"]) + + else if(href_list["listedit"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if (!index) + return + + var/list/L = locate(href_list["listedit"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + mod_list(L, null, "list", "contents", index, autodetect_class = TRUE) + + else if(href_list["listchange"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if (!index) + return + + var/list/L = locate(href_list["listchange"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + mod_list(L, null, "list", "contents", index, autodetect_class = FALSE) + + else if(href_list["listremove"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if (!index) + return + + var/list/L = locate(href_list["listremove"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + var/variable = L[index] + var/prompt = alert("Do you want to remove item number [index] from list?", "Confirm", "Yes", "No") + if (prompt != "Yes") + return + L.Cut(index, index+1) + log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]") + log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]") + message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]") + + else if(href_list["listadd"]) + var/list/L = locate(href_list["listadd"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + mod_list_add(L, null, "list", "contents") + + else if(href_list["listdupes"]) + var/list/L = locate(href_list["listdupes"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + uniqueList_inplace(L) + log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES") + log_admin("[key_name(src)] modified list's contents: CLEAR DUPES") + message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES") + + else if(href_list["listnulls"]) + var/list/L = locate(href_list["listnulls"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + listclearnulls(L) + log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS") + log_admin("[key_name(src)] modified list's contents: CLEAR NULLS") + message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS") + + else if(href_list["listlen"]) + var/list/L = locate(href_list["listlen"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + var/value = vv_get_value(VV_NUM) + if (value["class"] != VV_NUM) + return + + L.len = value["value"] + log_world("### ListVarEdit by [src]: /list len: [L.len]") + log_admin("[key_name(src)] modified list's len: [L.len]") + message_admins("[key_name_admin(src)] modified list's len: [L.len]") + + else if(href_list["listshuffle"]) + var/list/L = locate(href_list["listshuffle"]) + if (!istype(L)) + to_chat(usr, "This can only be used on instances of type /list") + return + + shuffle_inplace(L) + log_world("### ListVarEdit by [src]: /list contents: SHUFFLE") + log_admin("[key_name(src)] modified list's contents: SHUFFLE") + message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE") + + else if(href_list["give_spell"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["give_spell"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_spell(M) - href_list["datumrefresh"] = href_list["give_spell"] - - else if(href_list["remove_spell"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_spell(M) + href_list["datumrefresh"] = href_list["give_spell"] + + else if(href_list["remove_spell"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["remove_spell"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - remove_spell(M) - href_list["datumrefresh"] = href_list["remove_spell"] - - else if(href_list["give_disease"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + remove_spell(M) + href_list["datumrefresh"] = href_list["remove_spell"] + + else if(href_list["give_disease"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["give_disease"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_disease(M) - href_list["datumrefresh"] = href_list["give_spell"] - - else if(href_list["gib"]) - if(!check_rights(R_FUN)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_disease(M) + href_list["datumrefresh"] = href_list["give_spell"] + + else if(href_list["gib"]) + if(!check_rights(R_FUN)) + return + var/mob/M = locate(href_list["gib"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.cmd_admin_gib(M) - - else if(href_list["build_mode"]) - if(!check_rights(R_BUILDMODE)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.cmd_admin_gib(M) + + else if(href_list["build_mode"]) + if(!check_rights(R_BUILDMODE)) + return + var/mob/M = locate(href_list["build_mode"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - togglebuildmode(M) - href_list["datumrefresh"] = href_list["build_mode"] - - else if(href_list["drop_everything"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + togglebuildmode(M) + href_list["datumrefresh"] = href_list["build_mode"] + + else if(href_list["drop_everything"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["drop_everything"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - if(usr.client) - usr.client.cmd_admin_drop_everything(M) - - else if(href_list["direct_control"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(usr.client) + usr.client.cmd_admin_drop_everything(M) + + else if(href_list["direct_control"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["direct_control"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - if(usr.client) - usr.client.cmd_assume_direct_control(M) - - else if(href_list["offer_control"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(usr.client) + usr.client.cmd_assume_direct_control(M) + + else if(href_list["offer_control"]) + if(!check_rights(0)) + return + var/mob/M = locate(href_list["offer_control"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - offer_control(M) - - else if(href_list["delall"]) - if(!check_rights(R_DEBUG|R_SERVER)) - return - - var/obj/O = locate(href_list["delall"]) - if(!isobj(O)) - to_chat(usr, "This can only be used on instances of type /obj") - return - - var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") - if(action_type == "Cancel" || !action_type) - return - - if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") - return - - if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") - return - - var/O_type = O.type - switch(action_type) - if("Strict type") - var/i = 0 - for(var/obj/Obj in world) - if(Obj.type == O_type) - i++ - qdel(Obj) - CHECK_TICK - if(!i) - to_chat(usr, "No objects of this type exist") - return - log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") - message_admins("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") - if("Type and subtypes") - var/i = 0 - for(var/obj/Obj in world) - if(istype(Obj,O_type)) - i++ - qdel(Obj) - CHECK_TICK - if(!i) - to_chat(usr, "No objects of this type exist") - return - log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") - message_admins("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") - - else if(href_list["addreagent"]) - if(!check_rights(0)) - return - - var/atom/A = locate(href_list["addreagent"]) - - if(!A.reagents) - var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num - if(amount) - A.create_reagents(amount) - - if(A.reagents) - var/chosen_id - var/list/reagent_options = sortList(GLOB.chemical_reagents_list) - switch(alert(usr, "Choose a method.", "Add Reagents", "Enter ID", "Choose ID")) - if("Enter ID") - var/valid_id - while(!valid_id) - chosen_id = stripped_input(usr, "Enter the ID of the reagent you want to add.") - if(!chosen_id) //Get me out of here! - break - for(var/ID in reagent_options) - if(ID == chosen_id) - valid_id = 1 - if(!valid_id) - to_chat(usr, "A reagent with that ID doesn't exist!") - if("Choose ID") - chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in reagent_options - if(chosen_id) - var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num - if(amount) - A.reagents.add_reagent(chosen_id, amount) - log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") - message_admins("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") - - href_list["datumrefresh"] = href_list["addreagent"] - - else if(href_list["explode"]) - if(!check_rights(R_FUN)) - return - - var/atom/A = locate(href_list["explode"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) - to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") - return - - src.cmd_admin_explosion(A) - href_list["datumrefresh"] = href_list["explode"] - - else if(href_list["emp"]) - if(!check_rights(R_FUN)) - return - - var/atom/A = locate(href_list["emp"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) - to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") - return - - src.cmd_admin_emp(A) - href_list["datumrefresh"] = href_list["emp"] - - else if(href_list["rotatedatum"]) - if(!check_rights(0)) - return - - var/atom/A = locate(href_list["rotatedatum"]) - if(!istype(A)) - to_chat(usr, "This can only be done to instances of type /atom") - return - - switch(href_list["rotatedir"]) - if("right") - A.setDir(turn(A.dir, -45)) - if("left") - A.setDir(turn(A.dir, 45)) - href_list["datumrefresh"] = href_list["rotatedatum"] - - else if(href_list["editorgans"]) - if(!check_rights(0)) - return - + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + offer_control(M) + + else if(href_list["delall"]) + if(!check_rights(R_DEBUG|R_SERVER)) + return + + var/obj/O = locate(href_list["delall"]) + if(!isobj(O)) + to_chat(usr, "This can only be used on instances of type /obj") + return + + var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") + if(action_type == "Cancel" || !action_type) + return + + if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") + return + + if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") + return + + var/O_type = O.type + switch(action_type) + if("Strict type") + var/i = 0 + for(var/obj/Obj in world) + if(Obj.type == O_type) + i++ + qdel(Obj) + CHECK_TICK + if(!i) + to_chat(usr, "No objects of this type exist") + return + log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") + message_admins("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ") + if("Type and subtypes") + var/i = 0 + for(var/obj/Obj in world) + if(istype(Obj,O_type)) + i++ + qdel(Obj) + CHECK_TICK + if(!i) + to_chat(usr, "No objects of this type exist") + return + log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") + message_admins("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ") + + else if(href_list["addreagent"]) + if(!check_rights(0)) + return + + var/atom/A = locate(href_list["addreagent"]) + + if(!A.reagents) + var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num + if(amount) + A.create_reagents(amount) + + if(A.reagents) + var/chosen_id + var/list/reagent_options = sortList(GLOB.chemical_reagents_list) + switch(alert(usr, "Choose a method.", "Add Reagents", "Enter ID", "Choose ID")) + if("Enter ID") + var/valid_id + while(!valid_id) + chosen_id = stripped_input(usr, "Enter the ID of the reagent you want to add.") + if(!chosen_id) //Get me out of here! + break + for(var/ID in reagent_options) + if(ID == chosen_id) + valid_id = 1 + if(!valid_id) + to_chat(usr, "A reagent with that ID doesn't exist!") + if("Choose ID") + chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in reagent_options + if(chosen_id) + var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num + if(amount) + A.reagents.add_reagent(chosen_id, amount) + log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") + message_admins("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") + + href_list["datumrefresh"] = href_list["addreagent"] + + else if(href_list["explode"]) + if(!check_rights(R_FUN)) + return + + var/atom/A = locate(href_list["explode"]) + if(!isobj(A) && !ismob(A) && !isturf(A)) + to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") + return + + src.cmd_admin_explosion(A) + href_list["datumrefresh"] = href_list["explode"] + + else if(href_list["emp"]) + if(!check_rights(R_FUN)) + return + + var/atom/A = locate(href_list["emp"]) + if(!isobj(A) && !ismob(A) && !isturf(A)) + to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") + return + + src.cmd_admin_emp(A) + href_list["datumrefresh"] = href_list["emp"] + + else if(href_list["rotatedatum"]) + if(!check_rights(0)) + return + + var/atom/A = locate(href_list["rotatedatum"]) + if(!istype(A)) + to_chat(usr, "This can only be done to instances of type /atom") + return + + switch(href_list["rotatedir"]) + if("right") + A.setDir(turn(A.dir, -45)) + if("left") + A.setDir(turn(A.dir, 45)) + href_list["datumrefresh"] = href_list["rotatedatum"] + + else if(href_list["editorgans"]) + if(!check_rights(0)) + return + var/mob/living/carbon/C = locate(href_list["editorgans"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - manipulate_organs(C) - href_list["datumrefresh"] = href_list["editorgans"] - + if(!istype(C)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + manipulate_organs(C) + href_list["datumrefresh"] = href_list["editorgans"] + else if(href_list["hallucinate"]) if(!check_rights(0)) return @@ -1442,238 +1436,238 @@ if(result) new result(C, TRUE) - else if(href_list["makehuman"]) - if(!check_rights(R_SPAWN)) - return - + else if(href_list["makehuman"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list - if(!istype(Mo)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!Mo) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("humanone"=href_list["makehuman"])) - - else if(href_list["makemonkey"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(Mo)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!Mo) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("humanone"=href_list["makehuman"])) + + else if(href_list["makemonkey"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makemonkey"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) - - else if(href_list["makerobot"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) + + else if(href_list["makerobot"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makerobot"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makerobot"=href_list["makerobot"])) - - else if(href_list["makealien"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makerobot"=href_list["makerobot"])) + + else if(href_list["makealien"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makealien"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makealien"=href_list["makealien"])) - - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makealien"=href_list["makealien"])) + + else if(href_list["makeslime"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["makeslime"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makeslime"=href_list["makeslime"])) - - else if(href_list["makeai"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makeslime"=href_list["makeslime"])) + + else if(href_list["makeai"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/H = locate(href_list["makeai"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makeai"=href_list["makeai"])) - - else if(href_list["setspecies"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") + return + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makeai"=href_list["makeai"])) + + else if(href_list["setspecies"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["setspecies"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list - - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/newtype = GLOB.species_list[result] - admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [H] to [result]") - H.set_species(newtype) - - else if(href_list["editbodypart"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(result) + var/newtype = GLOB.species_list[result] + admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [H] to [result]") + H.set_species(newtype) + + else if(href_list["editbodypart"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/C = locate(href_list["editbodypart"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") - if(!edit_action) - return - var/list/limb_list = list("head", "l_arm", "r_arm", "l_leg", "r_leg") - if(edit_action == "augment") - limb_list += "chest" - var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list - - if(!C) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/obj/item/bodypart/BP = C.get_bodypart(result) - switch(edit_action) - if("remove") - if(BP) - BP.drop_limb() - else - to_chat(usr, "[C] doesn't have such bodypart.") - if("add") - if(BP) - to_chat(usr, "[C] already has such bodypart.") - else - if(!C.regenerate_limb(result)) - to_chat(usr, "[C] cannot have such bodypart.") - if("augment") - if(ishuman(C)) - if(BP) - BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) - else - to_chat(usr, "[C] doesn't have such bodypart.") - else - to_chat(usr, "Only humans can be augmented.") - admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [C]") - - - else if(href_list["purrbation"]) - if(!check_rights(R_SPAWN)) - return - + if(!istype(C)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") + if(!edit_action) + return + var/list/limb_list = list("head", "l_arm", "r_arm", "l_leg", "r_leg") + if(edit_action == "augment") + limb_list += "chest" + var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list + + if(!C) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(result) + var/obj/item/bodypart/BP = C.get_bodypart(result) + switch(edit_action) + if("remove") + if(BP) + BP.drop_limb() + else + to_chat(usr, "[C] doesn't have such bodypart.") + if("add") + if(BP) + to_chat(usr, "[C] already has such bodypart.") + else + if(!C.regenerate_limb(result)) + to_chat(usr, "[C] cannot have such bodypart.") + if("augment") + if(ishuman(C)) + if(BP) + BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) + else + to_chat(usr, "[C] doesn't have such bodypart.") + else + to_chat(usr, "Only humans can be augmented.") + admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [C]") + + + else if(href_list["purrbation"]) + if(!check_rights(R_SPAWN)) + return + var/mob/living/carbon/human/H = locate(href_list["purrbation"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - if(!ishumanbasic(H)) - to_chat(usr, "This can only be done to the basic human species at the moment.") - return - - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - - var/success = purrbation_toggle(H) - if(success) - to_chat(usr, "Put [H] on purrbation.") - log_admin("[key_name(usr)] has put [key_name(H)] on purrbation.") - var/msg = "[key_name_admin(usr)] has put [key_name(H)] on purrbation." - message_admins(msg) - admin_ticket_log(H, msg) - - else - to_chat(usr, "Removed [H] from purrbation.") - log_admin("[key_name(usr)] has removed [key_name(H)] from purrbation.") - var/msg = "[key_name_admin(usr)] has removed [key_name(H)] from purrbation." - message_admins(msg) - admin_ticket_log(H, msg) - - else if(href_list["adjustDamage"] && href_list["mobToDamage"]) - if(!check_rights(0)) - return - + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + if(!ishumanbasic(H)) + to_chat(usr, "This can only be done to the basic human species at the moment.") + return + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + var/success = purrbation_toggle(H) + if(success) + to_chat(usr, "Put [H] on purrbation.") + log_admin("[key_name(usr)] has put [key_name(H)] on purrbation.") + var/msg = "[key_name_admin(usr)] has put [key_name(H)] on purrbation." + message_admins(msg) + admin_ticket_log(H, msg) + + else + to_chat(usr, "Removed [H] from purrbation.") + log_admin("[key_name(usr)] has removed [key_name(H)] from purrbation.") + var/msg = "[key_name_admin(usr)] has removed [key_name(H)] from purrbation." + message_admins(msg) + admin_ticket_log(H, msg) + + else if(href_list["adjustDamage"] && href_list["mobToDamage"]) + if(!check_rights(0)) + return + var/mob/living/L = locate(href_list["mobToDamage"]) in GLOB.mob_list - if(!istype(L)) - return - - var/Text = href_list["adjustDamage"] - - var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num - - if(!L) - to_chat(usr, "Mob doesn't exist anymore") - return - - switch(Text) - if("brute") - L.adjustBruteLoss(amount) - if("fire") - L.adjustFireLoss(amount) - if("toxin") - L.adjustToxLoss(amount) - if("oxygen") - L.adjustOxyLoss(amount) - if("brain") - L.adjustBrainLoss(amount) - if("clone") - L.adjustCloneLoss(amount) - if("stamina") - L.adjustStaminaLoss(amount) - else - to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") - return - - if(amount != 0) - log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ") - var/msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [L] " - message_admins(msg) - admin_ticket_log(L, msg) - href_list["datumrefresh"] = href_list["mobToDamage"] - + if(!istype(L)) + return + + var/Text = href_list["adjustDamage"] + + var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num + + if(!L) + to_chat(usr, "Mob doesn't exist anymore") + return + + switch(Text) + if("brute") + L.adjustBruteLoss(amount) + if("fire") + L.adjustFireLoss(amount) + if("toxin") + L.adjustToxLoss(amount) + if("oxygen") + L.adjustOxyLoss(amount) + if("brain") + L.adjustBrainLoss(amount) + if("clone") + L.adjustCloneLoss(amount) + if("stamina") + L.adjustStaminaLoss(amount) + else + to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") + return + + if(amount != 0) + log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ") + var/msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [L] " + message_admins(msg) + admin_ticket_log(L, msg) + href_list["datumrefresh"] = href_list["mobToDamage"] + From 6d88e3642b924c4c55a004063dd476bd86a09a06 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 14:27:28 -0500 Subject: [PATCH 065/102] Update suit_storage_unit.dm --- code/game/machinery/suit_storage_unit.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 5d5539fc19..be89a3d2e6 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -583,7 +583,6 @@ return ..() ->>>>>>> d4d898f... Regularizes resisting out of containers (#30412) /obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) From 1553e26fe2eba880d8413f8b241c245dc58680b6 Mon Sep 17 00:00:00 2001 From: AnturK Date: Mon, 11 Sep 2017 21:36:22 +0200 Subject: [PATCH 066/102] I missed that in last fix. (#30590) --- code/modules/mob/living/carbon/monkey/punpun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/monkey/punpun.dm b/code/modules/mob/living/carbon/monkey/punpun.dm index 711e771074..52ca8c8226 100644 --- a/code/modules/mob/living/carbon/monkey/punpun.dm +++ b/code/modules/mob/living/carbon/monkey/punpun.dm @@ -68,6 +68,6 @@ if(!ancestor_name) file_data["ancestor_name"] = name fdel(json_file) - WRITE_FILE(json_file, json_encode(json_file)) + WRITE_FILE(json_file, json_encode(file_data)) if(!dead) memory_saved = 1 \ No newline at end of file From 80dbaae65a48e4ee598d81e70bc2eef20976c5f1 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 14:37:55 -0500 Subject: [PATCH 068/102] fuck --- code/game/objects/items/weaponry.dm | 566 ---------------------------- 1 file changed, 566 deletions(-) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 60b019bcf7..9a9cdbdebe 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -399,572 +399,6 @@ user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") return (OXYLOSS) -/obj/item/mounted_chainsaw - name = "mounted chainsaw" - desc = "A chainsaw that has replaced your arm." - icon_state = "chainsaw_on" - item_state = "mounted_chainsaw" - lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' - flags_1 = NODROP_1 | ABSTRACT_1 | DROPDEL_1 - w_class = WEIGHT_CLASS_HUGE - force = 21 - throwforce = 0 - throw_range = 0 - throw_speed = 0 - sharpness = IS_SHARP - attack_verb = list("sawed", "torn", "cut", "chopped", "diced") - hitsound = 'sound/weapons/chainsawhit.ogg' - -/obj/item/mounted_chainsaw/Destroy() - var/obj/item/bodypart/part - new /obj/item/twohanded/required/chainsaw(get_turf(src)) - if(iscarbon(loc)) - var/mob/living/carbon/holder = loc - var/index = holder.get_held_index_of_item(src) - if(index) - part = holder.hand_bodyparts[index] - . = ..() - if(part) - part.drop_limb() - -/obj/item/statuebust - name = "bust" - desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it - icon = 'icons/obj/statue.dmi' - icon_state = "bust" - force = 15 - throwforce = 10 - throw_speed = 5 - throw_range = 2 - attack_verb = list("busted") - -/obj/item/tailclub - name = "tail club" - desc = "For the beating to death of lizards with their own tails." - icon_state = "tailclub" - force = 14 - throwforce = 1 // why are you throwing a club do you even weapon - throw_speed = 1 - throw_range = 1 - attack_verb = list("clubbed", "bludgeoned") - -/obj/item/melee/chainofcommand/tailwhip - name = "liz o' nine tails" - desc = "A whip fashioned from the severed tails of lizards." - icon_state = "tailwhip" - origin_tech = "engineering=3;combat=3;biotech=3" - needs_permit = 0 - -/obj/item/melee/chainofcommand/tailwhip/kitty - name = "cat o' nine tails" - desc = "A whip fashioned from the severed tails of cats." - icon_state = "catwhip" - -/obj/item/melee/skateboard - name = "skateboard" - desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon." - icon_state = "skateboard" - item_state = "skateboard" - force = 12 - throwforce = 4 - w_class = WEIGHT_CLASS_HUGE - attack_verb = list("smacked", "whacked", "slammed", "smashed") - -/obj/item/melee/skateboard/attack_self(mob/user) - new /obj/vehicle/scooter/skateboard(get_turf(user)) - qdel(src) - -/obj/item/melee/baseball_bat - name = "baseball bat" - desc = "There ain't a skull in the league that can withstand a swatter." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "baseball_bat" - item_state = "baseball_bat" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 10 - throwforce = 12 - attack_verb = list("beat", "smacked") - w_class = WEIGHT_CLASS_HUGE - var/homerun_ready = 0 - var/homerun_able = 0 - -/obj/item/melee/baseball_bat/homerun - name = "home run bat" - desc = "This thing looks dangerous... Dangerously good at baseball, that is." - homerun_able = 1 - -/obj/item/melee/baseball_bat/attack_self(mob/user) - if(!homerun_able) - ..() - return - if(homerun_ready) - to_chat(user, "You're already ready to do a home run!") - ..() - return - to_chat(user, "You begin gathering strength...") - playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1) - if(do_after(user, 90, target = src)) - to_chat(user, "You gather power! Time for a home run!") - homerun_ready = 1 - ..() - -/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user) - . = ..() - var/atom/throw_target = get_edge_target_turf(target, user.dir) - if(homerun_ready) - user.visible_message("It's a home run!") - target.throw_at(throw_target, rand(8,10), 14, user) - target.ex_act(EXPLODE_HEAVY) - playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) - homerun_ready = 0 - return - else if(!target.anchored) - target.throw_at(throw_target, rand(1,2), 7, user) - -/obj/item/melee/baseball_bat/ablative - name = "metal baseball bat" - desc = "This bat is made of highly reflective, highly armored material." - icon_state = "baseball_bat_metal" - item_state = "baseball_bat_metal" - force = 12 - throwforce = 15 - -/obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers - var/picksound = rand(1,2) - var/turf = get_turf(src) - if(picksound == 1) - playsound(turf, 'sound/weapons/effects/batreflect1.ogg', 50, 1) - if(picksound == 2) - playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) - return 1 - -/obj/item/melee/flyswatter - name = "flyswatter" - desc = "Useful for killing insects of all sizes." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "flyswatter" - item_state = "flyswatter" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 1 - throwforce = 1 - attack_verb = list("swatted", "smacked") - hitsound = 'sound/effects/snap.ogg' - w_class = WEIGHT_CLASS_SMALL - //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. - var/list/strong_against - -/obj/item/melee/flyswatter/Initialize() - . = ..() - strong_against = typecacheof(list( - /mob/living/simple_animal/hostile/poison/bees/, - /mob/living/simple_animal/butterfly, - /mob/living/simple_animal/cockroach, - /obj/item/queen_bee - )) - - -/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag) - if(proximity_flag) - if(is_type_in_typecache(target, strong_against)) - new /obj/effect/decal/cleanable/deadcockroach(get_turf(target)) - to_chat(user, "You easily splat the [target].") - if(istype(target, /mob/living/)) - var/mob/living/bug = target - bug.death(1) - else - qdel(target) - -/obj/item/circlegame - name = "circled hand" - desc = "If somebody looks at this while it's below your waist, you get to bop them." - icon_state = "madeyoulook" - force = 0 - throwforce = 0 - flags_1 = DROPDEL_1 | ABSTRACT_1 - attack_verb = list("bopped") - -/obj/item/proc/can_trigger_gun(mob/living/user) - if(!user.can_use_guns(src)) - return FALSE - playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much - -/obj/item/sord - name = "\improper SORD" - desc = "This thing is so unspeakably shitty you are having a hard time even holding it." - icon_state = "sord" - item_state = "sord" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - slot_flags = SLOT_BELT - force = 2 - throwforce = 1 - w_class = WEIGHT_CLASS_NORMAL - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - -/obj/item/sord/suicide_act(mob/user) - user.visible_message("[user] is trying to impale [user.p_them()]self with [src]! It might be a suicide attempt if it weren't so shitty.", \ - "You try to impale yourself with [src], but it's USELESS...") - return SHAME - -/obj/item/claymore - name = "claymore" - desc = "What are you standing around staring at this for? Get to killing!" - icon_state = "claymore" - item_state = "claymore" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - hitsound = 'sound/weapons/bladeslice.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT | SLOT_BACK - force = 40 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 - sharpness = IS_SHARP - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/claymore/suicide_act(mob/user) - user.visible_message("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS - desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." - flags_1 = CONDUCT_1 | NODROP_1 | DROPDEL_1 - slot_flags = null - block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY - luminosity = 3 - attack_verb = list("brutalized", "eviscerated", "disemboweled", "hacked", "carved", "cleaved") //ONLY THE MOST VISCERAL ATTACK VERBS - var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE - var/obj/item/disk/nuclear/nuke_disk //OUR STORED NUKE DISK - -/obj/item/claymore/highlander/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/item/claymore/highlander/Destroy() - if(nuke_disk) - nuke_disk.forceMove(get_turf(src)) - nuke_disk.visible_message("The nuke disk is vulnerable!") - nuke_disk = null - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/claymore/highlander/process() - if(ishuman(loc)) - var/mob/living/carbon/human/H = loc - loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS) - H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS - else - if(!admin_spawned) - qdel(src) - - -/obj/item/claymore/highlander/pickup(mob/living/user) - to_chat(user, "The power of Scotland protects you! You are shielded from all stuns and knockdowns.") - user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!") - user.status_flags += IGNORESLOWDOWN - -/obj/item/claymore/highlander/dropped(mob/living/user) - user.status_flags -= IGNORESLOWDOWN - qdel(src) //If this ever happens, it's because you lost an arm - -/obj/item/claymore/highlander/examine(mob/user) - ..() - to_chat(user, "It has [!notches ? "nothing" : "[notches] notches"] scratched into the blade.") - if(nuke_disk) - to_chat(user, "It's holding the nuke disk!") - -/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) - . = ..() - if(!QDELETED(target) && iscarbon(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") - user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES - add_notch(user) - target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") - target.dust() - -/obj/item/claymore/highlander/attack_self(mob/living/user) - var/closest_victim - var/closest_distance = 255 - for(var/mob/living/carbon/human/H in GLOB.player_list - user) - if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) - closest_victim = H - if(!closest_victim) - to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") - return - to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].") - -/obj/item/claymore/highlander/IsReflect() - return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME? - -/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE - notches++ - force++ - var/new_name = name - switch(notches) - if(1) - to_chat(user, "Your first kill - hopefully one of many. You scratch a notch into [src]'s blade.") - to_chat(user, "You feel your fallen foe's soul entering your blade, restoring your wounds!") - new_name = "notched claymore" - if(2) - to_chat(user, "Another falls before you. Another soul fuses with your own. Another notch in the blade.") - new_name = "double-notched claymore" - add_atom_colour(rgb(255, 235, 235), ADMIN_COLOUR_PRIORITY) - if(3) - to_chat(user, "You're beginning to relish the thrill of battle.") - new_name = "triple-notched claymore" - add_atom_colour(rgb(255, 215, 215), ADMIN_COLOUR_PRIORITY) - if(4) - to_chat(user, "You've lost count of how many you've killed.") - new_name = "many-notched claymore" - add_atom_colour(rgb(255, 195, 195), ADMIN_COLOUR_PRIORITY) - if(5) - to_chat(user, "Five voices now echo in your mind, cheering the slaughter.") - new_name = "battle-tested claymore" - add_atom_colour(rgb(255, 175, 175), ADMIN_COLOUR_PRIORITY) - if(6) - to_chat(user, "Is this what the vikings felt like? Visions of glory fill your head as you slay your sixth foe.") - new_name = "battle-scarred claymore" - add_atom_colour(rgb(255, 155, 155), ADMIN_COLOUR_PRIORITY) - if(7) - to_chat(user, "Kill. Butcher. Conquer.") - new_name = "vicious claymore" - add_atom_colour(rgb(255, 135, 135), ADMIN_COLOUR_PRIORITY) - if(8) - to_chat(user, "IT NEVER GETS OLD. THE SCREAMING. THE BLOOD AS IT SPRAYS ACROSS YOUR FACE.") - new_name = "bloodthirsty claymore" - add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY) - if(9) - to_chat(user, "ANOTHER ONE FALLS TO YOUR BLOWS. ANOTHER WEAKLING UNFIT TO LIVE.") - new_name = "gore-stained claymore" - add_atom_colour(rgb(255, 95, 95), ADMIN_COLOUR_PRIORITY) - if(10) - user.visible_message("[user]'s eyes light up with a vengeful fire!", \ - "YOU FEEL THE POWER OF VALHALLA FLOWING THROUGH YOU! THERE CAN BE ONLY ONE!!!") - user.update_icons() - new_name = "GORE-DRENCHED CLAYMORE OF [pick("THE WHIMSICAL SLAUGHTER", "A THOUSAND SLAUGHTERED CATTLE", "GLORY AND VALHALLA", "ANNIHILATION", "OBLITERATION")]" - icon_state = "claymore_valhalla" - item_state = "cultblade" - remove_atom_colour(ADMIN_COLOUR_PRIORITY) - - name = new_name - playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) - -/obj/item/katana - name = "katana" - desc = "Woefully underpowered in D20" - icon_state = "katana" - item_state = "katana" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT | SLOT_BACK - force = 40 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 - sharpness = IS_SHARP - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/katana/cursed - slot_flags = null - -/obj/item/katana/suicide_act(mob/user) - user.visible_message("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!") - return(BRUTELOSS) - -/obj/item/wirerod - name = "wired rod" - desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." - icon_state = "wiredrod" - item_state = "rods" - flags_1 = CONDUCT_1 - force = 9 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - materials = list(MAT_METAL=1150, MAT_GLASS=75) - attack_verb = list("hit", "bludgeoned", "whacked", "bonked") - -/obj/item/wirerod/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/shard)) - var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear - - remove_item_from_storage(user) - qdel(I) - qdel(src) - - user.put_in_hands(S) - to_chat(user, "You fasten the glass shard to the top of the rod with the cable.") - - else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags_1 & NODROP_1)) - var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod - - remove_item_from_storage(user) - - to_chat(user, "You fasten [I] to the top of the rod with the cable.") - - qdel(I) - qdel(src) - - user.put_in_hands(P) - else - return ..() - - -/obj/item/throwing_star - name = "throwing star" - desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" - icon_state = "throwingstar" - item_state = "eshield0" - lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' - force = 2 - throwforce = 20 //This is never used on mobs since this has a 100% embed chance. - throw_speed = 4 - embedded_pain_multiplier = 4 - w_class = WEIGHT_CLASS_SMALL - embed_chance = 100 - embedded_fall_chance = 0 //Hahaha! - sharpness = IS_SHARP - materials = list(MAT_METAL=500, MAT_GLASS=500) - resistance_flags = FIRE_PROOF - - -/obj/item/switchblade - name = "switchblade" - icon_state = "switchblade" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - desc = "A sharp, concealable, spring-loaded knife." - flags_1 = CONDUCT_1 - force = 3 - w_class = WEIGHT_CLASS_SMALL - throwforce = 5 - throw_speed = 3 - throw_range = 6 - materials = list(MAT_METAL=12000) - origin_tech = "engineering=3;combat=2" - hitsound = 'sound/weapons/genhit.ogg' - attack_verb = list("stubbed", "poked") - resistance_flags = FIRE_PROOF - var/extended = 0 - -/obj/item/switchblade/attack_self(mob/user) - extended = !extended - playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1) - if(extended) - force = 20 - w_class = WEIGHT_CLASS_NORMAL - throwforce = 23 - icon_state = "switchblade_ext" - attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP - else - force = 3 - w_class = WEIGHT_CLASS_SMALL - throwforce = 5 - icon_state = "switchblade" - attack_verb = list("stubbed", "poked") - hitsound = 'sound/weapons/genhit.ogg' - sharpness = IS_BLUNT - -/obj/item/switchblade/suicide_act(mob/user) - user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/phone - name = "red phone" - desc = "Should anything ever go wrong..." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "red_phone" - force = 3 - throwforce = 2 - throw_speed = 3 - throw_range = 4 - w_class = WEIGHT_CLASS_SMALL - attack_verb = list("called", "rang") - hitsound = 'sound/weapons/ring.ogg' - -/obj/item/phone/suicide_act(mob/user) - if(locate(/obj/structure/chair/stool) in user.loc) - user.visible_message("[user] begins to tie a noose with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") - else - user.visible_message("[user] is strangling [user.p_them()]self with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") - return(OXYLOSS) - -/obj/item/cane - name = "cane" - desc = "A cane used by a true gentleman. Or a clown." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "cane" - item_state = "stick" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 5 - throwforce = 5 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") - -/obj/item/staff - name = "wizard staff" - desc = "Apparently a staff used by the wizard." - icon = 'icons/obj/wizard.dmi' - icon_state = "staff" - lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' - force = 3 - throwforce = 5 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armour_penetration = 100 - attack_verb = list("bludgeoned", "whacked", "disciplined") - resistance_flags = FLAMMABLE - -/obj/item/staff/broom - name = "broom" - desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." - icon = 'icons/obj/wizard.dmi' - icon_state = "broom" - resistance_flags = FLAMMABLE - -/obj/item/staff/stick - name = "stick" - desc = "A great tool to drag someone else's drinks across the bar." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "stick" - item_state = "stick" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 3 - throwforce = 5 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - -/obj/item/ectoplasm - name = "ectoplasm" - desc = "spooky" - gender = PLURAL - icon = 'icons/obj/wizard.dmi' - icon_state = "ectoplasm" - -/obj/item/ectoplasm/suicide_act(mob/user) - user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") - return (OXYLOSS) - /obj/item/mounted_chainsaw name = "mounted chainsaw" desc = "A chainsaw that has replaced your arm." From a4236145f480dfb394eb9f68aebb4cd5c663b1a0 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 11 Sep 2017 15:22:28 -0500 Subject: [PATCH 069/102] Automatic changelog generation for PR #2641 [ci skip] --- html/changelogs/AutoChangeLog-pr-2641.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2641.yml diff --git a/html/changelogs/AutoChangeLog-pr-2641.yml b/html/changelogs/AutoChangeLog-pr-2641.yml new file mode 100644 index 0000000000..a888615c05 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2641.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - rscadd: "Admins may now show the variables interface to players to help contributors debug their new additions" From b6e2f9bfa1e2e54fc36fa2cef06160a4c735db09 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 11 Sep 2017 15:22:51 -0500 Subject: [PATCH 070/102] Automatic changelog generation for PR #2650 [ci skip] --- html/changelogs/AutoChangeLog-pr-2650.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2650.yml diff --git a/html/changelogs/AutoChangeLog-pr-2650.yml b/html/changelogs/AutoChangeLog-pr-2650.yml new file mode 100644 index 0000000000..4e062b977c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2650.yml @@ -0,0 +1,4 @@ +author: "Naksu" +delete-after: True +changes: + - rscadd: "Added TGUI interfaces to various smartfridges of different kinds, drying racks and the disk compartmentalizer" From 9adcc174b3d5bf5da98fbc53883b7f8566a986f7 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:09:44 -0500 Subject: [PATCH 071/102] Update shuttle.dm --- code/modules/shuttle/shuttle.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index f035777df5..4326e6298e 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -570,7 +570,7 @@ move_mode = moving_atom.beforeShuttleMove(newT, rotation, move_mode) //atoms move_mode = oldT.fromShuttleMove(newT, underlying_turf_type, baseturf_cache, move_mode) //turfs - move_mode = newT.toShuttleMove(oldT, dir, move_mode) //turfs + move_mode = newT.toShuttleMove(oldT, move_mode , src) //turfs if(move_mode & MOVE_AREA) areas_to_move[old_area] = TRUE From ea82bf9bfaf5cce8393c0c29485d5caf7dca5044 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:47:48 -0500 Subject: [PATCH 072/102] Update suit_storage_unit.dm --- code/game/machinery/suit_storage_unit.dm | 244 ----------------------- 1 file changed, 244 deletions(-) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index be89a3d2e6..a78fa50a6a 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -26,100 +26,6 @@ var/uv = FALSE var/uv_super = FALSE var/uv_cycles = 6 - -/obj/machinery/suit_storage_unit/standard_unit - suit_type = /obj/item/clothing/suit/space/eva - helmet_type = /obj/item/clothing/head/helmet/space/eva - mask_type = /obj/item/clothing/mask/breath - -/obj/machinery/suit_storage_unit/captain - suit_type = /obj/item/clothing/suit/space/hardsuit/captain - mask_type = /obj/item/clothing/mask/gas/sechailer - storage_type = /obj/item/tank/jetpack/oxygen/captain - -/obj/machinery/suit_storage_unit/engine - suit_type = /obj/item/clothing/suit/space/hardsuit/engine - mask_type = /obj/item/clothing/mask/breath - -/obj/machinery/suit_storage_unit/ce - suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite - mask_type = /obj/item/clothing/mask/breath - storage_type= /obj/item/clothing/shoes/magboots/advance - -/obj/machinery/suit_storage_unit/security - suit_type = /obj/item/clothing/suit/space/hardsuit/security - mask_type = /obj/item/clothing/mask/gas/sechailer - -/obj/machinery/suit_storage_unit/hos - suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos - mask_type = /obj/item/clothing/mask/gas/sechailer - storage_type = /obj/item/tank/internals/oxygen - -/obj/machinery/suit_storage_unit/atmos - suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos - mask_type = /obj/item/clothing/mask/gas - storage_type = /obj/item/watertank/atmos - -/obj/machinery/suit_storage_unit/mining - suit_type = /obj/item/clothing/suit/hooded/explorer - mask_type = /obj/item/clothing/mask/gas/explorer - -/obj/machinery/suit_storage_unit/mining/eva - suit_type = /obj/item/clothing/suit/space/hardsuit/mining - mask_type = /obj/item/clothing/mask/breath - -/obj/machinery/suit_storage_unit/cmo - suit_type = /obj/item/clothing/suit/space/hardsuit/medical - mask_type = /obj/item/clothing/mask/breath - -/obj/machinery/suit_storage_unit/rd - suit_type = /obj/item/clothing/suit/space/hardsuit/rd - mask_type = /obj/item/clothing/mask/breath - -/obj/machinery/suit_storage_unit/syndicate - suit_type = /obj/item/clothing/suit/space/hardsuit/syndi - mask_type = /obj/item/clothing/mask/gas/syndicate - storage_type = /obj/item/tank/jetpack/oxygen/harness - -/obj/machinery/suit_storage_unit/ert/command - suit_type = /obj/item/clothing/suit/space/hardsuit/ert - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - -/obj/machinery/suit_storage_unit/ert/security - suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - -/obj/machinery/suit_storage_unit/ert/engineer - suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - -/obj/machinery/suit_storage_unit/ert/medical - suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - max_integrity = 250 - - var/obj/item/clothing/suit/space/suit = null - var/obj/item/clothing/head/helmet/space/helmet = null - var/obj/item/clothing/mask/mask = null - var/obj/item/storage = null - - var/suit_type = null - var/helmet_type = null - var/mask_type = null - var/storage_type = null - - state_open = FALSE - var/locked = FALSE - panel_open = FALSE - var/safeties = TRUE - - var/uv = FALSE - var/uv_super = FALSE - var/uv_cycles = 6 var/message_cooldown var/breakout_time = 0.5 @@ -344,156 +250,6 @@ if(electrocute_mob(user, src, src, 1, TRUE)) return 1 -/obj/machinery/suit_storage_unit/relaymove(mob/user) - container_resist(user) - -/obj/machinery/suit_storage_unit/container_resist(mob/living/user) - add_fingerprint(user) - if(locked) - visible_message("You see [user] kicking against the doors of [src]!", "You start kicking against the doors...") - addtimer(CALLBACK(src, .proc/resist_open, user), 300) - else - open_machine() - dump_contents() - -/obj/machinery/suit_storage_unit/proc/resist_open(mob/user) - if(!state_open && occupant && (user in src) && user.stat == 0) // Check they're still here. - visible_message("You see [user] bursts out of [src]!", "You escape the cramped confines of [src]!") - open_machine() - -/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params) - if(state_open && is_operational()) - if(istype(I, /obj/item/clothing/suit/space)) - if(suit) - to_chat(user, "The unit already contains a suit!.") - return - if(!user.drop_item()) - return - suit = I - else if(istype(I, /obj/item/clothing/head/helmet)) - if(helmet) - to_chat(user, "The unit already contains a helmet!") - return - if(!user.drop_item()) - return - helmet = I - else if(istype(I, /obj/item/clothing/mask)) - if(mask) - to_chat(user, "The unit already contains a mask!") - return - if(!user.drop_item()) - return - mask = I - else - if(storage) - to_chat(user, "The auxiliary storage compartment is full!") - return - if(!user.drop_item()) - return - storage = I - - I.loc = src - visible_message("[user] inserts [I] into [src]", "You load [I] into [src].") - update_icon() - return - - if(panel_open && is_wire_tool(I)) - wires.interact(user) - if(!state_open) - if(default_deconstruction_screwdriver(user, "panel", "close", I)) - return - if(default_pry_open(I)) - dump_contents() - return - - return ..() - - open_machine() - dump_contents() - new /obj/item/stack/sheet/metal (loc, 2) - qdel(src) - -/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user) - if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A)) - return - var/mob/living/target = A - if(!state_open) - to_chat(user, "The unit's doors are shut!") - return - if(!is_operational()) - to_chat(user, "The unit is not operational!") - return - if(occupant || helmet || suit || storage) - to_chat(user, "It's too cluttered inside to fit in!") - return - - if(target == user) - user.visible_message("[user] starts squeezing into [src]!", "You start working your way into [src]...") - else - target.visible_message("[user] starts shoving [target] into [src]!", "[user] starts shoving you into [src]!") - - if(do_mob(user, target, 30)) - if(occupant || helmet || suit || storage) - return - if(target == user) - user.visible_message("[user] slips into [src] and closes the door behind them!", "You slip into [src]'s cramped space and shut its door.") - else - target.visible_message("[user] pushes [target] into [src] and shuts its door!", "[user] shoves you into [src] and shuts the door!") - close_machine(target) - add_fingerprint(user) - -/obj/machinery/suit_storage_unit/proc/cook() - if(uv_cycles) - uv_cycles-- - uv = TRUE - locked = TRUE - update_icon() - if(occupant) - var/mob/living/mob_occupant = occupant - if(uv_super) - mob_occupant.adjustFireLoss(rand(20, 36)) - else - mob_occupant.adjustFireLoss(rand(10, 16)) - mob_occupant.emote("scream") - addtimer(CALLBACK(src, .proc/cook), 50) - else - uv_cycles = initial(uv_cycles) - uv = FALSE - locked = FALSE - if(uv_super) - visible_message("[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.") - playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, 1) - helmet = null - qdel(helmet) - suit = null - qdel(suit) // Delete everything but the occupant. - mask = null - qdel(mask) - storage = null - qdel(storage) - // The wires get damaged too. - wires.cut_all() - else - if(!occupant) - visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.") - else - visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.") - playsound(src, 'sound/machines/airlockclose.ogg', 25, 1) - for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected - I.clean_blood() - I.fingerprints = list() - open_machine(FALSE) - if(occupant) - dump_contents() - -/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb) - if(!prob(prb)) - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(5, 1, src) - s.start() - if(electrocute_mob(user, src, src, 1, TRUE)) - return 1 - /obj/machinery/suit_storage_unit/relaymove(mob/user) if(locked) if(message_cooldown <= world.time) From c42304737a762acd0e9160b7c7b1b9b46a069933 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:47:55 -0500 Subject: [PATCH 073/102] Update implantchair.dm --- .../objects/items/implants/implantchair.dm | 188 ------------------ 1 file changed, 188 deletions(-) diff --git a/code/game/objects/items/implants/implantchair.dm b/code/game/objects/items/implants/implantchair.dm index 30a55ab54e..2f59020cbe 100644 --- a/code/game/objects/items/implants/implantchair.dm +++ b/code/game/objects/items/implants/implantchair.dm @@ -1,191 +1,3 @@ - -/obj/machinery/implantchair - name = "mindshield implanter" - desc = "Used to implant occupants with mindshield implants." - icon = 'icons/obj/machines/implantchair.dmi' - icon_state = "implantchair" - density = TRUE - opacity = 0 - anchored = TRUE - - var/ready = TRUE - var/replenishing = FALSE - - var/ready_implants = 5 - var/max_implants = 5 - var/injection_cooldown = 600 - var/replenish_cooldown = 6000 - var/implant_type = /obj/item/implant/mindshield - var/auto_inject = FALSE - var/auto_replenish = TRUE - var/special = FALSE - var/special_name = "special function" - -/obj/machinery/implantchair/Initialize() - . = ..() - open_machine() - update_icon() - - -/obj/machinery/implantchair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "implantchair", name, 375, 280, master_ui, state) - ui.open() - - -/obj/machinery/implantchair/ui_data() - var/list/data = list() - data["occupied"] = occupant ? 1 : 0 - data["open"] = state_open - - data["occupant"] = list() - if(occupant) - var/mob/living/mob_occupant = occupant - data["occupant"]["name"] = mob_occupant.name - data["occupant"]["stat"] = mob_occupant.stat - - data["special_name"] = special ? special_name : null - data["ready_implants"] = ready_implants - data["ready"] = ready - data["replenishing"] = replenishing - - return data - -/obj/machinery/implantchair/ui_act(action, params) - if(..()) - return - switch(action) - if("door") - if(state_open) - close_machine() - else - open_machine() - . = TRUE - if("implant") - implant(occupant,usr) - . = TRUE - -/obj/machinery/implantchair/proc/implant(mob/living/M,mob/user) - if (!istype(M)) - return - if(!ready_implants || !ready) - return - if(implant_action(M,user)) - ready_implants-- - if(!replenishing && auto_replenish) - replenishing = TRUE - addtimer(CALLBACK(src,"replenish"),replenish_cooldown) - if(injection_cooldown > 0) - ready = FALSE - addtimer(CALLBACK(src,"set_ready"),injection_cooldown) - else - playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, 1) - update_icon() - -/obj/machinery/implantchair/proc/implant_action(mob/living/M) - var/obj/item/implant/I = new implant_type - if(I.implant(M)) - visible_message("[M] has been implanted by the [name].") - return 1 - -/obj/machinery/implantchair/update_icon() - icon_state = initial(icon_state) - if(state_open) - icon_state += "_open" - if(occupant) - icon_state += "_occupied" - if(ready) - add_overlay("ready") - else - cut_overlays() - -/obj/machinery/implantchair/proc/replenish() - if(ready_implants < max_implants) - ready_implants++ - if(ready_implants < max_implants) - addtimer(CALLBACK(src,"replenish"),replenish_cooldown) - else - replenishing = FALSE - -/obj/machinery/implantchair/proc/set_ready() - ready = TRUE - update_icon() - -/obj/machinery/implantchair/container_resist(mob/living/user) - if(state_open) - return - user.changeNext_move(CLICK_CD_BREAKOUT) - user.last_special = world.time + CLICK_CD_BREAKOUT - to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about about a minute.)") - audible_message("You hear a metallic creaking from [src]!",hearing_distance = 2) - - if(do_after(user, 600, target = src)) - if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) - return - visible_message("[user] successfully broke out of [src]!") - to_chat(user, "You successfully break out of [src]!") - open_machine() - -/obj/machinery/implantchair/relaymove(mob/user) - container_resist(user) - -/obj/machinery/implantchair/MouseDrop_T(mob/target, mob/user) - if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !isliving(target) || !user.IsAdvancedToolUser()) - return - close_machine(target) - -/obj/machinery/implantchair/close_machine(mob/living/user) - if((isnull(user) || istype(user)) && state_open) - ..(user) - if(auto_inject && ready && ready_implants > 0) - implant(user,null) - -/obj/machinery/implantchair/genepurge - name = "Genetic purifier" - desc = "Used to purge human genome of foreign influences" - special = TRUE - special_name = "Purge genome" - injection_cooldown = 0 - replenish_cooldown = 300 - -/obj/machinery/implantchair/genepurge/implant_action(mob/living/carbon/human/H,mob/user) - if(!istype(H)) - return 0 - H.set_species(/datum/species/human, 1)//lizards go home - purrbation_remove(H)//remove cats - H.dna.remove_all_mutations()//hulks out - return 1 - - -/obj/machinery/implantchair/brainwash - name = "Neural Imprinter" - desc = "Used to indoctrinate rehabilitate hardened recidivists." - special_name = "Imprint" - injection_cooldown = 3000 - auto_inject = FALSE - auto_replenish = FALSE - special = TRUE - var/objective = "Obey the law. Praise Nanotrasen." - var/custom = FALSE - -/obj/machinery/implantchair/brainwash/implant_action(mob/living/C,mob/user) - if(!istype(C) || !C.mind) // I don't know how this makes any sense for silicons but laws trump objectives anyway. - return 0 - if(custom) - if(!user || !user.Adjacent(src)) - return 0 - objective = stripped_input(usr,"What order do you want to imprint on [C]?","Enter the order","",120) - message_admins("[key_name_admin(user)] set brainwash machine objective to '[objective]'.") - log_game("[key_name_admin(user)] set brainwash machine objective to '[objective]'.") - var/datum/objective/custom_objective = new/datum/objective(objective) - custom_objective.owner = C.mind - C.mind.objectives += custom_objective - C.mind.announce_objectives() - message_admins("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.") - log_game("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.") - return 1 - /obj/machinery/implantchair name = "mindshield implanter" desc = "Used to implant occupants with mindshield implants." From 74588305ce74e2af95307bcebf09e42f6c24ff43 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:50:49 -0500 Subject: [PATCH 074/102] Update vending_items.dm --- code/game/objects/items/vending_items.dm | 84 ------------------------ 1 file changed, 84 deletions(-) diff --git a/code/game/objects/items/vending_items.dm b/code/game/objects/items/vending_items.dm index 7837b10939..b062c39ee5 100644 --- a/code/game/objects/items/vending_items.dm +++ b/code/game/objects/items/vending_items.dm @@ -1,86 +1,3 @@ -<<<<<<< HEAD -/obj/item/vending_refill - name = "resupply canister" - var/machine_name = "Generic" - - icon = 'icons/obj/vending_restock.dmi' - icon_state = "refill_snack" - item_state = "restock_unit" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - flags_1 = CONDUCT_1 - force = 7 - throwforce = 10 - throw_speed = 1 - throw_range = 7 - w_class = WEIGHT_CLASS_BULKY - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 30) - var/charges = list(0, 0, 0) //how many restocking "charges" the refill has for standard/contraband/coin products - var/init_charges = list(0, 0, 0) - - -/obj/item/vending_refill/New(amt = -1) - ..() - name = "\improper [machine_name] restocking unit" - if(isnum(amt) && amt > -1) - charges[1] = amt - -/obj/item/vending_refill/examine(mob/user) - ..() - if(charges[1] > 0) - to_chat(user, "It can restock [charges[1]+charges[2]+charges[3]] item(s).") - else - to_chat(user, "It's empty!") - -//NOTE I decided to go for about 1/3 of a machine's capacity - -/obj/item/vending_refill/boozeomat - machine_name = "Booze-O-Mat" - icon_state = "refill_booze" - charges = list(54, 4, 0)//of 159 standard, 12 contraband - init_charges = list(54, 4, 0) - -/obj/item/vending_refill/coffee - machine_name = "Solar's Best Hot Drinks" - icon_state = "refill_joe" - charges = list(25, 4, 0)//of 75 standard, 12 contraband - init_charges = list(25, 4, 0) - -/obj/item/vending_refill/snack - machine_name = "Getmore Chocolate Corp" - charges = list(12, 2, 0)//of 36 standard, 6 contraband - init_charges = list(12, 2, 0) - -/obj/item/vending_refill/cola - machine_name = "Robust Softdrinks" - icon_state = "refill_cola" - charges = list(30, 4, 1)//of 90 standard, 12 contraband, 1 premium - init_charges = list(30, 4, 1) - -/obj/item/vending_refill/cigarette - machine_name = "ShadyCigs Deluxe" - icon_state = "refill_smoke" - charges = list(12, 3, 2)// of 36 standard, 9 contraband, 6 premium - init_charges = list(12, 3, 2) - -/obj/item/vending_refill/autodrobe - machine_name = "AutoDrobe" - icon_state = "refill_costume" - charges = list(32, 2, 3)// of 96 standard, 6 contraband, 9 premium - init_charges = list(32, 2, 3) - -/obj/item/vending_refill/clothing - machine_name = "ClothesMate" - icon_state = "refill_clothes" - charges = list(37, 4, 4)// of 111 standard, 12 contraband, 10 premium(?) - init_charges = list(37, 4, 4) - -/obj/item/vending_refill/medical - machine_name = "NanoMed" - icon_state = "refill_medical" - charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium - init_charges = list(26, 5, 3) -======= /obj/item/vending_refill name = "resupply canister" var/machine_name = "Generic" @@ -168,4 +85,3 @@ icon_state = "refill_donksoft" charges = list(32,28,0)// of 90 standard, 75 contraband, 0 premium init_charges = list(32,28,0) ->>>>>>> 91a9164... Adds Donksoft Toy Vendor (Machine Board) to the Circuit Imprinter (#30531) From b5c007ffdfe7f5f7883bd6545908a3f2f532e428 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:50:56 -0500 Subject: [PATCH 075/102] Update vending.dm --- code/game/machinery/vending.dm | 2054 ++++++++++++++++---------------- 1 file changed, 1010 insertions(+), 1044 deletions(-) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index e65d71e38f..30ad2627ca 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -1,947 +1,947 @@ -#define STANDARD_CHARGE 1 -#define CONTRABAND_CHARGE 2 -#define COIN_CHARGE 3 - -/datum/data/vending_product - var/product_name = "generic" - var/product_path = null - var/amount = 0 - var/max_amount = 0 - var/display_color = "blue" - - -/obj/machinery/vending - name = "\improper Vendomat" - desc = "A generic vending machine." - icon = 'icons/obj/vending.dmi' - icon_state = "generic" - layer = BELOW_OBJ_LAYER +#define STANDARD_CHARGE 1 +#define CONTRABAND_CHARGE 2 +#define COIN_CHARGE 3 + +/datum/data/vending_product + var/product_name = "generic" + var/product_path = null + var/amount = 0 + var/max_amount = 0 + var/display_color = "blue" + + +/obj/machinery/vending + name = "\improper Vendomat" + desc = "A generic vending machine." + icon = 'icons/obj/vending.dmi' + icon_state = "generic" + layer = BELOW_OBJ_LAYER anchored = TRUE density = TRUE - verb_say = "beeps" - verb_ask = "beeps" - verb_exclaim = "beeps" - max_integrity = 300 - integrity_failure = 100 - armor = list(melee = 20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 70) + verb_say = "beeps" + verb_ask = "beeps" + verb_exclaim = "beeps" + max_integrity = 300 + integrity_failure = 100 + armor = list(melee = 20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 70) circuit = /obj/item/circuitboard/machine/vendor - var/active = 1 //No sales pitches if off! - var/vend_ready = 1 //Are we ready to vend?? Is it time?? - - // To be filled out at compile time - var/list/products = list() //For each, use the following pattern: + var/active = 1 //No sales pitches if off! + var/vend_ready = 1 //Are we ready to vend?? Is it time?? + + // To be filled out at compile time + var/list/products = list() //For each, use the following pattern: var/list/contraband = list() //list(/type/path = amount, /type/path2 = amount2) - var/list/premium = list() //No specified amount = only one in stock - - var/product_slogans = "" //String of slogans separated by semicolons, optional - var/product_ads = "" //String of small ad messages in the vending screen - random chance - var/list/product_records = list() - var/list/hidden_records = list() - var/list/coin_records = list() - var/list/slogan_list = list() - var/list/small_ads = list() //Small ad messages in the vending screen - random chance of popping up whenever you open it - var/vend_reply //Thank you for shopping! - var/last_reply = 0 - var/last_slogan = 0 //When did we last pitch? - var/slogan_delay = 6000 //How long until we can pitch again? - var/icon_vend //Icon_state when vending! - var/icon_deny //Icon_state when vending! - var/seconds_electrified = 0 //Shock customers like an airlock. - var/shoot_inventory = 0 //Fire items at customers! We're broken! - var/shoot_inventory_chance = 2 - var/shut_up = 0 //Stop spouting those godawful pitches! - var/extended_inventory = 0 //can we access the hidden inventory? - var/scan_id = 1 - var/obj/item/coin/coin - var/obj/item/stack/spacecash/bill - - var/dish_quants = list() //used by the snack machine's custom compartment to count dishes. - - var/obj/item/vending_refill/refill_canister = null //The type of refill canisters used by this machine. - var/refill_count = 3 //The number of canisters the vending machine uses - -/obj/machinery/vending/Initialize() - var/build_inv = FALSE - if(!refill_canister) - circuit = null - build_inv = TRUE - . = ..() - wires = new /datum/wires/vending(src) - if(build_inv) //non-constructable vending machine - build_inventory(products) - build_inventory(contraband, 1) - build_inventory(premium, 0, 1) - - slogan_list = splittext(product_slogans, ";") - // So not all machines speak at the exact same time. - // The first time this machine says something will be at slogantime + this random value, - // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. - last_slogan = world.time + rand(0, slogan_delay) - power_change() - -/obj/machinery/vending/Destroy() - QDEL_NULL(wires) - QDEL_NULL(coin) - QDEL_NULL(bill) - return ..() - -/obj/machinery/vending/snack/Destroy() - for(var/obj/item/reagent_containers/food/snacks/S in contents) - S.forceMove(get_turf(src)) - return ..() - -/obj/machinery/vending/RefreshParts() //Better would be to make constructable child - if(component_parts) - product_records = list() - hidden_records = list() - coin_records = list() - build_inventory(products, start_empty = 1) - build_inventory(contraband, 1, start_empty = 1) - build_inventory(premium, 0, 1, start_empty = 1) - for(var/obj/item/vending_refill/VR in component_parts) - refill_inventory(VR, product_records, STANDARD_CHARGE) - refill_inventory(VR, coin_records, COIN_CHARGE) - refill_inventory(VR, hidden_records, CONTRABAND_CHARGE) - - -/obj/machinery/vending/deconstruct(disassembled = TRUE) - if(!refill_canister) //the non constructable vendors drop metal instead of a machine frame. + var/list/premium = list() //No specified amount = only one in stock + + var/product_slogans = "" //String of slogans separated by semicolons, optional + var/product_ads = "" //String of small ad messages in the vending screen - random chance + var/list/product_records = list() + var/list/hidden_records = list() + var/list/coin_records = list() + var/list/slogan_list = list() + var/list/small_ads = list() //Small ad messages in the vending screen - random chance of popping up whenever you open it + var/vend_reply //Thank you for shopping! + var/last_reply = 0 + var/last_slogan = 0 //When did we last pitch? + var/slogan_delay = 6000 //How long until we can pitch again? + var/icon_vend //Icon_state when vending! + var/icon_deny //Icon_state when vending! + var/seconds_electrified = 0 //Shock customers like an airlock. + var/shoot_inventory = 0 //Fire items at customers! We're broken! + var/shoot_inventory_chance = 2 + var/shut_up = 0 //Stop spouting those godawful pitches! + var/extended_inventory = 0 //can we access the hidden inventory? + var/scan_id = 1 + var/obj/item/coin/coin + var/obj/item/stack/spacecash/bill + + var/dish_quants = list() //used by the snack machine's custom compartment to count dishes. + + var/obj/item/vending_refill/refill_canister = null //The type of refill canisters used by this machine. + var/refill_count = 3 //The number of canisters the vending machine uses + +/obj/machinery/vending/Initialize() + var/build_inv = FALSE + if(!refill_canister) + circuit = null + build_inv = TRUE + . = ..() + wires = new /datum/wires/vending(src) + if(build_inv) //non-constructable vending machine + build_inventory(products) + build_inventory(contraband, 1) + build_inventory(premium, 0, 1) + + slogan_list = splittext(product_slogans, ";") + // So not all machines speak at the exact same time. + // The first time this machine says something will be at slogantime + this random value, + // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. + last_slogan = world.time + rand(0, slogan_delay) + power_change() + +/obj/machinery/vending/Destroy() + QDEL_NULL(wires) + QDEL_NULL(coin) + QDEL_NULL(bill) + return ..() + +/obj/machinery/vending/snack/Destroy() + for(var/obj/item/reagent_containers/food/snacks/S in contents) + S.forceMove(get_turf(src)) + return ..() + +/obj/machinery/vending/RefreshParts() //Better would be to make constructable child + if(component_parts) + product_records = list() + hidden_records = list() + coin_records = list() + build_inventory(products, start_empty = 1) + build_inventory(contraband, 1, start_empty = 1) + build_inventory(premium, 0, 1, start_empty = 1) + for(var/obj/item/vending_refill/VR in component_parts) + refill_inventory(VR, product_records, STANDARD_CHARGE) + refill_inventory(VR, coin_records, COIN_CHARGE) + refill_inventory(VR, hidden_records, CONTRABAND_CHARGE) + + +/obj/machinery/vending/deconstruct(disassembled = TRUE) + if(!refill_canister) //the non constructable vendors drop metal instead of a machine frame. if(!(flags_1 & NODECONSTRUCT_1)) - new /obj/item/stack/sheet/metal(loc, 3) - qdel(src) - else - ..() - -/obj/machinery/vending/obj_break(damage_flag) + new /obj/item/stack/sheet/metal(loc, 3) + qdel(src) + else + ..() + +/obj/machinery/vending/obj_break(damage_flag) if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1)) - var/dump_amount = 0 - for(var/datum/data/vending_product/R in product_records) - if(R.amount <= 0) //Try to use a record that actually has something to dump. - continue - var/dump_path = R.product_path - if(!dump_path) - continue - - while(R.amount>0) - var/obj/O = new dump_path(loc) - step(O, pick(GLOB.alldirs)) //we only drop 20% of the total of each products and spread it - R.amount -= 5 //around to not fill the turf with too many objects. - dump_amount++ - if(dump_amount > 15) //so we don't drop too many items (e.g. ClothesMate) - break - stat |= BROKEN - icon_state = "[initial(icon_state)]-broken" - -/obj/machinery/vending/proc/build_inventory(list/productlist, hidden=0, req_coin=0, start_empty = null) - for(var/typepath in productlist) - var/amount = productlist[typepath] - if(isnull(amount)) - amount = 0 - - var/atom/temp = new typepath(null) - var/datum/data/vending_product/R = new /datum/data/vending_product() - R.product_name = initial(temp.name) - R.product_path = typepath - if(!start_empty) - R.amount = amount - R.max_amount = amount - R.display_color = pick("red","blue","green") - - if(hidden) - hidden_records += R - else if(req_coin) - coin_records += R - else - product_records += R - -/obj/machinery/vending/proc/refill_inventory(obj/item/vending_refill/refill, datum/data/vending_product/machine, var/charge_type = STANDARD_CHARGE) - var/total = 0 - var/to_restock = 0 - - for(var/datum/data/vending_product/machine_content in machine) - if(machine_content.amount == 0 && refill.charges[charge_type] > 0) - machine_content.amount++ - refill.charges[charge_type]-- - total++ - to_restock += machine_content.max_amount - machine_content.amount - if(to_restock <= refill.charges[charge_type]) - for(var/datum/data/vending_product/machine_content in machine) - machine_content.amount = machine_content.max_amount - refill.charges[charge_type] -= to_restock - total += to_restock - else - var/tmp_charges = refill.charges[charge_type] - for(var/datum/data/vending_product/machine_content in machine) - if(refill.charges[charge_type] == 0) - break - var/restock = Ceiling(((machine_content.max_amount - machine_content.amount)/to_restock)*tmp_charges) - if(restock > refill.charges[charge_type]) - restock = refill.charges[charge_type] - machine_content.amount += restock - refill.charges[charge_type] -= restock - total += restock - return total - -/obj/machinery/vending/snack/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/reagent_containers/food/snacks)) - if(!compartment_access_check(user)) - return - var/obj/item/reagent_containers/food/snacks/S = W - if(!S.junkiness) - if(!iscompartmentfull(user)) - if(!user.drop_item()) - return - W.loc = src - food_load(W) - to_chat(user, "You insert [W] into [src]'s chef compartment.") - else - to_chat(user, "[src]'s chef compartment does not accept junk food.") - - else if(istype(W, /obj/item/storage/bag/tray)) - if(!compartment_access_check(user)) - return - var/obj/item/storage/T = W - var/loaded = 0 - var/denied_items = 0 - for(var/obj/item/reagent_containers/food/snacks/S in T.contents) - if(iscompartmentfull(user)) - break - if(!S.junkiness) - T.remove_from_storage(S, src) - food_load(S) - loaded++ - else - denied_items++ - if(denied_items) - to_chat(user, "[src] refuses some items.") - if(loaded) - to_chat(user, "You insert [loaded] dishes into [src]'s chef compartment.") - updateUsrDialog() - return - - else - return ..() - -/obj/machinery/vending/snack/proc/compartment_access_check(user) - req_access_txt = chef_compartment_access - if(!allowed(user) && !emagged && scan_id) - to_chat(user, "[src]'s chef compartment blinks red: Access denied.") - req_access_txt = "0" - return 0 - req_access_txt = "0" - return 1 - -/obj/machinery/vending/snack/proc/iscompartmentfull(mob/user) - if(contents.len >= 30) // no more than 30 dishes can fit inside - to_chat(user, "[src]'s chef compartment is full.") - return 1 - return 0 - -/obj/machinery/vending/snack/proc/food_load(obj/item/reagent_containers/food/snacks/S) - if(dish_quants[S.name]) - dish_quants[S.name]++ - else - dish_quants[S.name] = 1 - sortList(dish_quants) - -/obj/machinery/vending/attackby(obj/item/W, mob/user, params) - if(panel_open) - if(default_unfasten_wrench(user, W, time = 60)) - return - - if(component_parts) - if(default_deconstruction_crowbar(W)) - return - - if(istype(W, /obj/item/screwdriver)) - if(anchored) - panel_open = !panel_open - to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") - cut_overlays() - if(panel_open) - add_overlay("[initial(icon_state)]-panel") - playsound(src.loc, W.usesound, 50, 1) - updateUsrDialog() - else - to_chat(user, "You must first secure [src].") - return - else if(istype(W, /obj/item/device/multitool)||istype(W, /obj/item/wirecutters)) - if(panel_open) - attack_hand(user) - return - else if(istype(W, /obj/item/coin)) - if(coin) - to_chat(user, "[src] already has [coin] inserted") - return - if(bill) - to_chat(user, "[src] already has [bill] inserted") - return - if(!premium.len) - to_chat(user, "[src] doesn't have a coin slot.") - return - if(!user.drop_item()) - return - W.loc = src - coin = W - to_chat(user, "You insert [W] into [src].") - return - else if(istype(W, /obj/item/stack/spacecash)) - if(coin) - to_chat(user, "[src] already has [coin] inserted") - return - if(bill) - to_chat(user, "[src] already has [bill] inserted") - return - var/obj/item/stack/S = W - if(!premium.len) - to_chat(user, "[src] doesn't have a bill slot.") - return - S.use(1) - bill = new S.type(src,1) - to_chat(user, "You insert [W] into [src].") - return - else if(istype(W, refill_canister) && refill_canister != null) - if(stat & (BROKEN|NOPOWER)) - to_chat(user, "It does nothing.") - else if(panel_open) - //if the panel is open we attempt to refill the machine - var/obj/item/vending_refill/canister = W - if(canister.charges[STANDARD_CHARGE] == 0) - to_chat(user, "This [canister.name] is empty!") - else - var/transfered = refill_inventory(canister,product_records,STANDARD_CHARGE) - transfered += refill_inventory(canister,coin_records,COIN_CHARGE) - transfered += refill_inventory(canister,hidden_records,CONTRABAND_CHARGE) - if(transfered) - to_chat(user, "You loaded [transfered] items in \the [name].") - else - to_chat(user, "The [name] is fully stocked.") - return - else - to_chat(user, "You should probably unscrew the service panel first.") - else - return ..() - - -/obj/machinery/vending/on_deconstruction() - var/product_list = list(product_records, hidden_records, coin_records) - for(var/i=1, i<=3, i++) - for(var/datum/data/vending_product/machine_content in product_list[i]) - while(machine_content.amount !=0) - var/safety = 0 //to avoid infinite loop - for(var/obj/item/vending_refill/VR in component_parts) - safety++ - if(VR.charges[i] < VR.init_charges[i]) - VR.charges[i]++ - machine_content.amount-- - if(!machine_content.amount) - break - else - safety-- - if(safety <= 0) // all refill canisters are full - break - ..() - -/obj/machinery/vending/emag_act(mob/user) + var/dump_amount = 0 + for(var/datum/data/vending_product/R in product_records) + if(R.amount <= 0) //Try to use a record that actually has something to dump. + continue + var/dump_path = R.product_path + if(!dump_path) + continue + + while(R.amount>0) + var/obj/O = new dump_path(loc) + step(O, pick(GLOB.alldirs)) //we only drop 20% of the total of each products and spread it + R.amount -= 5 //around to not fill the turf with too many objects. + dump_amount++ + if(dump_amount > 15) //so we don't drop too many items (e.g. ClothesMate) + break + stat |= BROKEN + icon_state = "[initial(icon_state)]-broken" + +/obj/machinery/vending/proc/build_inventory(list/productlist, hidden=0, req_coin=0, start_empty = null) + for(var/typepath in productlist) + var/amount = productlist[typepath] + if(isnull(amount)) + amount = 0 + + var/atom/temp = new typepath(null) + var/datum/data/vending_product/R = new /datum/data/vending_product() + R.product_name = initial(temp.name) + R.product_path = typepath + if(!start_empty) + R.amount = amount + R.max_amount = amount + R.display_color = pick("red","blue","green") + + if(hidden) + hidden_records += R + else if(req_coin) + coin_records += R + else + product_records += R + +/obj/machinery/vending/proc/refill_inventory(obj/item/vending_refill/refill, datum/data/vending_product/machine, var/charge_type = STANDARD_CHARGE) + var/total = 0 + var/to_restock = 0 + + for(var/datum/data/vending_product/machine_content in machine) + if(machine_content.amount == 0 && refill.charges[charge_type] > 0) + machine_content.amount++ + refill.charges[charge_type]-- + total++ + to_restock += machine_content.max_amount - machine_content.amount + if(to_restock <= refill.charges[charge_type]) + for(var/datum/data/vending_product/machine_content in machine) + machine_content.amount = machine_content.max_amount + refill.charges[charge_type] -= to_restock + total += to_restock + else + var/tmp_charges = refill.charges[charge_type] + for(var/datum/data/vending_product/machine_content in machine) + if(refill.charges[charge_type] == 0) + break + var/restock = Ceiling(((machine_content.max_amount - machine_content.amount)/to_restock)*tmp_charges) + if(restock > refill.charges[charge_type]) + restock = refill.charges[charge_type] + machine_content.amount += restock + refill.charges[charge_type] -= restock + total += restock + return total + +/obj/machinery/vending/snack/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/reagent_containers/food/snacks)) + if(!compartment_access_check(user)) + return + var/obj/item/reagent_containers/food/snacks/S = W + if(!S.junkiness) + if(!iscompartmentfull(user)) + if(!user.drop_item()) + return + W.loc = src + food_load(W) + to_chat(user, "You insert [W] into [src]'s chef compartment.") + else + to_chat(user, "[src]'s chef compartment does not accept junk food.") + + else if(istype(W, /obj/item/storage/bag/tray)) + if(!compartment_access_check(user)) + return + var/obj/item/storage/T = W + var/loaded = 0 + var/denied_items = 0 + for(var/obj/item/reagent_containers/food/snacks/S in T.contents) + if(iscompartmentfull(user)) + break + if(!S.junkiness) + T.remove_from_storage(S, src) + food_load(S) + loaded++ + else + denied_items++ + if(denied_items) + to_chat(user, "[src] refuses some items.") + if(loaded) + to_chat(user, "You insert [loaded] dishes into [src]'s chef compartment.") + updateUsrDialog() + return + + else + return ..() + +/obj/machinery/vending/snack/proc/compartment_access_check(user) + req_access_txt = chef_compartment_access + if(!allowed(user) && !emagged && scan_id) + to_chat(user, "[src]'s chef compartment blinks red: Access denied.") + req_access_txt = "0" + return 0 + req_access_txt = "0" + return 1 + +/obj/machinery/vending/snack/proc/iscompartmentfull(mob/user) + if(contents.len >= 30) // no more than 30 dishes can fit inside + to_chat(user, "[src]'s chef compartment is full.") + return 1 + return 0 + +/obj/machinery/vending/snack/proc/food_load(obj/item/reagent_containers/food/snacks/S) + if(dish_quants[S.name]) + dish_quants[S.name]++ + else + dish_quants[S.name] = 1 + sortList(dish_quants) + +/obj/machinery/vending/attackby(obj/item/W, mob/user, params) + if(panel_open) + if(default_unfasten_wrench(user, W, time = 60)) + return + + if(component_parts) + if(default_deconstruction_crowbar(W)) + return + + if(istype(W, /obj/item/screwdriver)) + if(anchored) + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") + cut_overlays() + if(panel_open) + add_overlay("[initial(icon_state)]-panel") + playsound(src.loc, W.usesound, 50, 1) + updateUsrDialog() + else + to_chat(user, "You must first secure [src].") + return + else if(istype(W, /obj/item/device/multitool)||istype(W, /obj/item/wirecutters)) + if(panel_open) + attack_hand(user) + return + else if(istype(W, /obj/item/coin)) + if(coin) + to_chat(user, "[src] already has [coin] inserted") + return + if(bill) + to_chat(user, "[src] already has [bill] inserted") + return + if(!premium.len) + to_chat(user, "[src] doesn't have a coin slot.") + return + if(!user.drop_item()) + return + W.loc = src + coin = W + to_chat(user, "You insert [W] into [src].") + return + else if(istype(W, /obj/item/stack/spacecash)) + if(coin) + to_chat(user, "[src] already has [coin] inserted") + return + if(bill) + to_chat(user, "[src] already has [bill] inserted") + return + var/obj/item/stack/S = W + if(!premium.len) + to_chat(user, "[src] doesn't have a bill slot.") + return + S.use(1) + bill = new S.type(src,1) + to_chat(user, "You insert [W] into [src].") + return + else if(istype(W, refill_canister) && refill_canister != null) + if(stat & (BROKEN|NOPOWER)) + to_chat(user, "It does nothing.") + else if(panel_open) + //if the panel is open we attempt to refill the machine + var/obj/item/vending_refill/canister = W + if(canister.charges[STANDARD_CHARGE] == 0) + to_chat(user, "This [canister.name] is empty!") + else + var/transfered = refill_inventory(canister,product_records,STANDARD_CHARGE) + transfered += refill_inventory(canister,coin_records,COIN_CHARGE) + transfered += refill_inventory(canister,hidden_records,CONTRABAND_CHARGE) + if(transfered) + to_chat(user, "You loaded [transfered] items in \the [name].") + else + to_chat(user, "The [name] is fully stocked.") + return + else + to_chat(user, "You should probably unscrew the service panel first.") + else + return ..() + + +/obj/machinery/vending/on_deconstruction() + var/product_list = list(product_records, hidden_records, coin_records) + for(var/i=1, i<=3, i++) + for(var/datum/data/vending_product/machine_content in product_list[i]) + while(machine_content.amount !=0) + var/safety = 0 //to avoid infinite loop + for(var/obj/item/vending_refill/VR in component_parts) + safety++ + if(VR.charges[i] < VR.init_charges[i]) + VR.charges[i]++ + machine_content.amount-- + if(!machine_content.amount) + break + else + safety-- + if(safety <= 0) // all refill canisters are full + break + ..() + +/obj/machinery/vending/emag_act(mob/user) if(emagged) return emagged = TRUE to_chat(user, "You short out the product lock on [src].") - -/obj/machinery/vending/attack_ai(mob/user) - return attack_hand(user) - -/obj/machinery/vending/attack_hand(mob/user) - var/dat = "" - if(panel_open && !isAI(user)) - return wires.interact(user) - else - if(stat & (BROKEN|NOPOWER)) - return - - dat += "

    Select an item

    " - dat += "
    " - if(product_records.len == 0) - dat += "No product loaded!" - else - var/list/display_records = product_records - if(extended_inventory) - display_records = product_records + hidden_records - if(coin || bill) - display_records = product_records + coin_records - if((coin || bill) && extended_inventory) - display_records = product_records + hidden_records + coin_records - dat += "
      " - for (var/datum/data/vending_product/R in display_records) - dat += "
    • " - if(R.amount > 0) - dat += "Vend " - else - dat += "Sold out " - dat += "[sanitize(R.product_name)]:" - dat += " [R.amount]" - dat += "
    • " - dat += "
    " - dat += "
    " - if(premium.len > 0) - dat += "Change Return: " - if (coin || bill) - dat += "[(coin ? coin : "")][(bill ? bill : "")]  Remove" - else - dat += "No money  Remove" - if(istype(src, /obj/machinery/vending/snack)) - dat += "

    Chef's Food Selection

    " - dat += "
    " - for (var/O in dish_quants) - if(dish_quants[O] > 0) - var/N = dish_quants[O] - dat += "Dispense " - dat += "[capitalize(O)]: [N]
    " - dat += "
    " - user.set_machine(src) - if(seconds_electrified && !(stat & NOPOWER)) - if(shock(user, 100)) - return - - var/datum/browser/popup = new(user, "vending", (name)) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - - -/obj/machinery/vending/Topic(href, href_list) - if(..()) - return - - if(issilicon(usr)) - if(iscyborg(usr)) - var/mob/living/silicon/robot/R = usr + +/obj/machinery/vending/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/vending/attack_hand(mob/user) + var/dat = "" + if(panel_open && !isAI(user)) + return wires.interact(user) + else + if(stat & (BROKEN|NOPOWER)) + return + + dat += "

    Select an item

    " + dat += "
    " + if(product_records.len == 0) + dat += "No product loaded!" + else + var/list/display_records = product_records + if(extended_inventory) + display_records = product_records + hidden_records + if(coin || bill) + display_records = product_records + coin_records + if((coin || bill) && extended_inventory) + display_records = product_records + hidden_records + coin_records + dat += "
      " + for (var/datum/data/vending_product/R in display_records) + dat += "
    • " + if(R.amount > 0) + dat += "Vend " + else + dat += "Sold out " + dat += "[sanitize(R.product_name)]:" + dat += " [R.amount]" + dat += "
    • " + dat += "
    " + dat += "
    " + if(premium.len > 0) + dat += "Change Return: " + if (coin || bill) + dat += "[(coin ? coin : "")][(bill ? bill : "")]  Remove" + else + dat += "No money  Remove" + if(istype(src, /obj/machinery/vending/snack)) + dat += "

    Chef's Food Selection

    " + dat += "
    " + for (var/O in dish_quants) + if(dish_quants[O] > 0) + var/N = dish_quants[O] + dat += "Dispense " + dat += "[capitalize(O)]: [N]
    " + dat += "
    " + user.set_machine(src) + if(seconds_electrified && !(stat & NOPOWER)) + if(shock(user, 100)) + return + + var/datum/browser/popup = new(user, "vending", (name)) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + + +/obj/machinery/vending/Topic(href, href_list) + if(..()) + return + + if(issilicon(usr)) + if(iscyborg(usr)) + var/mob/living/silicon/robot/R = usr if(!(R.module && istype(R.module, /obj/item/robot_module/butler) )) - to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") - return - else - to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") - return - - if(href_list["remove_coin"]) - if(!(coin || bill)) - to_chat(usr, "There is no money in this machine.") - return - if(coin) - if(!usr.get_active_held_item()) - usr.put_in_hands(coin) - else - coin.forceMove(get_turf(src)) - to_chat(usr, "You remove [coin] from [src].") - coin = null - if(bill) - if(!usr.get_active_held_item()) - usr.put_in_hands(bill) - else - bill.forceMove(get_turf(src)) - to_chat(usr, "You remove [bill] from [src].") - bill = null - - - usr.set_machine(src) - - if((href_list["dispense"]) && (vend_ready)) - var/N = href_list["dispense"] - if(dish_quants[N] <= 0) // Sanity check, there are probably ways to press the button when it shouldn't be possible. - return - vend_ready = 0 - use_power(5) - - dish_quants[N] = max(dish_quants[N] - 1, 0) - for(var/obj/O in contents) - if(O.name == N) - O.loc = src.loc - break - vend_ready = 1 - updateUsrDialog() - return - - if((href_list["vend"]) && (vend_ready)) - if(panel_open) - to_chat(usr, "The vending machine cannot dispense products while its service panel is open!") - return - - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH - to_chat(usr, "Access denied." ) - flick(icon_deny,src) - return - - vend_ready = 0 //One thing at a time!! - - var/datum/data/vending_product/R = locate(href_list["vend"]) - if(!R || !istype(R) || !R.product_path) - vend_ready = 1 - return - - if(R in hidden_records) - if(!extended_inventory) - vend_ready = 1 - return - else if(R in coin_records) - if(!(coin || bill)) - to_chat(usr, "You need to insert money to get this item!") - vend_ready = 1 - return - if(coin && coin.string_attached) - if(prob(50)) - if(usr.put_in_hands(coin)) - to_chat(usr, "You successfully pull [coin] out before [src] could swallow it.") - coin = null - else - to_chat(usr, "You couldn't pull [coin] out because your hands are full!") - QDEL_NULL(coin) - else - to_chat(usr, "You weren't able to pull [coin] out fast enough, the machine ate it, string and all!") - QDEL_NULL(coin) - else - QDEL_NULL(coin) - QDEL_NULL(bill) - - else if (!(R in product_records)) - vend_ready = 1 - message_admins("Vending machine exploit attempted by [key_name(usr, usr.client)]!") - return - - if (R.amount <= 0) - to_chat(usr, "Sold out.") - vend_ready = 1 - return - else - R.amount-- - - if(((last_reply + 200) <= world.time) && vend_reply) - speak(vend_reply) - last_reply = world.time - - use_power(5) - if(icon_vend) //Show the vending animation if needed - flick(icon_vend,src) - new R.product_path(get_turf(src)) - SSblackbox.add_details("vending_machine_usage","[src.type]|[R.product_path]") - vend_ready = 1 - return - - updateUsrDialog() - return - - else if(href_list["togglevoice"] && panel_open) - shut_up = !shut_up - - updateUsrDialog() - - -/obj/machinery/vending/process() - if(stat & (BROKEN|NOPOWER)) - return - if(!active) - return - - if(seconds_electrified > 0) - seconds_electrified-- - - //Pitch to the people! Really sell it! - if(last_slogan + slogan_delay <= world.time && slogan_list.len > 0 && !shut_up && prob(5)) - var/slogan = pick(slogan_list) - speak(slogan) - last_slogan = world.time - - if(shoot_inventory && prob(shoot_inventory_chance)) - throw_item() - - -/obj/machinery/vending/proc/speak(message) - if(stat & (BROKEN|NOPOWER)) - return - if(!message) - return - - say(message) - -/obj/machinery/vending/power_change() - if(stat & BROKEN) - icon_state = "[initial(icon_state)]-broken" - else - if(powered()) - icon_state = initial(icon_state) - stat &= ~NOPOWER - else - icon_state = "[initial(icon_state)]-off" - stat |= NOPOWER - - -//Somebody cut an important wire and now we're following a new definition of "pitch." -/obj/machinery/vending/proc/throw_item() - var/obj/throw_item = null - var/mob/living/target = locate() in view(7,src) - if(!target) - return 0 - - for(var/datum/data/vending_product/R in shuffle(product_records)) - if(R.amount <= 0) //Try to use a record that actually has something to dump. - continue - var/dump_path = R.product_path - if(!dump_path) - continue - - R.amount-- - throw_item = new dump_path(loc) - break - if(!throw_item) - return 0 - - pre_throw(throw_item) - - throw_item.throw_at(target, 16, 3) - visible_message("[src] launches [throw_item] at [target]!") - return 1 - -/obj/machinery/vending/proc/pre_throw(obj/item/I) - return - - -/obj/machinery/vending/proc/shock(mob/user, prb) - if(stat & (BROKEN|NOPOWER)) // unpowered, no shock - return FALSE - if(!prob(prb)) - return FALSE - do_sparks(5, TRUE, src) - var/tmp/check_range = TRUE - if(electrocute_mob(user, get_area(src), src, 0.7, check_range)) - return TRUE - else - return FALSE - -/* - * Vending machine types - */ - -/* - -/obj/machinery/vending/[vendors name here] // --vending machine template :) - name = "" - desc = "" - icon = '' - icon_state = "" - products = list() - contraband = list() - premium = list() - -IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY CANISTER CHARGES in vending_items.dm -*/ - -/* -/obj/machinery/vending/atmospherics //Commenting this out until someone ponies up some actual working, broken, and unpowered sprites - Quarxink - name = "Tank Vendor" - desc = "A vendor with a wide variety of masks and gas tanks." - icon = 'icons/obj/objects.dmi' - icon_state = "dispenser" - product_paths = "/obj/item/tank/internals/oxygen;/obj/item/tank/internals/plasma;/obj/item/tank/internals/emergency_oxygen;/obj/item/tank/internals/emergency_oxygen/engi;/obj/item/clothing/mask/breath" - product_amounts = "10;10;10;5;25" -*/ - -/obj/machinery/vending/boozeomat - name = "\improper Booze-O-Mat" - desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one." - icon_state = "boozeomat" //////////////18 drink entities below, plus the glasses, in case someone wants to edit the number of bottles - icon_deny = "boozeomat-deny" + to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") + return + else + to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") + return + + if(href_list["remove_coin"]) + if(!(coin || bill)) + to_chat(usr, "There is no money in this machine.") + return + if(coin) + if(!usr.get_active_held_item()) + usr.put_in_hands(coin) + else + coin.forceMove(get_turf(src)) + to_chat(usr, "You remove [coin] from [src].") + coin = null + if(bill) + if(!usr.get_active_held_item()) + usr.put_in_hands(bill) + else + bill.forceMove(get_turf(src)) + to_chat(usr, "You remove [bill] from [src].") + bill = null + + + usr.set_machine(src) + + if((href_list["dispense"]) && (vend_ready)) + var/N = href_list["dispense"] + if(dish_quants[N] <= 0) // Sanity check, there are probably ways to press the button when it shouldn't be possible. + return + vend_ready = 0 + use_power(5) + + dish_quants[N] = max(dish_quants[N] - 1, 0) + for(var/obj/O in contents) + if(O.name == N) + O.loc = src.loc + break + vend_ready = 1 + updateUsrDialog() + return + + if((href_list["vend"]) && (vend_ready)) + if(panel_open) + to_chat(usr, "The vending machine cannot dispense products while its service panel is open!") + return + + if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + to_chat(usr, "Access denied." ) + flick(icon_deny,src) + return + + vend_ready = 0 //One thing at a time!! + + var/datum/data/vending_product/R = locate(href_list["vend"]) + if(!R || !istype(R) || !R.product_path) + vend_ready = 1 + return + + if(R in hidden_records) + if(!extended_inventory) + vend_ready = 1 + return + else if(R in coin_records) + if(!(coin || bill)) + to_chat(usr, "You need to insert money to get this item!") + vend_ready = 1 + return + if(coin && coin.string_attached) + if(prob(50)) + if(usr.put_in_hands(coin)) + to_chat(usr, "You successfully pull [coin] out before [src] could swallow it.") + coin = null + else + to_chat(usr, "You couldn't pull [coin] out because your hands are full!") + QDEL_NULL(coin) + else + to_chat(usr, "You weren't able to pull [coin] out fast enough, the machine ate it, string and all!") + QDEL_NULL(coin) + else + QDEL_NULL(coin) + QDEL_NULL(bill) + + else if (!(R in product_records)) + vend_ready = 1 + message_admins("Vending machine exploit attempted by [key_name(usr, usr.client)]!") + return + + if (R.amount <= 0) + to_chat(usr, "Sold out.") + vend_ready = 1 + return + else + R.amount-- + + if(((last_reply + 200) <= world.time) && vend_reply) + speak(vend_reply) + last_reply = world.time + + use_power(5) + if(icon_vend) //Show the vending animation if needed + flick(icon_vend,src) + new R.product_path(get_turf(src)) + SSblackbox.add_details("vending_machine_usage","[src.type]|[R.product_path]") + vend_ready = 1 + return + + updateUsrDialog() + return + + else if(href_list["togglevoice"] && panel_open) + shut_up = !shut_up + + updateUsrDialog() + + +/obj/machinery/vending/process() + if(stat & (BROKEN|NOPOWER)) + return + if(!active) + return + + if(seconds_electrified > 0) + seconds_electrified-- + + //Pitch to the people! Really sell it! + if(last_slogan + slogan_delay <= world.time && slogan_list.len > 0 && !shut_up && prob(5)) + var/slogan = pick(slogan_list) + speak(slogan) + last_slogan = world.time + + if(shoot_inventory && prob(shoot_inventory_chance)) + throw_item() + + +/obj/machinery/vending/proc/speak(message) + if(stat & (BROKEN|NOPOWER)) + return + if(!message) + return + + say(message) + +/obj/machinery/vending/power_change() + if(stat & BROKEN) + icon_state = "[initial(icon_state)]-broken" + else + if(powered()) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + icon_state = "[initial(icon_state)]-off" + stat |= NOPOWER + + +//Somebody cut an important wire and now we're following a new definition of "pitch." +/obj/machinery/vending/proc/throw_item() + var/obj/throw_item = null + var/mob/living/target = locate() in view(7,src) + if(!target) + return 0 + + for(var/datum/data/vending_product/R in shuffle(product_records)) + if(R.amount <= 0) //Try to use a record that actually has something to dump. + continue + var/dump_path = R.product_path + if(!dump_path) + continue + + R.amount-- + throw_item = new dump_path(loc) + break + if(!throw_item) + return 0 + + pre_throw(throw_item) + + throw_item.throw_at(target, 16, 3) + visible_message("[src] launches [throw_item] at [target]!") + return 1 + +/obj/machinery/vending/proc/pre_throw(obj/item/I) + return + + +/obj/machinery/vending/proc/shock(mob/user, prb) + if(stat & (BROKEN|NOPOWER)) // unpowered, no shock + return FALSE + if(!prob(prb)) + return FALSE + do_sparks(5, TRUE, src) + var/tmp/check_range = TRUE + if(electrocute_mob(user, get_area(src), src, 0.7, check_range)) + return TRUE + else + return FALSE + +/* + * Vending machine types + */ + +/* + +/obj/machinery/vending/[vendors name here] // --vending machine template :) + name = "" + desc = "" + icon = '' + icon_state = "" + products = list() + contraband = list() + premium = list() + +IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY CANISTER CHARGES in vending_items.dm +*/ + +/* +/obj/machinery/vending/atmospherics //Commenting this out until someone ponies up some actual working, broken, and unpowered sprites - Quarxink + name = "Tank Vendor" + desc = "A vendor with a wide variety of masks and gas tanks." + icon = 'icons/obj/objects.dmi' + icon_state = "dispenser" + product_paths = "/obj/item/tank/internals/oxygen;/obj/item/tank/internals/plasma;/obj/item/tank/internals/emergency_oxygen;/obj/item/tank/internals/emergency_oxygen/engi;/obj/item/clothing/mask/breath" + product_amounts = "10;10;10;5;25" +*/ + +/obj/machinery/vending/boozeomat + name = "\improper Booze-O-Mat" + desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one." + icon_state = "boozeomat" //////////////18 drink entities below, plus the glasses, in case someone wants to edit the number of bottles + icon_deny = "boozeomat-deny" products = list(/obj/item/reagent_containers/food/drinks/bottle/gin = 5, /obj/item/reagent_containers/food/drinks/bottle/whiskey = 5, /obj/item/reagent_containers/food/drinks/bottle/tequila = 5, /obj/item/reagent_containers/food/drinks/bottle/vodka = 5, /obj/item/reagent_containers/food/drinks/bottle/vermouth = 5, /obj/item/reagent_containers/food/drinks/bottle/rum = 5, /obj/item/reagent_containers/food/drinks/bottle/wine = 5, /obj/item/reagent_containers/food/drinks/bottle/cognac = 5, /obj/item/reagent_containers/food/drinks/bottle/kahlua = 5, /obj/item/reagent_containers/food/drinks/bottle/hcider = 5, - /obj/item/reagent_containers/food/drinks/bottle/absinthe = 5, /obj/item/reagent_containers/food/drinks/bottle/grappa = 5, + /obj/item/reagent_containers/food/drinks/bottle/absinthe = 5, /obj/item/reagent_containers/food/drinks/bottle/grappa = 5, /obj/item/reagent_containers/food/drinks/ale = 6, /obj/item/reagent_containers/food/drinks/bottle/orangejuice = 4, /obj/item/reagent_containers/food/drinks/bottle/tomatojuice = 4, /obj/item/reagent_containers/food/drinks/bottle/limejuice = 4, /obj/item/reagent_containers/food/drinks/bottle/cream = 4, /obj/item/reagent_containers/food/drinks/soda_cans/tonic = 8, - /obj/item/reagent_containers/food/drinks/soda_cans/cola = 8, /obj/item/reagent_containers/food/drinks/soda_cans/sodawater = 15, + /obj/item/reagent_containers/food/drinks/soda_cans/cola = 8, /obj/item/reagent_containers/food/drinks/soda_cans/sodawater = 15, /obj/item/reagent_containers/food/drinks/drinkingglass = 30, /obj/item/reagent_containers/food/drinks/ice = 10, /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass = 12, /obj/item/reagent_containers/food/drinks/flask = 3) - contraband = list(/obj/item/reagent_containers/food/drinks/mug/tea = 12) - product_slogans = "I hope nobody asks me for a bloody cup o' tea...;Alcohol is humanity's friend. Would you abandon a friend?;Quite delighted to serve you!;Is nobody thirsty on this station?" - product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!" - req_access_txt = "25" - refill_canister = /obj/item/vending_refill/boozeomat - -/obj/machinery/vending/assist + contraband = list(/obj/item/reagent_containers/food/drinks/mug/tea = 12) + product_slogans = "I hope nobody asks me for a bloody cup o' tea...;Alcohol is humanity's friend. Would you abandon a friend?;Quite delighted to serve you!;Is nobody thirsty on this station?" + product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!" + req_access_txt = "25" + refill_canister = /obj/item/vending_refill/boozeomat + +/obj/machinery/vending/assist products = list( /obj/item/device/assembly/prox_sensor = 5, /obj/item/device/assembly/igniter = 3, /obj/item/device/assembly/signaler = 4, - /obj/item/wirecutters = 1, /obj/item/cartridge/signal = 4) - contraband = list(/obj/item/device/assembly/timer = 2, /obj/item/device/assembly/voice = 2, /obj/item/device/assembly/health = 2) - product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!" - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/coffee - name = "\improper Solar's Best Hot Drinks" - desc = "A vending machine which dispenses hot drinks." - product_ads = "Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies" - icon_state = "coffee" - icon_vend = "coffee-vend" + /obj/item/wirecutters = 1, /obj/item/cartridge/signal = 4) + contraband = list(/obj/item/device/assembly/timer = 2, /obj/item/device/assembly/voice = 2, /obj/item/device/assembly/health = 2) + product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/coffee + name = "\improper Solar's Best Hot Drinks" + desc = "A vending machine which dispenses hot drinks." + product_ads = "Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies" + icon_state = "coffee" + icon_vend = "coffee-vend" products = list(/obj/item/reagent_containers/food/drinks/coffee = 25, /obj/item/reagent_containers/food/drinks/mug/tea = 25, /obj/item/reagent_containers/food/drinks/mug/coco = 25) - contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12) - refill_canister = /obj/item/vending_refill/coffee - -/obj/machinery/vending/snack - name = "\improper Getmore Chocolate Corp" - desc = "A snack machine courtesy of the Getmore Chocolate Corporation, based out of Mars." - product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" - product_ads = "The healthiest!;Award-winning chocolate bars!;Mmm! So good!;Oh my god it's so juicy!;Have a snack.;Snacks are good for you!;Have some more Getmore!;Best quality snacks straight from mars.;We love chocolate!;Try our new jerky!" - icon_state = "snack" + contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12) + refill_canister = /obj/item/vending_refill/coffee + +/obj/machinery/vending/snack + name = "\improper Getmore Chocolate Corp" + desc = "A snack machine courtesy of the Getmore Chocolate Corporation, based out of Mars." + product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" + product_ads = "The healthiest!;Award-winning chocolate bars!;Mmm! So good!;Oh my god it's so juicy!;Have a snack.;Snacks are good for you!;Have some more Getmore!;Best quality snacks straight from mars.;We love chocolate!;Try our new jerky!" + icon_state = "snack" products = list(/obj/item/reagent_containers/food/snacks/candy = 6, /obj/item/reagent_containers/food/drinks/dry_ramen = 6, /obj/item/reagent_containers/food/snacks/chips =6, /obj/item/reagent_containers/food/snacks/sosjerky = 6, /obj/item/reagent_containers/food/snacks/no_raisin = 6, /obj/item/reagent_containers/food/snacks/spacetwinkie = 6, - /obj/item/reagent_containers/food/snacks/cheesiehonkers = 6) - contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6) - refill_canister = /obj/item/vending_refill/snack - var/chef_compartment_access = "28" - -/obj/machinery/vending/snack/random - name = "\improper Random Snackies" - desc = "Uh oh!" - -/obj/machinery/vending/snack/random/Initialize() - ..() - var/T = pick(subtypesof(/obj/machinery/vending/snack) - /obj/machinery/vending/snack/random) - new T(get_turf(src)) - qdel(src) - -/obj/machinery/vending/snack/blue - icon_state = "snackblue" - -/obj/machinery/vending/snack/orange - icon_state = "snackorange" - -/obj/machinery/vending/snack/green - icon_state = "snackgreen" - -/obj/machinery/vending/snack/teal - icon_state = "snackteal" - -/obj/machinery/vending/sustenance - name = "\improper Sustenance Vendor" - desc = "A vending machine which vends food, as required by section 47-C of the NT's Prisoner Ethical Treatment Agreement." - product_slogans = "Enjoy your meal.;Enough calories to support strenuous labor." - product_ads = "Sufficiently healthy.;Efficiently produced tofu!;Mmm! So good!;Have a meal.;You need food to live!;Have some more candy corn!;Try our new ice cups!" - icon_state = "sustenance" - products = list(/obj/item/reagent_containers/food/snacks/tofu = 24, - /obj/item/reagent_containers/food/drinks/ice = 12, + /obj/item/reagent_containers/food/snacks/cheesiehonkers = 6) + contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6) + refill_canister = /obj/item/vending_refill/snack + var/chef_compartment_access = "28" + +/obj/machinery/vending/snack/random + name = "\improper Random Snackies" + desc = "Uh oh!" + +/obj/machinery/vending/snack/random/Initialize() + ..() + var/T = pick(subtypesof(/obj/machinery/vending/snack) - /obj/machinery/vending/snack/random) + new T(get_turf(src)) + qdel(src) + +/obj/machinery/vending/snack/blue + icon_state = "snackblue" + +/obj/machinery/vending/snack/orange + icon_state = "snackorange" + +/obj/machinery/vending/snack/green + icon_state = "snackgreen" + +/obj/machinery/vending/snack/teal + icon_state = "snackteal" + +/obj/machinery/vending/sustenance + name = "\improper Sustenance Vendor" + desc = "A vending machine which vends food, as required by section 47-C of the NT's Prisoner Ethical Treatment Agreement." + product_slogans = "Enjoy your meal.;Enough calories to support strenuous labor." + product_ads = "Sufficiently healthy.;Efficiently produced tofu!;Mmm! So good!;Have a meal.;You need food to live!;Have some more candy corn!;Try our new ice cups!" + icon_state = "sustenance" + products = list(/obj/item/reagent_containers/food/snacks/tofu = 24, + /obj/item/reagent_containers/food/drinks/ice = 12, /obj/item/reagent_containers/food/snacks/candy_corn = 6) - contraband = list(/obj/item/kitchen/knife = 6, - /obj/item/reagent_containers/food/drinks/coffee = 12, - /obj/item/tank/internals/emergency_oxygen = 6, - /obj/item/clothing/mask/breath = 6) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/cola - name = "\improper Robust Softdrinks" - desc = "A softdrink vendor provided by Robust Industries, LLC." - icon_state = "Cola_Machine" - product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!" - product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space." + contraband = list(/obj/item/kitchen/knife = 6, + /obj/item/reagent_containers/food/drinks/coffee = 12, + /obj/item/tank/internals/emergency_oxygen = 6, + /obj/item/clothing/mask/breath = 6) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/cola + name = "\improper Robust Softdrinks" + desc = "A softdrink vendor provided by Robust Industries, LLC." + icon_state = "Cola_Machine" + product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!" + product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space." products = list(/obj/item/reagent_containers/food/drinks/soda_cans/cola = 10, /obj/item/reagent_containers/food/drinks/soda_cans/space_mountain_wind = 10, /obj/item/reagent_containers/food/drinks/soda_cans/dr_gibb = 10, /obj/item/reagent_containers/food/drinks/soda_cans/starkist = 10, /obj/item/reagent_containers/food/drinks/soda_cans/space_up = 10, /obj/item/reagent_containers/food/drinks/soda_cans/pwr_game = 10, /obj/item/reagent_containers/food/drinks/soda_cans/lemon_lime = 10, /obj/item/reagent_containers/glass/beaker/waterbottle = 10) contraband = list(/obj/item/reagent_containers/food/drinks/soda_cans/thirteenloko = 6, /obj/item/reagent_containers/food/drinks/soda_cans/shamblers = 6) premium = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/nuka_cola = 1, /obj/item/reagent_containers/food/drinks/soda_cans/air = 1) - refill_canister = /obj/item/vending_refill/cola - -/obj/machinery/vending/cola/random - name = "\improper Random Drinkies" - desc = "Uh oh!" - -/obj/machinery/vending/cola/random/Initialize() + refill_canister = /obj/item/vending_refill/cola + +/obj/machinery/vending/cola/random + name = "\improper Random Drinkies" + desc = "Uh oh!" + +/obj/machinery/vending/cola/random/Initialize() . = ..() - var/T = pick(subtypesof(/obj/machinery/vending/cola) - /obj/machinery/vending/cola/random) - new T(get_turf(src)) - qdel(src) - -/obj/machinery/vending/cola/blue - icon_state = "Cola_Machine" - -/obj/machinery/vending/cola/black - icon_state = "cola_black" - -/obj/machinery/vending/cola/red - icon_state = "red_cola" - name = "\improper Space Cola Vendor" - desc = "It vends cola, in space." - product_slogans = "Cola in space!" - -/obj/machinery/vending/cola/space_up - icon_state = "space_up" - name = "\improper Space-up! Vendor" - desc = "Indulge in an explosion of flavor." - product_slogans = "Space-up! Like a hull breach in your mouth." - -/obj/machinery/vending/cola/starkist - icon_state = "starkist" - name = "\improper Star-kist Vendor" - desc = "The taste of a star in liquid form." - product_slogans = "Drink the stars! Star-kist!" - -/obj/machinery/vending/cola/sodie - icon_state = "soda" - -/obj/machinery/vending/cola/pwr_game - icon_state = "pwr_game" - name = "\improper Pwr Game Vendor" - desc = "You want it, we got it. Brought to you in partnership with Vlad's Salads." - product_slogans = "The POWER that gamers crave! PWR GAME!" - -/obj/machinery/vending/cola/shamblers - name = "\improper Shambler's Vendor" - desc = "~Shake me up some of that Shambler's Juice!~" - icon_state = "shamblers_juice" + var/T = pick(subtypesof(/obj/machinery/vending/cola) - /obj/machinery/vending/cola/random) + new T(get_turf(src)) + qdel(src) + +/obj/machinery/vending/cola/blue + icon_state = "Cola_Machine" + +/obj/machinery/vending/cola/black + icon_state = "cola_black" + +/obj/machinery/vending/cola/red + icon_state = "red_cola" + name = "\improper Space Cola Vendor" + desc = "It vends cola, in space." + product_slogans = "Cola in space!" + +/obj/machinery/vending/cola/space_up + icon_state = "space_up" + name = "\improper Space-up! Vendor" + desc = "Indulge in an explosion of flavor." + product_slogans = "Space-up! Like a hull breach in your mouth." + +/obj/machinery/vending/cola/starkist + icon_state = "starkist" + name = "\improper Star-kist Vendor" + desc = "The taste of a star in liquid form." + product_slogans = "Drink the stars! Star-kist!" + +/obj/machinery/vending/cola/sodie + icon_state = "soda" + +/obj/machinery/vending/cola/pwr_game + icon_state = "pwr_game" + name = "\improper Pwr Game Vendor" + desc = "You want it, we got it. Brought to you in partnership with Vlad's Salads." + product_slogans = "The POWER that gamers crave! PWR GAME!" + +/obj/machinery/vending/cola/shamblers + name = "\improper Shambler's Vendor" + desc = "~Shake me up some of that Shambler's Juice!~" + icon_state = "shamblers_juice" products = list(/obj/item/reagent_containers/food/drinks/soda_cans/cola = 10, /obj/item/reagent_containers/food/drinks/soda_cans/space_mountain_wind = 10, /obj/item/reagent_containers/food/drinks/soda_cans/dr_gibb = 10, /obj/item/reagent_containers/food/drinks/soda_cans/starkist = 10, /obj/item/reagent_containers/food/drinks/soda_cans/space_up = 10, /obj/item/reagent_containers/food/drinks/soda_cans/pwr_game = 10, /obj/item/reagent_containers/food/drinks/soda_cans/lemon_lime = 10, /obj/item/reagent_containers/food/drinks/soda_cans/shamblers = 10) - product_slogans = "~Shake me up some of that Shambler's Juice!~" - product_ads = "Refreshing!;Jyrbv dv lg jfdv fw kyrk Jyrdscvi'j Alztv!;Over 1 trillion souls drank!;Thirsty? Nyp efk uizeb kyv uribevjj?;Kyv Jyrdscvi uizebj kyv ezxyk!;Drink up!;Krjkp." - - -//This one's from bay12 -/obj/machinery/vending/cart - name = "\improper PTech" - desc = "Cartridges for PDAs" - product_slogans = "Carts to go!" - icon_state = "cart" - icon_deny = "cart-deny" + product_slogans = "~Shake me up some of that Shambler's Juice!~" + product_ads = "Refreshing!;Jyrbv dv lg jfdv fw kyrk Jyrdscvi'j Alztv!;Over 1 trillion souls drank!;Thirsty? Nyp efk uizeb kyv uribevjj?;Kyv Jyrdscvi uizebj kyv ezxyk!;Drink up!;Krjkp." + + +//This one's from bay12 +/obj/machinery/vending/cart + name = "\improper PTech" + desc = "Cartridges for PDAs" + product_slogans = "Carts to go!" + icon_state = "cart" + icon_deny = "cart-deny" products = list(/obj/item/cartridge/medical = 10, /obj/item/cartridge/engineering = 10, /obj/item/cartridge/security = 10, /obj/item/cartridge/janitor = 10, /obj/item/cartridge/signal/toxins = 10, /obj/item/device/pda/heads = 10, /obj/item/cartridge/captain = 3, /obj/item/cartridge/quartermaster = 10) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/liberationstation - name = "\improper Liberation Station" - desc = "An overwhelming amount of ancient patriotism washes over you just by looking at the machine." - icon_state = "liberationstation" - req_access_txt = "1" - product_slogans = "Liberation Station: Your one-stop shop for all things second ammendment!;Be a patriot today, pick up a gun!;Quality weapons for cheap prices!;Better dead than red!" - product_ads = "Float like an astronaut, sting like a bullet!;Express your second ammendment today!;Guns don't kill people, but you can!;Who needs responsibilities when you have guns?" - vend_reply = "Remember the name: Liberation Station!" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/liberationstation + name = "\improper Liberation Station" + desc = "An overwhelming amount of ancient patriotism washes over you just by looking at the machine." + icon_state = "liberationstation" + req_access_txt = "1" + product_slogans = "Liberation Station: Your one-stop shop for all things second ammendment!;Be a patriot today, pick up a gun!;Quality weapons for cheap prices!;Better dead than red!" + product_ads = "Float like an astronaut, sting like a bullet!;Express your second ammendment today!;Guns don't kill people, but you can!;Who needs responsibilities when you have guns?" + vend_reply = "Remember the name: Liberation Station!" products = list(/obj/item/gun/ballistic/automatic/pistol/deagle/gold = 2, /obj/item/gun/ballistic/automatic/pistol/deagle/camo = 2, /obj/item/gun/ballistic/automatic/pistol/m1911 = 2, /obj/item/gun/ballistic/automatic/proto/unrestricted = 2, /obj/item/gun/ballistic/shotgun/automatic/combat = 2, /obj/item/gun/ballistic/automatic/gyropistol = 1, /obj/item/gun/ballistic/shotgun = 2, /obj/item/gun/ballistic/automatic/ar = 2) premium = list(/obj/item/ammo_box/magazine/smgm9mm = 2, /obj/item/ammo_box/magazine/m50 = 4, /obj/item/ammo_box/magazine/m45 = 2, /obj/item/ammo_box/magazine/m75 = 2) contraband = list(/obj/item/clothing/under/patriotsuit = 1, /obj/item/bedsheet/patriot = 3) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/cigarette - name = "\improper ShadyCigs Deluxe" - desc = "If you want to get cancer, might as well do it in style." - product_slogans = "Space cigs taste good like a cigarette should.;I'd rather toolbox than switch.;Smoke!;Don't believe the reports - smoke today!" - product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." - icon_state = "cigs" - products = list(/obj/item/storage/fancy/cigarettes = 5, - /obj/item/storage/fancy/cigarettes/cigpack_uplift = 3, - /obj/item/storage/fancy/cigarettes/cigpack_robust = 3, - /obj/item/storage/fancy/cigarettes/cigpack_carp = 3, - /obj/item/storage/fancy/cigarettes/cigpack_midori = 3, - /obj/item/storage/box/matches = 10, - /obj/item/lighter/greyscale = 4, - /obj/item/storage/fancy/rollingpapers = 5) - contraband = list(/obj/item/lighter = 3, /obj/item/clothing/mask/vape = 5) - premium = list(/obj/item/storage/fancy/cigarettes/cigpack_robustgold = 3, \ - /obj/item/storage/fancy/cigarettes/cigars = 1, /obj/item/storage/fancy/cigarettes/cigars/havana = 1, /obj/item/storage/fancy/cigarettes/cigars/cohiba = 1) - refill_canister = /obj/item/vending_refill/cigarette - -/obj/machinery/vending/cigarette/pre_throw(obj/item/I) - if(istype(I, /obj/item/lighter)) - var/obj/item/lighter/L = I - L.set_lit(TRUE) - -/obj/machinery/vending/medical - name = "\improper NanoMed Plus" - desc = "Medical drug dispenser." - icon_state = "med" - icon_deny = "med-deny" - product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?;Ping!" - req_access_txt = "5" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/cigarette + name = "\improper ShadyCigs Deluxe" + desc = "If you want to get cancer, might as well do it in style." + product_slogans = "Space cigs taste good like a cigarette should.;I'd rather toolbox than switch.;Smoke!;Don't believe the reports - smoke today!" + product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." + icon_state = "cigs" + products = list(/obj/item/storage/fancy/cigarettes = 5, + /obj/item/storage/fancy/cigarettes/cigpack_uplift = 3, + /obj/item/storage/fancy/cigarettes/cigpack_robust = 3, + /obj/item/storage/fancy/cigarettes/cigpack_carp = 3, + /obj/item/storage/fancy/cigarettes/cigpack_midori = 3, + /obj/item/storage/box/matches = 10, + /obj/item/lighter/greyscale = 4, + /obj/item/storage/fancy/rollingpapers = 5) + contraband = list(/obj/item/lighter = 3, /obj/item/clothing/mask/vape = 5) + premium = list(/obj/item/storage/fancy/cigarettes/cigpack_robustgold = 3, \ + /obj/item/storage/fancy/cigarettes/cigars = 1, /obj/item/storage/fancy/cigarettes/cigars/havana = 1, /obj/item/storage/fancy/cigarettes/cigars/cohiba = 1) + refill_canister = /obj/item/vending_refill/cigarette + +/obj/machinery/vending/cigarette/pre_throw(obj/item/I) + if(istype(I, /obj/item/lighter)) + var/obj/item/lighter/L = I + L.set_lit(TRUE) + +/obj/machinery/vending/medical + name = "\improper NanoMed Plus" + desc = "Medical drug dispenser." + icon_state = "med" + icon_deny = "med-deny" + product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?;Ping!" + req_access_txt = "5" products = list(/obj/item/reagent_containers/syringe = 12, /obj/item/reagent_containers/dropper = 3, /obj/item/stack/medical/gauze = 8, /obj/item/reagent_containers/pill/patch/styptic = 5, /obj/item/reagent_containers/pill/insulin = 10, /obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/glass/bottle/charcoal = 4, /obj/item/reagent_containers/spray/medical/sterilizer = 1, /obj/item/reagent_containers/glass/bottle/epinephrine = 4, /obj/item/reagent_containers/glass/bottle/morphine = 4, /obj/item/reagent_containers/glass/bottle/salglu_solution = 3, - /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2) + /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2, /obj/item/pinpointer/crew = 2) contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6) premium = list(/obj/item/storage/box/hug/medical = 1, /obj/item/reagent_containers/hypospray/medipen = 3, /obj/item/storage/belt/medical = 3, /obj/item/wrench/medical = 1) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - refill_canister = /obj/item/vending_refill/medical - -//This one's from bay12 -/obj/machinery/vending/plasmaresearch - name = "\improper Toximate 3000" - desc = "All the fine parts you need in one vending machine!" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + refill_canister = /obj/item/vending_refill/medical + +//This one's from bay12 +/obj/machinery/vending/plasmaresearch + name = "\improper Toximate 3000" + desc = "All the fine parts you need in one vending machine!" products = list(/obj/item/clothing/under/rank/scientist = 6, /obj/item/clothing/suit/bio_suit = 6, /obj/item/clothing/head/bio_hood = 6, /obj/item/device/transfer_valve = 6, /obj/item/device/assembly/timer = 6, /obj/item/device/assembly/signaler = 6, /obj/item/device/assembly/prox_sensor = 6, /obj/item/device/assembly/igniter = 6) - contraband = list(/obj/item/device/assembly/health = 3) - -/obj/machinery/vending/wallmed - name = "\improper NanoMed" - desc = "Wall-mounted Medical Equipment dispenser." - icon_state = "wallmed" - icon_deny = "wallmed-deny" + contraband = list(/obj/item/device/assembly/health = 3) + +/obj/machinery/vending/wallmed + name = "\improper NanoMed" + desc = "Wall-mounted Medical Equipment dispenser." + icon_state = "wallmed" + icon_deny = "wallmed-deny" density = FALSE products = list(/obj/item/reagent_containers/syringe = 3, /obj/item/reagent_containers/pill/patch/styptic = 5, /obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/pill/charcoal = 2, - /obj/item/reagent_containers/spray/medical/sterilizer = 1) + /obj/item/reagent_containers/spray/medical/sterilizer = 1) contraband = list(/obj/item/reagent_containers/pill/tox = 2, /obj/item/reagent_containers/pill/morphine = 2) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - refill_canister = /obj/item/vending_refill/medical - refill_count = 1 - -/obj/machinery/vending/security - name = "\improper SecTech" - desc = "A security equipment vendor" - product_ads = "Crack capitalist skulls!;Beat some heads in!;Don't forget - harm is good!;Your weapons are right here.;Handcuffs!;Freeze, scumbag!;Don't tase me bro!;Tase them, bro.;Why not have a donut?" - icon_state = "sec" - icon_deny = "sec-deny" - req_access_txt = "1" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + refill_canister = /obj/item/vending_refill/medical + refill_count = 1 + +/obj/machinery/vending/security + name = "\improper SecTech" + desc = "A security equipment vendor" + product_ads = "Crack capitalist skulls!;Beat some heads in!;Don't forget - harm is good!;Your weapons are right here.;Handcuffs!;Freeze, scumbag!;Don't tase me bro!;Tase them, bro.;Why not have a donut?" + icon_state = "sec" + icon_deny = "sec-deny" + req_access_txt = "1" products = list(/obj/item/restraints/handcuffs = 8, /obj/item/restraints/handcuffs/cable/zipties = 10, /obj/item/grenade/flashbang = 4, /obj/item/device/assembly/flash/handheld = 5, /obj/item/reagent_containers/food/snacks/donut = 12, /obj/item/storage/box/evidence = 6, /obj/item/device/flashlight/seclite = 4, /obj/item/restraints/legcuffs/bola/energy = 7) contraband = list(/obj/item/clothing/glasses/sunglasses = 2, /obj/item/storage/fancy/donut_box = 2) - premium = list(/obj/item/coin/antagtoken = 1) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/security/pre_throw(obj/item/I) - if(istype(I, /obj/item/grenade)) - var/obj/item/grenade/G = I - G.preprime() - else if(istype(I, /obj/item/device/flashlight)) - var/obj/item/device/flashlight/F = I - F.on = TRUE - F.update_brightness() - -/obj/machinery/vending/hydronutrients - name = "\improper NutriMax" - desc = "A plant nutrients vendor." - product_slogans = "Aren't you glad you don't have to fertilize the natural way?;Now with 50% less stink!;Plants are people too!" - product_ads = "We like plants!;Don't you want some?;The greenest thumbs ever.;We like big plants.;Soft soil..." - icon_state = "nutri" - icon_deny = "nutri-deny" + premium = list(/obj/item/coin/antagtoken = 1) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/security/pre_throw(obj/item/I) + if(istype(I, /obj/item/grenade)) + var/obj/item/grenade/G = I + G.preprime() + else if(istype(I, /obj/item/device/flashlight)) + var/obj/item/device/flashlight/F = I + F.on = TRUE + F.update_brightness() + +/obj/machinery/vending/hydronutrients + name = "\improper NutriMax" + desc = "A plant nutrients vendor." + product_slogans = "Aren't you glad you don't have to fertilize the natural way?;Now with 50% less stink!;Plants are people too!" + product_ads = "We like plants!;Don't you want some?;The greenest thumbs ever.;We like big plants.;Soft soil..." + icon_state = "nutri" + icon_deny = "nutri-deny" products = list(/obj/item/reagent_containers/glass/bottle/nutrient/ez = 30, /obj/item/reagent_containers/glass/bottle/nutrient/l4z = 20, /obj/item/reagent_containers/glass/bottle/nutrient/rh = 10, /obj/item/reagent_containers/spray/pestspray = 20, /obj/item/reagent_containers/syringe = 5, /obj/item/storage/bag/plants = 5, /obj/item/cultivator = 3, /obj/item/shovel/spade = 3, /obj/item/device/plant_analyzer = 4) contraband = list(/obj/item/reagent_containers/glass/bottle/ammonia = 10, /obj/item/reagent_containers/glass/bottle/diethylamine = 5) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/hydroseeds - name = "\improper MegaSeed Servitor" - desc = "When you need seeds fast!" - product_slogans = "THIS'S WHERE TH' SEEDS LIVE! GIT YOU SOME!;Hands down the best seed selection on the station!;Also certain mushroom varieties available, more for experts! Get certified today!" - product_ads = "We like plants!;Grow some crops!;Grow, baby, growww!;Aw h'yeah son!" - icon_state = "seeds" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/hydroseeds + name = "\improper MegaSeed Servitor" + desc = "When you need seeds fast!" + product_slogans = "THIS'S WHERE TH' SEEDS LIVE! GIT YOU SOME!;Hands down the best seed selection on the station!;Also certain mushroom varieties available, more for experts! Get certified today!" + product_ads = "We like plants!;Grow some crops!;Grow, baby, growww!;Aw h'yeah son!" + icon_state = "seeds" products = list(/obj/item/seeds/ambrosia = 3, /obj/item/seeds/apple = 3, /obj/item/seeds/banana = 3, /obj/item/seeds/berry = 3, /obj/item/seeds/cabbage = 3, /obj/item/seeds/carrot = 3, /obj/item/seeds/cherry = 3, /obj/item/seeds/chanter = 3, /obj/item/seeds/chili = 3, /obj/item/seeds/cocoapod = 3, /obj/item/seeds/coffee = 3, /obj/item/seeds/corn = 3, @@ -952,31 +952,31 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C /obj/item/seeds/tower = 3, /obj/item/seeds/watermelon = 3, /obj/item/seeds/wheat = 3, /obj/item/seeds/whitebeet = 3) contraband = list(/obj/item/seeds/amanita = 2, /obj/item/seeds/glowshroom = 2, /obj/item/seeds/liberty = 2, /obj/item/seeds/nettle = 2, /obj/item/seeds/plump = 2, /obj/item/seeds/reishi = 2, /obj/item/seeds/cannabis = 3, /obj/item/seeds/starthistle = 2, - /obj/item/seeds/random = 2) - premium = list(/obj/item/reagent_containers/spray/waterflower = 1) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/magivend - name = "\improper MagiVend" - desc = "A magic vending machine." - icon_state = "MagiVend" - product_slogans = "Sling spells the proper way with MagiVend!;Be your own Houdini! Use MagiVend!" - vend_reply = "Have an enchanted evening!" - product_ads = "FJKLFJSD;AJKFLBJAKL;1234 LOONIES LOL!;>MFW;Kill them fuckers!;GET DAT FUKKEN DISK;HONK!;EI NATH;Destroy the station!;Admin conspiracies since forever!;Space-time bending hardware!" + /obj/item/seeds/random = 2) + premium = list(/obj/item/reagent_containers/spray/waterflower = 1) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/magivend + name = "\improper MagiVend" + desc = "A magic vending machine." + icon_state = "MagiVend" + product_slogans = "Sling spells the proper way with MagiVend!;Be your own Houdini! Use MagiVend!" + vend_reply = "Have an enchanted evening!" + product_ads = "FJKLFJSD;AJKFLBJAKL;1234 LOONIES LOL!;>MFW;Kill them fuckers!;GET DAT FUKKEN DISK;HONK!;EI NATH;Destroy the station!;Admin conspiracies since forever!;Space-time bending hardware!" products = list(/obj/item/clothing/head/wizard = 1, /obj/item/clothing/suit/wizrobe = 1, /obj/item/clothing/head/wizard/red = 1, /obj/item/clothing/suit/wizrobe/red = 1, /obj/item/clothing/head/wizard/yellow = 1, /obj/item/clothing/suit/wizrobe/yellow = 1, /obj/item/clothing/shoes/sandal/magic = 1, /obj/item/staff = 2) - contraband = list(/obj/item/reagent_containers/glass/bottle/wizarditis = 1) //No one can get to the machine to hack it anyways; for the lulz - Microwave - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/autodrobe - name = "\improper AutoDrobe" - desc = "A vending machine for costumes." - icon_state = "theater" - icon_deny = "theater-deny" - req_access_txt = "46" //Theatre access needed, unless hacked. - product_slogans = "Dress for success!;Suited and booted!;It's show time!;Why leave style up to fate? Use AutoDrobe!" - vend_reply = "Thank you for using AutoDrobe!" + contraband = list(/obj/item/reagent_containers/glass/bottle/wizarditis = 1) //No one can get to the machine to hack it anyways; for the lulz - Microwave + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/autodrobe + name = "\improper AutoDrobe" + desc = "A vending machine for costumes." + icon_state = "theater" + icon_deny = "theater-deny" + req_access_txt = "46" //Theatre access needed, unless hacked. + product_slogans = "Dress for success!;Suited and booted!;It's show time!;Why leave style up to fate? Use AutoDrobe!" + vend_reply = "Thank you for using AutoDrobe!" products = list(/obj/item/clothing/suit/chickensuit = 1, /obj/item/clothing/head/chicken = 1, /obj/item/clothing/under/gladiator = 1, /obj/item/clothing/head/helmet/gladiator = 1, /obj/item/clothing/under/gimmick/rank/captain/suit = 1, /obj/item/clothing/head/flatcap = 1, /obj/item/clothing/suit/toggle/labcoat/mad = 1, /obj/item/clothing/shoes/jackboots = 1, @@ -985,7 +985,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C /obj/item/clothing/glasses/monocle =1, /obj/item/clothing/head/bowler = 1, /obj/item/cane = 1, /obj/item/clothing/under/sl_suit = 1, /obj/item/clothing/mask/fakemoustache = 1, /obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1, /obj/item/clothing/head/plaguedoctorhat = 1, /obj/item/clothing/mask/gas/plaguedoctor = 1, /obj/item/clothing/suit/toggle/owlwings = 1, /obj/item/clothing/under/owl = 1, /obj/item/clothing/mask/gas/owl_mask = 1, - /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1, /obj/item/clothing/under/griffin = 1, /obj/item/clothing/shoes/griffin = 1, /obj/item/clothing/head/griffin = 1, + /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1, /obj/item/clothing/under/griffin = 1, /obj/item/clothing/shoes/griffin = 1, /obj/item/clothing/head/griffin = 1, /obj/item/clothing/suit/apron = 1, /obj/item/clothing/under/waiter = 1, /obj/item/clothing/suit/jacket/miljacket = 1, /obj/item/clothing/under/pirate = 1, /obj/item/clothing/suit/pirate = 1, /obj/item/clothing/head/pirate = 1, /obj/item/clothing/head/bandana = 1, /obj/item/clothing/head/bandana = 1, /obj/item/clothing/under/soviet = 1, /obj/item/clothing/head/ushanka = 1, /obj/item/clothing/suit/imperium_monk = 1, @@ -993,132 +993,132 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C /obj/item/clothing/suit/wizrobe/marisa/fake = 1, /obj/item/clothing/under/sundress = 1, /obj/item/clothing/head/witchwig = 1, /obj/item/staff/broom = 1, /obj/item/clothing/suit/wizrobe/fake = 1, /obj/item/clothing/head/wizard/fake = 1, /obj/item/staff = 3, /obj/item/clothing/mask/gas/sexyclown = 1, /obj/item/clothing/under/rank/clown/sexy = 1, /obj/item/clothing/mask/gas/sexymime = 1, /obj/item/clothing/under/sexymime = 1, /obj/item/clothing/mask/rat/bat = 1, /obj/item/clothing/mask/rat/bee = 1, /obj/item/clothing/mask/rat/bear = 1, /obj/item/clothing/mask/rat/raven = 1, /obj/item/clothing/mask/rat/jackal = 1, /obj/item/clothing/mask/rat/fox = 1, /obj/item/clothing/mask/rat/tribal = 1, /obj/item/clothing/mask/rat = 1, /obj/item/clothing/suit/apron/overalls = 1, - /obj/item/clothing/head/rabbitears =1, /obj/item/clothing/head/sombrero = 1, /obj/item/clothing/head/sombrero/green = 1, /obj/item/clothing/suit/poncho = 1, - /obj/item/clothing/suit/poncho/green = 1, /obj/item/clothing/suit/poncho/red = 1, + /obj/item/clothing/head/rabbitears =1, /obj/item/clothing/head/sombrero = 1, /obj/item/clothing/head/sombrero/green = 1, /obj/item/clothing/suit/poncho = 1, + /obj/item/clothing/suit/poncho/green = 1, /obj/item/clothing/suit/poncho/red = 1, /obj/item/clothing/under/maid = 1, /obj/item/clothing/under/janimaid = 1, /obj/item/clothing/glasses/cold=1, /obj/item/clothing/glasses/heat=1, - /obj/item/clothing/suit/whitedress = 1, - /obj/item/clothing/under/jester = 1, /obj/item/clothing/head/jester = 1, - /obj/item/clothing/under/villain = 1, + /obj/item/clothing/suit/whitedress = 1, + /obj/item/clothing/under/jester = 1, /obj/item/clothing/head/jester = 1, + /obj/item/clothing/under/villain = 1, /obj/item/clothing/shoes/singery = 1, /obj/item/clothing/under/singery = 1, /obj/item/clothing/shoes/singerb = 1, /obj/item/clothing/under/singerb = 1, - /obj/item/clothing/suit/hooded/carp_costume = 1, - /obj/item/clothing/suit/hooded/ian_costume = 1, - /obj/item/clothing/suit/hooded/bee_costume = 1, - /obj/item/clothing/suit/snowman = 1, - /obj/item/clothing/head/snowman = 1, - /obj/item/clothing/mask/joy = 1, - /obj/item/clothing/head/cueball = 1, - /obj/item/clothing/under/scratch = 1, + /obj/item/clothing/suit/hooded/carp_costume = 1, + /obj/item/clothing/suit/hooded/ian_costume = 1, + /obj/item/clothing/suit/hooded/bee_costume = 1, + /obj/item/clothing/suit/snowman = 1, + /obj/item/clothing/head/snowman = 1, + /obj/item/clothing/mask/joy = 1, + /obj/item/clothing/head/cueball = 1, + /obj/item/clothing/under/scratch = 1, /obj/item/clothing/under/sailor = 1, /obj/item/clothing/ears/headphones = 2) contraband = list(/obj/item/clothing/suit/judgerobe = 1, /obj/item/clothing/head/powdered_wig = 1, /obj/item/gun/magic/wand = 2, /obj/item/clothing/glasses/sunglasses/garb = 2, /obj/item/clothing/glasses/sunglasses/blindfold = 1, /obj/item/clothing/mask/muzzle = 2) - premium = list(/obj/item/clothing/suit/pirate/captain = 2, /obj/item/clothing/head/pirate/captain = 2, /obj/item/clothing/head/helmet/roman = 1, /obj/item/clothing/head/helmet/roman/legionaire = 1, /obj/item/clothing/under/roman = 1, /obj/item/clothing/shoes/roman = 1, /obj/item/shield/riot/roman = 1, /obj/item/skub = 1) - refill_canister = /obj/item/vending_refill/autodrobe - -/obj/machinery/vending/dinnerware - name = "\improper Plasteel Chef's Dinnerware Vendor" - desc = "A kitchen and restaurant equipment vendor" - product_ads = "Mm, food stuffs!;Food and food accessories.;Get your plates!;You like forks?;I like forks.;Woo, utensils.;You don't really need these..." - icon_state = "dinnerware" + premium = list(/obj/item/clothing/suit/pirate/captain = 2, /obj/item/clothing/head/pirate/captain = 2, /obj/item/clothing/head/helmet/roman = 1, /obj/item/clothing/head/helmet/roman/legionaire = 1, /obj/item/clothing/under/roman = 1, /obj/item/clothing/shoes/roman = 1, /obj/item/shield/riot/roman = 1, /obj/item/skub = 1) + refill_canister = /obj/item/vending_refill/autodrobe + +/obj/machinery/vending/dinnerware + name = "\improper Plasteel Chef's Dinnerware Vendor" + desc = "A kitchen and restaurant equipment vendor" + product_ads = "Mm, food stuffs!;Food and food accessories.;Get your plates!;You like forks?;I like forks.;Woo, utensils.;You don't really need these..." + icon_state = "dinnerware" products = list(/obj/item/storage/bag/tray = 8, /obj/item/kitchen/fork = 6, /obj/item/kitchen/knife = 6, /obj/item/kitchen/rollingpin = 2, /obj/item/reagent_containers/food/drinks/drinkingglass = 8, /obj/item/clothing/suit/apron/chef = 2, /obj/item/reagent_containers/food/condiment/pack/ketchup = 5, /obj/item/reagent_containers/food/condiment/pack/hotsauce = 5, /obj/item/reagent_containers/food/condiment/saltshaker = 5, /obj/item/reagent_containers/food/condiment/peppermill = 5, /obj/item/reagent_containers/glass/bowl = 20) - contraband = list(/obj/item/kitchen/rollingpin = 2, /obj/item/kitchen/knife/butcher = 2) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/sovietsoda - name = "\improper BODA" - desc = "Old sweet water vending machine" - icon_state = "sovietsoda" - product_ads = "For Tsar and Country.;Have you fulfilled your nutrition quota today?;Very nice!;We are simple people, for this is all we eat.;If there is a person, there is a problem. If there is no person, then there is no problem." - products = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/soda = 30) - contraband = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/cola = 20) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/tool - name = "\improper YouTool" - desc = "Tools for tools." - icon_state = "tool" - icon_deny = "tool-deny" - //req_access_txt = "12" //Maintenance access - products = list( - /obj/item/stack/cable_coil/random = 10, - /obj/item/crowbar = 5, - /obj/item/weldingtool = 3, - /obj/item/wirecutters = 5, - /obj/item/wrench = 5, - /obj/item/device/analyzer = 5, - /obj/item/device/t_scanner = 5, - /obj/item/screwdriver = 5, - /obj/item/device/flashlight/glowstick = 3, - /obj/item/device/flashlight/glowstick/red = 3, - /obj/item/device/flashlight = 5) - contraband = list( - /obj/item/weldingtool/hugetank = 2, - /obj/item/clothing/gloves/color/fyellow = 2) - premium = list( - /obj/item/clothing/gloves/color/yellow = 1) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 70) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/engivend - name = "\improper Engi-Vend" - desc = "Spare tool vending. What? Did you expect some witty description?" - icon_state = "engivend" - icon_deny = "engivend-deny" - req_access_txt = "11" //Engineering Equipment access + contraband = list(/obj/item/kitchen/rollingpin = 2, /obj/item/kitchen/knife/butcher = 2) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/sovietsoda + name = "\improper BODA" + desc = "Old sweet water vending machine" + icon_state = "sovietsoda" + product_ads = "For Tsar and Country.;Have you fulfilled your nutrition quota today?;Very nice!;We are simple people, for this is all we eat.;If there is a person, there is a problem. If there is no person, then there is no problem." + products = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/soda = 30) + contraband = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/cola = 20) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/tool + name = "\improper YouTool" + desc = "Tools for tools." + icon_state = "tool" + icon_deny = "tool-deny" + //req_access_txt = "12" //Maintenance access + products = list( + /obj/item/stack/cable_coil/random = 10, + /obj/item/crowbar = 5, + /obj/item/weldingtool = 3, + /obj/item/wirecutters = 5, + /obj/item/wrench = 5, + /obj/item/device/analyzer = 5, + /obj/item/device/t_scanner = 5, + /obj/item/screwdriver = 5, + /obj/item/device/flashlight/glowstick = 3, + /obj/item/device/flashlight/glowstick/red = 3, + /obj/item/device/flashlight = 5) + contraband = list( + /obj/item/weldingtool/hugetank = 2, + /obj/item/clothing/gloves/color/fyellow = 2) + premium = list( + /obj/item/clothing/gloves/color/yellow = 1) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 70) + resistance_flags = FIRE_PROOF + +/obj/machinery/vending/engivend + name = "\improper Engi-Vend" + desc = "Spare tool vending. What? Did you expect some witty description?" + icon_state = "engivend" + icon_deny = "engivend-deny" + req_access_txt = "11" //Engineering Equipment access products = list(/obj/item/clothing/glasses/meson/engine = 2, /obj/item/device/multitool = 4, /obj/item/electronics/airlock = 10, /obj/item/electronics/apc = 10, /obj/item/electronics/airalarm = 10, /obj/item/stock_parts/cell/high = 10, /obj/item/construction/rcd/loaded = 3, /obj/item/device/geiger_counter = 5, /obj/item/grenade/chem_grenade/smart_metal_foam = 10) - contraband = list(/obj/item/stock_parts/cell/potato = 3) - premium = list(/obj/item/storage/belt/utility = 3, /obj/item/storage/box/smart_metal_foam = 1) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -//This one's from bay12 -/obj/machinery/vending/engineering - name = "\improper Robco Tool Maker" - desc = "Everything you need for do-it-yourself station repair." - icon_state = "engi" - icon_deny = "engi-deny" - req_access_txt = "11" + contraband = list(/obj/item/stock_parts/cell/potato = 3) + premium = list(/obj/item/storage/belt/utility = 3, /obj/item/storage/box/smart_metal_foam = 1) + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +//This one's from bay12 +/obj/machinery/vending/engineering + name = "\improper Robco Tool Maker" + desc = "Everything you need for do-it-yourself station repair." + icon_state = "engi" + icon_deny = "engi-deny" + req_access_txt = "11" products = list(/obj/item/clothing/under/rank/chief_engineer = 4, /obj/item/clothing/under/rank/engineer = 4, /obj/item/clothing/shoes/sneakers/orange = 4, /obj/item/clothing/head/hardhat = 4, /obj/item/storage/belt/utility = 4, /obj/item/clothing/glasses/meson/engine = 4, /obj/item/clothing/gloves/color/yellow = 4, /obj/item/screwdriver = 12, /obj/item/crowbar = 12, /obj/item/wirecutters = 12, /obj/item/device/multitool = 12, /obj/item/wrench = 12, /obj/item/device/t_scanner = 12, /obj/item/stock_parts/cell = 8, /obj/item/weldingtool = 8, /obj/item/clothing/head/welding = 8, /obj/item/light/tube = 10, /obj/item/clothing/suit/fire = 4, /obj/item/stock_parts/scanning_module = 5, /obj/item/stock_parts/micro_laser = 5, /obj/item/stock_parts/matter_bin = 5, /obj/item/stock_parts/manipulator = 5, /obj/item/stock_parts/console_screen = 5) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -//This one's from bay12 -/obj/machinery/vending/robotics - name = "\improper Robotech Deluxe" - desc = "All the tools you need to create your own robot army." - icon_state = "robotics" - icon_deny = "robotics-deny" - req_access_txt = "29" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +//This one's from bay12 +/obj/machinery/vending/robotics + name = "\improper Robotech Deluxe" + desc = "All the tools you need to create your own robot army." + icon_state = "robotics" + icon_deny = "robotics-deny" + req_access_txt = "29" products = list(/obj/item/clothing/suit/toggle/labcoat = 4, /obj/item/clothing/under/rank/roboticist = 4, /obj/item/stack/cable_coil = 4, /obj/item/device/assembly/flash/handheld = 4, /obj/item/stock_parts/cell/high = 12, /obj/item/device/assembly/prox_sensor = 3, /obj/item/device/assembly/signaler = 3, /obj/item/device/healthanalyzer = 3, /obj/item/scalpel = 2, /obj/item/circular_saw = 2, /obj/item/tank/internals/anesthetic = 2, /obj/item/clothing/mask/breath/medical = 5, /obj/item/screwdriver = 5, /obj/item/crowbar = 5) - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -//DON'T FORGET TO CHANGE THE REFILL SIZE IF YOU CHANGE THE MACHINE'S CONTENTS! -/obj/machinery/vending/clothing - name = "ClothesMate" //renamed to make the slogan rhyme - desc = "A vending machine for clothing." - icon_state = "clothes" - product_slogans = "Dress for success!;Prepare to look swagalicious!;Look at all this free swag!;Why leave style up to fate? Use the ClothesMate!" - vend_reply = "Thank you for using the ClothesMate!" + armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + +//DON'T FORGET TO CHANGE THE REFILL SIZE IF YOU CHANGE THE MACHINE'S CONTENTS! +/obj/machinery/vending/clothing + name = "ClothesMate" //renamed to make the slogan rhyme + desc = "A vending machine for clothing." + icon_state = "clothes" + product_slogans = "Dress for success!;Prepare to look swagalicious!;Look at all this free swag!;Why leave style up to fate? Use the ClothesMate!" + vend_reply = "Thank you for using the ClothesMate!" products = list(/obj/item/clothing/head/that=2, /obj/item/clothing/head/fedora=1, /obj/item/clothing/glasses/monocle=1, - /obj/item/clothing/suit/jacket=2, /obj/item/clothing/suit/jacket/puffer/vest=2, /obj/item/clothing/suit/jacket/puffer=2, + /obj/item/clothing/suit/jacket=2, /obj/item/clothing/suit/jacket/puffer/vest=2, /obj/item/clothing/suit/jacket/puffer=2, /obj/item/clothing/under/suit_jacket/navy=1, /obj/item/clothing/under/suit_jacket/really_black=1, /obj/item/clothing/under/suit_jacket/burgundy=1, /obj/item/clothing/under/suit_jacket/charcoal=1, /obj/item/clothing/under/suit_jacket/white=1, /obj/item/clothing/under/kilt=1, /obj/item/clothing/under/overalls=1, /obj/item/clothing/under/sl_suit=1, /obj/item/clothing/under/pants/jeans=3, /obj/item/clothing/under/pants/classicjeans=2, /obj/item/clothing/under/pants/camo = 1, /obj/item/clothing/under/pants/blackjeans=2, /obj/item/clothing/under/pants/khaki=2, /obj/item/clothing/under/pants/white=2, /obj/item/clothing/under/pants/red=1, /obj/item/clothing/under/pants/black=2, /obj/item/clothing/under/pants/tan=2, /obj/item/clothing/under/pants/track=1, /obj/item/clothing/suit/jacket/miljacket = 1, - /obj/item/clothing/neck/tie/blue=1, /obj/item/clothing/neck/tie/red=1, /obj/item/clothing/neck/tie/black=1, /obj/item/clothing/neck/tie/horrible=1, + /obj/item/clothing/neck/tie/blue=1, /obj/item/clothing/neck/tie/red=1, /obj/item/clothing/neck/tie/black=1, /obj/item/clothing/neck/tie/horrible=1, /obj/item/clothing/neck/scarf/red=1, /obj/item/clothing/neck/scarf/green=1, /obj/item/clothing/neck/scarf/darkblue=1, /obj/item/clothing/neck/scarf/purple=1, /obj/item/clothing/neck/scarf/yellow=1, /obj/item/clothing/neck/scarf/orange=1, /obj/item/clothing/neck/scarf/cyan=1, /obj/item/clothing/neck/scarf=1, /obj/item/clothing/neck/scarf/black=1, @@ -1130,47 +1130,14 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C /obj/item/clothing/glasses/regular=1, /obj/item/clothing/glasses/regular/jamjar=1, /obj/item/clothing/head/sombrero=1, /obj/item/clothing/suit/poncho=1, /obj/item/clothing/suit/ianshirt=1, /obj/item/clothing/shoes/laceup=2, /obj/item/clothing/shoes/sneakers/black=4, /obj/item/clothing/shoes/sandal=1, /obj/item/clothing/gloves/fingerless=2, /obj/item/clothing/glasses/orange=1, /obj/item/clothing/glasses/red=1, - /obj/item/storage/belt/fannypack=1, /obj/item/storage/belt/fannypack/blue=1, /obj/item/storage/belt/fannypack/red=1, /obj/item/clothing/suit/jacket/letterman=2, - /obj/item/clothing/head/beanie=1, /obj/item/clothing/head/beanie/black=1, /obj/item/clothing/head/beanie/red=1, /obj/item/clothing/head/beanie/green=1, /obj/item/clothing/head/beanie/darkblue=1, - /obj/item/clothing/head/beanie/purple=1, /obj/item/clothing/head/beanie/yellow=1, /obj/item/clothing/head/beanie/orange=1, /obj/item/clothing/head/beanie/cyan=1, /obj/item/clothing/head/beanie/christmas=1, - /obj/item/clothing/head/beanie/striped=1, /obj/item/clothing/head/beanie/stripedred=1, /obj/item/clothing/head/beanie/stripedblue=1, /obj/item/clothing/head/beanie/stripedgreen=1, + /obj/item/storage/belt/fannypack=1, /obj/item/storage/belt/fannypack/blue=1, /obj/item/storage/belt/fannypack/red=1, /obj/item/clothing/suit/jacket/letterman=2, + /obj/item/clothing/head/beanie=1, /obj/item/clothing/head/beanie/black=1, /obj/item/clothing/head/beanie/red=1, /obj/item/clothing/head/beanie/green=1, /obj/item/clothing/head/beanie/darkblue=1, + /obj/item/clothing/head/beanie/purple=1, /obj/item/clothing/head/beanie/yellow=1, /obj/item/clothing/head/beanie/orange=1, /obj/item/clothing/head/beanie/cyan=1, /obj/item/clothing/head/beanie/christmas=1, + /obj/item/clothing/head/beanie/striped=1, /obj/item/clothing/head/beanie/stripedred=1, /obj/item/clothing/head/beanie/stripedblue=1, /obj/item/clothing/head/beanie/stripedgreen=1, /obj/item/clothing/suit/jacket/letterman_red=1, /obj/item/clothing/ears/headphones = 10) contraband = list(/obj/item/clothing/under/syndicate/tacticool=1, /obj/item/clothing/mask/balaclava=1, /obj/item/clothing/head/ushanka=1, /obj/item/clothing/under/soviet=1, /obj/item/storage/belt/fannypack/black=2, /obj/item/clothing/suit/jacket/letterman_syndie=1, /obj/item/clothing/under/jabroni=1, /obj/item/clothing/suit/vapeshirt=1, /obj/item/clothing/under/geisha=1) premium = list(/obj/item/clothing/under/suit_jacket/checkered=1, /obj/item/clothing/head/mailman=1, /obj/item/clothing/under/rank/mailman=1, /obj/item/clothing/suit/jacket/leather=1, /obj/item/clothing/suit/jacket/leather/overcoat=1, /obj/item/clothing/under/pants/mustangjeans=1, /obj/item/clothing/neck/necklace/dope=3, /obj/item/clothing/suit/jacket/letterman_nanotrasen=1) -<<<<<<< HEAD - refill_canister = /obj/item/vending_refill/clothing - -/obj/machinery/vending/toyliberationstation - name = "\improper Syndicate Donksoft Toy Vendor" - desc = "A ages 8 and up approved vendor that dispenses toys. If you were to find the right wires, you can unlock the adult mode setting!" - icon_state = "syndi" - req_access_txt = "1" - product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!" - product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!" - vend_reply = "Come back for more!" - products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10, - /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10, - /obj/item/gun/ballistic/shotgun/toy/unrestricted = 10, - /obj/item/toy/sword = 10, /obj/item/ammo_box/foambox = 20, - /obj/item/toy/foamblade = 10, - /obj/item/toy/syndicateballoon = 10, - /obj/item/clothing/suit/syndicatefake = 5, - /obj/item/clothing/head/syndicatefake = 5) //OPS IN DORMS oh wait it's just a assistant - contraband = list(/obj/item/gun/ballistic/shotgun/toy/crossbow = 10, //Congrats, you unlocked the +18 setting! - /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted = 10, - /obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted = 10, - /obj/item/ammo_box/foambox/riot = 20, - /obj/item/toy/katana = 10, - /obj/item/twohanded/dualsaber/toy = 5, - /obj/item/toy/cards/deck/syndicate = 10) //Gambling and it hurts, making it a +18 item - armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -#undef STANDARD_CHARGE -#undef CONTRABAND_CHARGE -#undef COIN_CHARGE -======= refill_canister = /obj/item/vending_refill/clothing /obj/machinery/vending/toyliberationstation @@ -1229,4 +1196,3 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C #undef STANDARD_CHARGE #undef CONTRABAND_CHARGE #undef COIN_CHARGE ->>>>>>> 91a9164... Adds Donksoft Toy Vendor (Machine Board) to the Circuit Imprinter (#30531) From c3a1c08206f7fc1adf3cb3aca2bb86705bcfde9b Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:51:49 -0500 Subject: [PATCH 076/102] Update smartfridge.dm --- .../kitchen_machinery/smartfridge.dm | 94 ++++--------------- 1 file changed, 17 insertions(+), 77 deletions(-) diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 491da12a81..806fbc1f90 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -142,55 +142,8 @@ user.set_machine(src) interact(user) -/******************* -* SmartFridge Menu -********************/ -/obj/machinery/smartfridge/interact(mob/user) - if(stat) - return FALSE -<<<<<<< HEAD - var/dat = "Select an item:
    " - - if (contents.len == 0) - dat += "No product loaded!" - else - var/listofitems = list() - for (var/atom/movable/O in contents) - if (listofitems[O.name]) - listofitems[O.name]++ - else - listofitems[O.name] = 1 - sortList(listofitems) - - for (var/O in listofitems) - if(listofitems[O] <= 0) - continue - var/N = listofitems[O] - var/itemName = url_encode(O) - dat += "[capitalize(O)]:" - dat += " [N] " - dat += "Vend " - if(N > 5) - dat += "(x5)" - if(N > 10) - dat += "(x10)" - if(N > 25) - dat += "(x25)" - if(N > 1) - dat += "(All)" - - dat += "
    " - - dat += "
    " - user << browse("[src] supplies[dat]", "window=smartfridge") - onclose(user, "smartfridge") - return dat - -/obj/machinery/smartfridge/Topic(var/href, var/list/href_list) - if(..()) -======= /obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) @@ -222,23 +175,27 @@ /obj/machinery/smartfridge/ui_act(action, params) . = ..() if(.) ->>>>>>> 5f6b2a9... Merge pull request #30519 from vuonojenmustaturska/smartfridges2electricboogaloo return - usr.set_machine(src) + switch(action) + if("Release") + var/desired = 0 - var/N = href_list["vend"] - var/amount = text2num(href_list["amount"]) + if (params["amount"]) + desired = text2num(params["amount"]) + else + desired = input("How many items?", "How many items would you like to take out?", 1) as null|num - var/i = amount - for(var/obj/O in contents) - if(i <= 0) - break - if(O.name == N) - O.loc = src.loc - i-- + if(QDELETED(src) || QDELETED(usr) || !usr.Adjacent(src)) // Sanity checkin' in case stupid stuff happens while we wait for input() + return FALSE - - updateUsrDialog() + for(var/obj/item/O in src) + if(desired <= 0) + break + if(O.name == params["name"]) + O.forceMove(drop_location()) + desired-- + return TRUE + return FALSE // ---------------------------- @@ -274,22 +231,6 @@ /obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(obj/item/crowbar/C, ignore_panel = 1) ..() -<<<<<<< HEAD -/obj/machinery/smartfridge/drying_rack/interact(mob/user) - var/dat = ..() - if(dat) - dat += "
    " - dat += "Toggle Drying " - user << browse("[src] supplies[dat]", "window=smartfridge") - onclose(user, "smartfridge") - -/obj/machinery/smartfridge/drying_rack/Topic(href, list/href_list) - ..() - if(href_list["dry"]) - toggle_drying(FALSE) - updateUsrDialog() - update_icon() -======= /obj/machinery/smartfridge/drying_rack/ui_data(mob/user) . = ..() .["isdryer"] = TRUE @@ -307,7 +248,6 @@ toggle_drying(FALSE) return TRUE return FALSE ->>>>>>> 5f6b2a9... Merge pull request #30519 from vuonojenmustaturska/smartfridges2electricboogaloo /obj/machinery/smartfridge/drying_rack/power_change() if(powered() && anchored) From bfe633540a6296842f1abf5d01b6eeac1f5af8ca Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 17:55:35 -0500 Subject: [PATCH 077/102] Update human_movement.dm --- .../mob/living/carbon/human/human_movement.dm | 80 +++---------------- 1 file changed, 12 insertions(+), 68 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index d01048c69a..06f3007e6b 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -1,72 +1,17 @@ -/mob/living/carbon/human/movement_delay() - . = 0 - . += ..() - . += config.human_delay - . += dna.species.movement_delay(src) - -/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube) +/mob/living/carbon/human/movement_delay() + . = 0 + . += ..() + . += config.human_delay + . += dna.species.movement_delay(src) + +/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube) if(isobj(shoes) && (shoes.flags_1&NOSLIP_1) && !(lube&GALOSHES_DONT_HELP)) - return 0 - return ..() - -/mob/living/carbon/human/experience_pressure_difference() - playsound(src, 'sound/effects/space_wind.ogg', 50, 1) + return 0 + return ..() + +/mob/living/carbon/human/experience_pressure_difference() + playsound(src, 'sound/effects/space_wind.ogg', 50, 1) if(shoes && shoes.flags_1&NOSLIP_1) -<<<<<<< HEAD - return 0 - return ..() - -/mob/living/carbon/human/mob_has_gravity() - . = ..() - if(!.) - if(mob_negates_gravity()) - . = 1 - -/mob/living/carbon/human/mob_negates_gravity() - return ((shoes && shoes.negates_gravity()) || dna.species.negates_gravity(src)) - -/mob/living/carbon/human/Move(NewLoc, direct) - . = ..() - for(var/datum/mutation/human/HM in dna.mutations) - HM.on_move(src, NewLoc) - if(shoes) - if(!lying && !buckled) - if(loc == NewLoc) - if(!has_gravity(loc)) - return - var/obj/item/clothing/shoes/S = shoes - - //Bloody footprints - var/turf/T = get_turf(src) - if(S.bloody_shoes && S.bloody_shoes[S.blood_state]) - var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T - if(oldFP && oldFP.blood_state == S.blood_state) - return - else - //No oldFP or it's a different kind of blood - S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state]-BLOOD_LOSS_PER_STEP) - var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T) - FP.blood_state = S.blood_state - FP.entered_dirs |= dir - FP.bloodiness = S.bloody_shoes[S.blood_state] - if(S.blood_DNA && S.blood_DNA.len) - FP.transfer_blood_dna(S.blood_DNA) - FP.update_icon() - update_inv_shoes() - //End bloody footprints - - S.step_action() - -/mob/living/carbon/human/Moved() - . = ..() - if(buckled_mobs && buckled_mobs.len && riding_datum) - riding_datum.on_vehicle_move() - -/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee. - if(..()) - return 1 - return dna.species.space_move(src) -======= return 0 return ..() @@ -120,4 +65,3 @@ if(..()) return 1 return dna.species.space_move(src) ->>>>>>> 96a55aa... People in soft crit will leave blood trails when dragging themselves/Will take less damage in soft crit (#30482) From 933d9f5f6925e6c33e7da9a9e812988d2354b5f7 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:09:03 -0500 Subject: [PATCH 078/102] Delete tgstation.dme.rej --- tgstation.dme.rej | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 tgstation.dme.rej diff --git a/tgstation.dme.rej b/tgstation.dme.rej deleted file mode 100644 index 82c613607a..0000000000 --- a/tgstation.dme.rej +++ /dev/null @@ -1,9 +0,0 @@ -diff a/tgstation.dme b/tgstation.dme (rejected hunks) -@@ -793,7 +794,6 @@ - #include "code\game\objects\items\devices\megaphone.dm" - #include "code\game\objects\items\devices\multitool.dm" - #include "code\game\objects\items\devices\paicard.dm" --#include "code\game\objects\items\devices\pinpointer.dm" - #include "code\game\objects\items\devices\pipe_painter.dm" - #include "code\game\objects\items\devices\powersink.dm" - #include "code\game\objects\items\devices\pressureplates.dm" From bb463cef4882ba0012e43454e9b6ef3af95e0ccd Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:26:13 -0500 Subject: [PATCH 079/102] Update create_mob.dm --- code/modules/admin/create_mob.dm | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 7bfd7ec80a..e76385db59 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -1,31 +1,3 @@ -<<<<<<< HEAD - -/datum/admins/proc/create_mob(mob/user) - var/static/create_mob_html - if (!create_mob_html) - var/mobjs = null - mobjs = jointext(typesof(/mob), ";") - create_mob_html = file2text('html/create_object.html') - create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"") - - user << browse(replacetext(create_mob_html, "/* ref src */", "\ref[src]"), "window=create_mob;size=425x475") - -/proc/randomize_human(mob/living/carbon/human/H) - H.gender = pick(MALE, FEMALE) - H.real_name = random_unique_name(H.gender) - H.name = H.real_name - H.underwear = random_underwear(H.gender) - H.skin_tone = random_skin_tone() - H.hair_style = random_hair_style(H.gender) - H.facial_hair_style = random_facial_hair_style(H.gender) - H.hair_color = random_short_color() - H.facial_hair_color = H.hair_color - H.eye_color = random_eye_color() - H.dna.blood_type = random_blood_type() - H.update_body() - H.update_hair() -======= - /datum/admins/proc/create_mob(mob/user) var/static/create_mob_html if (!create_mob_html) @@ -50,5 +22,4 @@ H.dna.blood_type = random_blood_type() H.update_body() H.update_hair() ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) - H.update_body_parts() \ No newline at end of file + H.update_body_parts() From 98f6cf208bfd1fad83f66559d96e830a1d864bec Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:26:36 -0500 Subject: [PATCH 080/102] Update create_object.dm --- code/modules/admin/create_object.dm | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm index cddadb4082..cb947355b1 100644 --- a/code/modules/admin/create_object.dm +++ b/code/modules/admin/create_object.dm @@ -1,31 +1,3 @@ -<<<<<<< HEAD -/datum/admins/proc/create_object(mob/user) - var/static/create_object_html = null - if (!create_object_html) - var/objectjs = null - objectjs = jointext(typesof(/obj), ";") - create_object_html = file2text('html/create_object.html') - create_object_html = replacetext(create_object_html, "null /* object types */", "\"[objectjs]\"") - - user << browse(replacetext(create_object_html, "/* ref src */", "\ref[src]"), "window=create_object;size=425x475") - -/datum/admins/proc/quick_create_object(mob/user) - var/static/list/create_object_forms = list( - /obj, /obj/structure, /obj/machinery, /obj/effect, - /obj/item, /obj/item/clothing, /obj/item/stack, /obj/item/device, - /obj/item/weapon, /obj/item/reagent_containers, /obj/item/gun) - - var/path = input("Select the path of the object you wish to create.", "Path", /obj) in create_object_forms - var/html_form = create_object_forms[path] - - if (!html_form) - var/objectjs = jointext(typesof(path), ";") - html_form = file2text('html/create_object.html') - html_form = replacetext(html_form, "null /* object types */", "\"[objectjs]\"") - create_object_forms[path] = html_form - - user << browse(replacetext(html_form, "/* ref src */", "\ref[src]"), "window=qco[path];size=425x475") -======= /datum/admins/proc/create_object(mob/user) var/static/create_object_html = null if (!create_object_html) @@ -52,4 +24,3 @@ create_object_forms[path] = html_form user << browse(replacetext(html_form, "/* ref src */", "\ref[src];[HrefToken()]"), "window=qco[path];size=425x475") ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) From 15c4d34b5592ee52e5106bbd9bec4c7ddb848ff0 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:26:50 -0500 Subject: [PATCH 081/102] Update create_turf.dm --- code/modules/admin/create_turf.dm | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/code/modules/admin/create_turf.dm b/code/modules/admin/create_turf.dm index 62e26d89d5..f38b86a7b9 100644 --- a/code/modules/admin/create_turf.dm +++ b/code/modules/admin/create_turf.dm @@ -1,14 +1,3 @@ -<<<<<<< HEAD -/datum/admins/proc/create_turf(mob/user) - var/static/create_turf_html - if (!create_turf_html) - var/turfjs = null - turfjs = jointext(typesof(/turf), ";") - create_turf_html = file2text('html/create_object.html') - create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"") - - user << browse(replacetext(create_turf_html, "/* ref src */", "\ref[src]"), "window=create_turf;size=425x475") -======= /datum/admins/proc/create_turf(mob/user) var/static/create_turf_html if (!create_turf_html) @@ -18,4 +7,3 @@ create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"") user << browse(replacetext(create_turf_html, "/* ref src */", "\ref[src];[HrefToken()]"), "window=create_turf;size=425x475") ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) From 584bb8dc64c8daf7b74cfba04a2e2a0f39b4ab22 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:27:04 -0500 Subject: [PATCH 082/102] Update holder2.dm --- code/modules/admin/holder2.dm | 109 +--------------------------------- 1 file changed, 1 insertion(+), 108 deletions(-) diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index d9c5b88364..153fb2d8c2 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -1,109 +1,3 @@ -<<<<<<< HEAD -GLOBAL_LIST_EMPTY(admin_datums) -GLOBAL_PROTECT(admin_datums) - -/datum/admins - var/datum/admin_rank/rank - - var/client/owner = null - var/fakekey = null - - var/datum/marked_datum - - var/spamcooldown = 0 - - var/admincaster_screen = 0 //TODO: remove all these 5 variables, they are completly unacceptable - var/datum/newscaster/feed_message/admincaster_feed_message = new /datum/newscaster/feed_message - var/datum/newscaster/wanted_message/admincaster_wanted_message = new /datum/newscaster/wanted_message - var/datum/newscaster/feed_channel/admincaster_feed_channel = new /datum/newscaster/feed_channel - var/admin_signature - -/datum/admins/New(datum/admin_rank/R, ckey) - if(!ckey) - QDEL_IN(src, 0) - throw EXCEPTION("Admin datum created without a ckey") - return - if(!istype(R)) - QDEL_IN(src, 0) - throw EXCEPTION("Admin datum created without a rank") - return - rank = R - admin_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]" - GLOB.admin_datums[ckey] = src - -/datum/admins/proc/associate(client/C) - if(IsAdminAdvancedProcCall()) - var/msg = " has tried to elevate permissions!" - message_admins("[key_name_admin(usr)][msg]") - log_admin_private("[key_name(usr)][msg]") - return - if(istype(C)) - owner = C - owner.holder = src - owner.add_admin_verbs() //TODO - owner.verbs -= /client/proc/readmin - GLOB.admins |= C - -/datum/admins/proc/disassociate() - if(owner) - GLOB.admins -= owner - owner.remove_admin_verbs() - owner.holder = null - owner = null - -/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other) - if(!other) - return 1 //they have no rights - if(rank.rights == 65535) - return 1 //we have all the rights - if(src == other) - return 1 //you always have more rights than yourself - if(rank.rights != other.rank.rights) - if( (rank.rights & other.rank.rights) == other.rank.rights ) - return 1 //we have all the rights they have and more - return 0 - -/datum/admins/vv_edit_var(var_name, var_value) - return FALSE //nice try trialmin - -/* -checks if usr is an admin with at least ONE of the flags_1 in rights_required. (Note, they don't need all the flags_1) -if rights_required == 0, then it simply checks if they are an admin. -if it doesn't return 1 and show_msg=1 it will prints a message explaining why the check has failed -generally it would be used like so: - -/proc/admin_proc() - if(!check_rights(R_ADMIN)) return - to_chat(world, "you have enough rights!") - -NOTE: it checks usr! not src! So if you're checking somebody's rank in a proc which they did not call -you will have to do something like if(client.rights & R_ADMIN) yourself. -*/ -/proc/check_rights(rights_required, show_msg=1) - if(usr && usr.client) - if (check_rights_for(usr.client, rights_required)) - return 1 - else - if(show_msg) - to_chat(usr, "Error: You do not have sufficient rights to do that. You require one of the following flags_1:[rights2text(rights_required," ")].") - return 0 - -//probably a bit iffy - will hopefully figure out a better solution -/proc/check_if_greater_rights_than(client/other) - if(usr && usr.client) - if(usr.client.holder) - if(!other || !other.holder) - return 1 - return usr.client.holder.check_if_greater_rights_than_holder(other.holder) - return 0 - -//This proc checks whether subject has at least ONE of the rights specified in rights_required. -/proc/check_rights_for(client/subject, rights_required) - if(subject && subject.holder && subject.holder.rank) - if(rights_required && !(rights_required & subject.holder.rank.rights)) - return 0 - return 1 -======= GLOBAL_LIST_EMPTY(admin_datums) GLOBAL_PROTECT(admin_datums) @@ -229,5 +123,4 @@ you will have to do something like if(client.rights & R_ADMIN) yourself. if(rights_required && !(rights_required & subject.holder.rank.rights)) return 0 return 1 ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) - return 0 \ No newline at end of file + return 0 From 5fafa90538c97d7c87ae5b54c3f06319ce61dfb7 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:27:20 -0500 Subject: [PATCH 083/102] Update secrets.dm --- code/modules/admin/secrets.dm | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 899e763c92..c277dd59e0 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -47,29 +47,6 @@
    <<<<<<< HEAD - Trigger a Virus Outbreak
    - Turn all humans into monkeys
    - Chinese Cartoons
    - Change the species of all humans
    - Make all areas powered
    - Make all areas unpowered
    - Power all SMES
    - Triple AI mode (needs to be used in the lobby)
    - Everyone is the traitor
    - Summon Guns
    - Summon Magic
    - Summon Events (Toggle)
    - There can only be one!
    - There can only be one! (40-second delay)
    - There can only be me!
    - Make all players retarded
    - Egalitarian Station Mode
    - Break all lights
    - Fix all lights
    - The floor is lava! (DANGEROUS: extremely lame)
    -======= -<<<<<<< HEAD - ======= >>>>>>> 6e5ebf9c41fc97d5ee0daf4fd22536844438ace0 Trigger a Virus Outbreak
    @@ -91,7 +68,6 @@ Break all lights
    Fix all lights
    The floor is lava! (DANGEROUS: extremely lame)
    ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839)
    Change bomb cap
    Mass Purrbation
    @@ -552,12 +528,6 @@ usr.client.only_one_delayed() sound_to_playing_players('sound/misc/highlander_delayed.ogg') - if("onlyme") - if(!check_rights(R_FUN)) - return - SSblackbox.add_details("admin_secrets_fun_used","There Can Be Only Me") - only_me() - if("maint_access_brig") if(!check_rights(R_DEBUG)) return From c03fb31b1ce3a4c0e1764c54433200a6aa298baf Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:27:47 -0500 Subject: [PATCH 084/102] Update sql_message_system.dm --- code/modules/admin/sql_message_system.dm | 60 +++++++++++++++--------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index 9eb66986b0..2d35dcad80 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -56,7 +56,7 @@ if(browse) browse_messages("[type]") else - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) /proc/delete_message(message_id, logged = 1, browse) if(!SSdbcore.Connect()) @@ -68,14 +68,14 @@ var/type var/target_ckey var/text - var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") if(!query_find_del_message.warn_execute()) return if(query_find_del_message.NextRow()) type = query_find_del_message.item[1] target_ckey = query_find_del_message.item[2] text = query_find_del_message.item[4] - var/datum/DBQuery/query_del_message = SSdbcore.NewQuery("DELETE FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_del_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET deleted = 1 WHERE id = [message_id]") if(!query_del_message.warn_execute()) return if(logged) @@ -84,7 +84,7 @@ if(browse) browse_messages("[type]") else - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) /proc/edit_message(message_id, browse) if(!SSdbcore.Connect()) @@ -93,7 +93,7 @@ message_id = text2num(message_id) if(!message_id) return - var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") if(!query_find_edit_message.warn_execute()) return if(query_find_edit_message.NextRow()) @@ -107,7 +107,7 @@ return new_text = sanitizeSQL(new_text) var/edit_text = sanitizeSQL("Edited by [editor_ckey] on [SQLtime()] from
    [old_text]
    to
    [new_text]
    ") - var/datum/DBQuery/query_edit_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET text = '[new_text]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id]") + var/datum/DBQuery/query_edit_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET text = '[new_text]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0") if(!query_edit_message.warn_execute()) return log_admin_private("[key_name(usr)] has edited a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_ckey]" : ""] made by [admin_ckey] from [old_text] to [new_text]") @@ -115,7 +115,7 @@ if(browse) browse_messages("[type]") else - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) /proc/toggle_message_secrecy(message_id) if(!SSdbcore.Connect()) @@ -124,7 +124,7 @@ message_id = text2num(message_id) if(!message_id) return - var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, secret FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, secret FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") if(!query_find_message_secret.warn_execute()) return if(query_find_message_secret.NextRow()) @@ -139,9 +139,9 @@ return log_admin_private("[key_name(usr)] has toggled [target_ckey]'s [type] made by [admin_ckey] to [secret ? "not secret" : "secret"]") message_admins("[key_name_admin(usr)] has toggled [target_ckey]'s [type] made by [admin_ckey] to [secret ? "not secret" : "secret"]") - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) -/proc/browse_messages(type, target_ckey, index, linkless = 0, filter) +/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE) if(!SSdbcore.Connect()) to_chat(usr, "Failed to establish database connection.") return @@ -169,7 +169,7 @@ else output += "|\[Filter offline clients\]" output += ruler - var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, targetckey, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]'") + var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, targetckey, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0") if(!query_get_type_messages.warn_execute()) return while(query_get_type_messages.NextRow()) @@ -193,12 +193,13 @@ output += "
    [text]
    " if(target_ckey) target_ckey = sanitizeSQL(target_ckey) - var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' ORDER BY timestamp DESC") + var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, adminckey, text, timestamp, server, lasteditor, DATEDIFF(NOW(), timestamp) AS `age` FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' AND deleted = 0 ORDER BY timestamp DESC") if(!query_get_messages.warn_execute()) return var/messagedata var/watchdata var/notedata + var/skipped = 0 while(query_get_messages.NextRow()) type = query_get_messages.item[1] if(type == "memo") @@ -212,8 +213,21 @@ var/timestamp = query_get_messages.item[6] var/server = query_get_messages.item[7] var/editor_ckey = query_get_messages.item[8] + var/age = text2num(query_get_messages.item[9]) + var/alphatext = "" + if (agegate && type == "note" && isnum(config.note_stale_days) && isnum(config.note_fresh_days) && config.note_stale_days > config.note_fresh_days) + var/alpha = Clamp(100 - (age - config.note_fresh_days) * (85 / (config.note_stale_days - config.note_fresh_days)), 15, 100) + if (alpha < 100) + if (alpha <= 15) + if (skipped) + skipped++ + continue + alpha = 10 + skipped = TRUE + alphatext = "filter: alpha(opacity=[alpha]); opacity: [alpha/100];" + var/data - data += "[timestamp] | [server] | [admin_ckey]" + data += "

    [timestamp] | [server] | [admin_ckey]" if(!linkless) data += " \[Delete\]" if(type == "note") @@ -225,13 +239,8 @@ else data += " \[Edit\]" if(editor_ckey) -<<<<<<< HEAD - data += " Last edit by [editor_ckey] (Click here to see edit log)" - data += "
    [text]


    " -======= data += " Last edit by [editor_ckey] (Click here to see edit log)" data += "
    [text]


    " ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) switch(type) if("message") messagedata += data @@ -259,6 +268,15 @@ if(notedata) output += "

    Notes

    " output += notedata + if(!linkless) + if (agegate) + if (skipped) //the first skipped message is still shown so that we can put this link over it. + output += "
    \[Show [skipped] hidden messages\]
    " + else + output += "
    \[Show All\]
    " + + else + output += "
    \[Hide Old\]
    " if(index) var/index_ckey var/search @@ -273,7 +291,7 @@ search = "^\[^\[:alpha:\]\]" else search = "^[index]" - var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' ORDER BY targetckey") + var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 ORDER BY targetckey") if(!query_list_messages.warn_execute()) return while(query_list_messages.NextRow()) @@ -282,7 +300,7 @@ else if(!type && !target_ckey && !index) output += "
    \[Add message\]\[Add watchlist entry\]\[Add note\]
    " output += ruler - usr << browse(output, "window=browse_messages;size=900x500") + usr << browse({"[output]"}, "window=browse_messages;size=900x500") proc/get_message_output(type, target_ckey) if(!SSdbcore.Connect()) @@ -293,7 +311,7 @@ proc/get_message_output(type, target_ckey) var/output if(target_ckey) target_ckey = sanitizeSQL(target_ckey) - var/query = "SELECT id, adminckey, text, timestamp, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]'" + var/query = "SELECT id, adminckey, text, timestamp, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0" if(type == "message" || type == "watchlist entry") query += " AND targetckey = '[target_ckey]'" var/datum/DBQuery/query_get_message_output = SSdbcore.NewQuery(query) From e5cc2c1e4ed08c4c8375648d0b250c71e482a3a1 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:28:09 -0500 Subject: [PATCH 085/102] Update one_click_antag.dm --- code/modules/admin/verbs/one_click_antag.dm | 52 --------------------- 1 file changed, 52 deletions(-) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 398965e74d..c637389031 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -11,20 +11,6 @@ /datum/admins/proc/one_click_antag() var/dat = {" -<<<<<<< HEAD - Make Traitors
    - Make Changelings
    - Make Revs
    - Make Cult
    - Make Clockwork Cult
    - Make Blob
    - Make Gangsters
    - Make Wizard (Requires Ghosts)
    - Make Nuke Team (Requires Ghosts)
    - Make CentCom Response Team (Requires Ghosts)
    - Make Abductor Team (Requires Ghosts)
    - Make Revenant (Requires Ghost)
    -======= Make Traitors
    Make Changelings
    Make Revs
    @@ -36,7 +22,6 @@ Make CentCom Response Team (Requires Ghosts)
    Make Abductor Team (Requires Ghosts)
    Make Revenant (Requires Ghost)
    ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) "} var/datum/browser/popup = new(usr, "oneclickantag", "Quick-Create Antagonist", 400, 400) @@ -372,43 +357,6 @@ return - -/datum/admins/proc/makeGangsters() - - var/datum/game_mode/gang/temp = new - if(config.protect_roles_from_antagonist) - temp.restricted_jobs += temp.protected_jobs - - if(config.protect_assistant_from_antagonist) - temp.restricted_jobs += "Assistant" - - var/list/mob/living/carbon/human/candidates = list() - var/mob/living/carbon/human/H = null - - for(var/mob/living/carbon/human/applicant in GLOB.player_list) - if(ROLE_GANG in applicant.client.prefs.be_special) - var/turf/T = get_turf(applicant) - if(applicant.stat == CONSCIOUS && applicant.mind && !applicant.mind.special_role && T.z == ZLEVEL_STATION) - if(!jobban_isbanned(applicant, ROLE_GANG) && !jobban_isbanned(applicant, "Syndicate")) - if(temp.age_check(applicant.client)) - if(!(applicant.job in temp.restricted_jobs)) - candidates += applicant - - if(candidates.len >= 2) - for(var/needs_assigned=2,needs_assigned>0,needs_assigned--) - H = pick(candidates) - if(GLOB.gang_colors_pool.len) - var/datum/gang/newgang = new() - SSticker.mode.gangs += newgang - H.mind.make_Gang(newgang) - candidates.Remove(H) - else if(needs_assigned == 2) - return 0 - return 1 - - return 0 - - /datum/admins/proc/makeOfficial() var/mission = input("Assign a task for the official", "Assign Task", "Conduct a routine preformance review of [station_name()] and its Captain.") var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered to be a CentCom Official?", "deathsquad") From 7d4c6a84459ce51fae64e5f7e2406de54964870b Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:28:39 -0500 Subject: [PATCH 086/102] Update config.txt --- config/config.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/config.txt b/config/config.txt index 6effd92b53..652651e425 100644 --- a/config/config.txt +++ b/config/config.txt @@ -337,9 +337,6 @@ MINUTE_TOPIC_LIMIT 100 ## Send a message to IRC when starting a new game #IRC_ANNOUNCE_NEW_GAME -<<<<<<< HEAD -======= ## Allow admin hrefs that don't use the new token system, will eventually be removed DEBUG_ADMIN_HREFS ->>>>>>> 84b1e3d... [s] Adds a security token to all admin hrefs (#29839) From bf5094cf19504604de9ba9373eb360fdccb55b27 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:40:30 -0500 Subject: [PATCH 087/102] Update nuclearbomb.dm --- code/game/gamemodes/nuclear/nuclearbomb.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 5245b00c35..95fc735ec6 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -388,7 +388,7 @@ bomb_set = FALSE detonation_timer = null set_security_level(previous_level) - for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list) + for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(initial(S.mode)) S.alert = FALSE countdown.stop() From 37600510746186798e6486ae51cfbd1506aad422 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 11 Sep 2017 18:45:24 -0500 Subject: [PATCH 088/102] Automatic changelog generation for PR #2678 [ci skip] --- html/changelogs/AutoChangeLog-pr-2678.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2678.yml diff --git a/html/changelogs/AutoChangeLog-pr-2678.yml b/html/changelogs/AutoChangeLog-pr-2678.yml new file mode 100644 index 0000000000..cf518a6179 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2678.yml @@ -0,0 +1,5 @@ +author: "Kor" +delete-after: True +changes: + - rscadd: "People in soft crit will take oxyloss more slowly than people in full crit if they remain still." + - rscadd: "People dragging themselves in critical condition will now leave blood trails. This will rapidly deal oxyloss to you." From beed20c1308a6322315a3858b0febcecd612deee Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:52:14 -0500 Subject: [PATCH 089/102] Update life.dm --- code/modules/mob/living/carbon/life.dm | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index d0dd1796bf..8cb7043bad 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -58,13 +58,6 @@ var/datum/gas_mixture/breath -<<<<<<< HEAD - if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube"))) - losebreath++ - - //Suffocate - if(losebreath > 0) -======= if(!getorganslot("breathing_tube")) if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL)) losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath @@ -74,7 +67,6 @@ //Suffocate if(losebreath >= 1) //You've missed a breath, take oxy damage ->>>>>>> d4e09c9... Losebreath (#30580) losebreath-- if(prob(10)) emote("gasp") @@ -126,10 +118,6 @@ if(reagents.has_reagent("epinephrine") && lungs) return adjustOxyLoss(1) -<<<<<<< HEAD -======= - ->>>>>>> d4e09c9... Losebreath (#30580) failed_last_breath = 1 throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) return 0 From ce518ee45e78503c91b57e883c4f187035ad079d Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 18:56:10 -0500 Subject: [PATCH 090/102] Update closets.dm --- code/game/objects/structures/crates_lockers/closets.dm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 03168d42ea..27cb6de715 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -388,11 +388,7 @@ /obj/structure/closet/AltClick(mob/user) ..() -<<<<<<< HEAD - if(!user.canUseTopic(src, be_close=TRUE)) -======= if(!user.canUseTopic(src, be_close=TRUE) || !isturf(loc)) ->>>>>>> 847e426... Fixes lockers alt-click (#30544) to_chat(user, "You can't do that right now!") return if(opened || !secure) From 2629d3b87ddf5405f9b09279e9adaf025d99ce72 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Mon, 11 Sep 2017 20:22:21 -0500 Subject: [PATCH 091/102] Adds horse, cow tails, Sergal ears/tails also (#2695) * Adds horse, sergal, cow tails * Slight tweaks before bed * sprite tweaks --- .../new_player/sprite_accessories_Citadel.dm | 263 +++++++++++------- icons/mob/mam_bodyparts.dmi | Bin 49503 -> 50903 bytes 2 files changed, 163 insertions(+), 100 deletions(-) diff --git a/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm b/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm index 648e6170fa..228c9fe6e7 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm @@ -1,8 +1,8 @@ /datum/sprite_accessory - var/extra = 0 + var/extra = FALSE var/extra_icon = 'icons/mob/mam_bodyparts.dmi' var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay. - var/extra2 = 0 + var/extra2 = FALSE var/extra2_icon = 'icons/mob/mam_bodyparts.dmi' var/extra2_color_src = MUTCOLORS3 // var/list/ckeys_allowed = null @@ -13,6 +13,10 @@ icon = 'icons/mob/mam_bodyparts.dmi' */ +/***************** Alphabetical Order please *************** +************* Keep it to Ears, Tails, Tails Animated *********/ + + /datum/sprite_accessory/tails/lizard/none name = "None" icon_state = "None" @@ -31,12 +35,17 @@ color_src = 0 icon = 'icons/mob/mam_bodyparts.dmi' +/datum/sprite_accessory/ears/human/bear + name = "Bear" + icon_state = "bear" + icon = 'icons/mob/mam_bodyparts.dmi' + /datum/sprite_accessory/tails/human/bear name = "Bear" icon_state = "bear" icon = 'icons/mob/mam_bodyparts.dmi' -/datum/sprite_accessory/ears/human/bear +/datum/sprite_accessory/tails_animated/human/bear name = "Bear" icon_state = "bear" icon = 'icons/mob/mam_bodyparts.dmi' @@ -51,10 +60,27 @@ icon_state = "catbig" icon = 'icons/mob/mam_bodyparts.dmi' +/datum/sprite_accessory/ears/human/cow + name = "Cow" + icon_state = "cow" + icon = 'icons/mob/mam_bodyparts.dmi' + gender_specific = 1 + +/datum/sprite_accessory/tails/human/cow + name = "Cow" + icon_state = "cow" + icon = 'icons/mob/mam_bodyparts.dmi' + +/datum/sprite_accessory/tails_animated/human/cow + name = "Cow" + icon_state = "cow" + icon = 'icons/mob/mam_bodyparts.dmi' + /datum/sprite_accessory/ears/fennec name = "Fennec" icon_state = "fennec" icon = 'icons/mob/mam_bodyparts.dmi' + hasinner = 1 /datum/sprite_accessory/tails/human/fennec name = "Fennec" @@ -76,37 +102,49 @@ name = "Fox" icon_state = "fox" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/tails_animated/human/fox name = "Fox" icon_state = "fox" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE + +/datum/sprite_accessory/tails/human/horse + name = "Horse" + icon_state = "horse" + icon = 'icons/mob/mam_bodyparts.dmi' + color_src = HAIR + +/datum/sprite_accessory/tails_animated/human/horse + name = "Horse" + icon_state = "horse" + icon = 'icons/mob/mam_bodyparts.dmi' + color_src = HAIR /datum/sprite_accessory/tails/human/husky name = "Husky" icon_state = "husky" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/tails_animated/human/husky name = "Husky" icon_state = "husky" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/tails/human/kitsune name = "Kitsune" icon_state = "kitsune" - extra = 1 + extra = TRUE extra_color_src = MUTCOLORS2 icon = 'icons/mob/mam_bodyparts.dmi' /datum/sprite_accessory/tails_animated/human/kitsune name = "Kitsune" icon_state = "kitsune" - extra = 1 + extra = TRUE extra_color_src = MUTCOLORS2 icon = 'icons/mob/mam_bodyparts.dmi' @@ -146,6 +184,24 @@ name = "Otusian" icon_state = "otie" +/datum/sprite_accessory/ears/human/rabbit + name = "Rabbit" + icon_state = "rabbit" + hasinner= 1 + icon = 'icons/mob/mam_bodyparts.dmi' + +/datum/sprite_accessory/tails/human/rabbit + name = "Rabbit" + icon_state = "rabbit" + color_src = 0 + icon = 'icons/mob/mam_bodyparts.dmi' + +/datum/sprite_accessory/tails_animated/human/rabbit + name = "Rabbit" + icon_state = "rabbit" + color_src = 0 + icon = 'icons/mob/mam_bodyparts.dmi' + /datum/sprite_accessory/ears/human/skunk name = "skunk" icon_state = "skunk" @@ -191,7 +247,7 @@ /datum/sprite_accessory/ears/wolf name = "Wolf" icon_state = "wolf" - extra = 1 + hasinner = 1 /datum/sprite_accessory/tails/human/wolf name = "Wolf" @@ -203,18 +259,6 @@ icon_state = "wolf" icon = 'icons/mob/mam_bodyparts.dmi' -/datum/sprite_accessory/tails/human/rabbit - name = "Rabbit" - icon_state = "rabbit" - color_src = 0 - icon = 'icons/mob/mam_bodyparts.dmi' - -/datum/sprite_accessory/ears/human/rabbit - name = "Rabbit" - icon_state = "rabbit" - hasinner= 1 - icon = 'icons/mob/mam_bodyparts.dmi' - /****************************************** *************** Body Parts **************** *******************************************/ @@ -248,36 +292,37 @@ name = "Beak" icon_state = "bird" icon = 'icons/mob/mam_bodyparts.dmi' + color_src = MUTCOLORS3 /datum/sprite_accessory/snouts/lcanid name = "Fox, Long" icon_state = "lcanid" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/snouts/scanid name = "Fox, Short" icon_state = "scanid" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/snouts/wolf name = "Wolf" icon_state = "wolf" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/snouts/husky name = "Husky" icon_state = "husky" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/snouts/otie name = "Otie" icon_state = "otie" icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /****************************************** ************ Actual Species *************** @@ -286,31 +331,30 @@ /datum/sprite_accessory/mam_tails/ailurus name = "Ailurus" icon_state = "ailurus" - extra = 1 - extra_color_src = MUTCOLORS2 + extra = TRUE /datum/sprite_accessory/mam_tails_animated/ailurus name = "Ailurus" icon_state = "ailurus" - extra = 1 - extra_color_src = MUTCOLORS2 - -/datum/sprite_accessory/mam_tails/bear - name = "Bear" - icon_state = "bear" - icon = 'icons/mob/mam_bodyparts.dmi' + extra = TRUE /datum/sprite_accessory/mam_ears/bear name = "Bear" icon_state = "bear" - icon = 'icons/mob/mam_bodyparts.dmi' + +/datum/sprite_accessory/mam_tails/bear + name = "Bear" + icon_state = "bear" + +/datum/sprite_accessory/mam_tails_animated/bear + name = "Bear" + icon_state = "bear" /datum/sprite_accessory/mam_ears/catbig name = "Cat, Big" icon_state = "cat" hasinner = 1 - icon = 'icons/mob/mutant_bodyparts.dmi' - + /datum/sprite_accessory/mam_tails/catbig name = "Cat, Big" icon_state = "catbig" @@ -323,6 +367,14 @@ name = "Cow" icon_state = "cow" gender_specific = 1 + +/datum/sprite_accessory/mam_tail/cow + name = "Cow" + icon_state = "cow" + +/datum/sprite_accessory/mam_tails_animated/cow + name = "Cow" + icon_state = "cow" /datum/sprite_accessory/mam_ears/deer name = "Deer" @@ -331,8 +383,7 @@ /datum/sprite_accessory/mam_tails/eevee name = "Eevee" icon_state = "eevee" - extra = 1 - extra_color_src = MUTCOLORS2 + extra = TRUE /datum/sprite_accessory/mam_ears/eevee name = "Eevee" @@ -341,8 +392,7 @@ /datum/sprite_accessory/mam_tails_animated/eevee name = "Eevee" icon_state = "eevee" - extra = 1 - extra_color_src = MUTCOLORS2 + extra = TRUE /datum/sprite_accessory/mam_ears/fennec name = "Fennec" @@ -360,25 +410,17 @@ /datum/sprite_accessory/mam_ears/fox name = "Fox" icon_state = "fox" - hasinner = 0 + hasinner = 1 /datum/sprite_accessory/mam_tails/fox name = "Fox" icon_state = "fox" - extra = 1 - extra_color_src = MUTCOLORS2 + extra = TRUE /datum/sprite_accessory/mam_tails_animated/fox name = "Fox" icon_state = "fox" - extra = 1 - extra_color_src = MUTCOLORS2 - -/datum/sprite_accessory/mam_ears/husky - name = "Husky" - icon_state = "wolf" - icon = 'icons/mob/mam_bodyparts.dmi' - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_tails/hawk name = "Hawk" @@ -388,20 +430,36 @@ name = "Hawk" icon_state = "hawk" +/datum/sprite_accessory/mam_tails/horse + name = "Horse" + icon_state = "horse" + color_src = HAIR + +/datum/sprite_accessory/mam_tails_animated/horse + name = "Horse" + icon_state = "Horse" + color_src = HAIR + +/datum/sprite_accessory/mam_ears/husky + name = "Husky" + icon_state = "wolf" + icon = 'icons/mob/mam_bodyparts.dmi' + extra = TRUE + /datum/sprite_accessory/mam_tails/husky name = "Husky" icon_state = "husky" - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_tails_animated/husky name = "Husky" icon_state = "husky" - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_ears/kangaroo name = "kangaroo" icon_state = "kangaroo" - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_tails/kangaroo name = "kangaroo" @@ -414,14 +472,12 @@ /datum/sprite_accessory/mam_tails/kitsune name = "Kitsune" icon_state = "kitsune" - extra = 1 - extra_color_src = MUTCOLORS2 + extra = TRUE /datum/sprite_accessory/mam_tails_animated/kitsune name = "Kitsune" icon_state = "kitsune" - extra = 1 - extra_color_src = MUTCOLORS2 + extra = TRUE /datum/sprite_accessory/mam_ears/lab name = "Dog, Long" @@ -462,6 +518,32 @@ name = "Otusian" icon_state = "otie" +/datum/sprite_accessory/mam_ears/rabbit + name = "Rabbit" + icon_state = "rabbit" + hasinner= 1 + +/datum/sprite_accessory/mam_tails/rabbit + name = "Rabbit" + icon_state = "rabbit" + +/datum/sprite_accessory/mam_tails_animated/rabbit + name = "Rabbit" + icon_state = "rabbit" + +/datum/sprite_accessory/mam_ears/sergal + name = "Sergal" + icon_state = "sergal" + hasinner= 1 + +/datum/sprite_accessory/mam_tails/sergal + name = "Sergal" + icon_state = "sergal" + +/datum/sprite_accessory/mam_tails_animated/sergal + name = "Sergal" + icon_state = "sergal" + /datum/sprite_accessory/mam_ears/skunk name = "skunk" icon_state = "skunk" @@ -470,13 +552,13 @@ name = "skunk" icon_state = "skunk" color_src = 0 - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_tails_animated/skunk name = "skunk" icon_state = "skunk" color_src = 0 - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_tails/shark name = "Shark" @@ -486,19 +568,19 @@ /datum/sprite_accessory/mam_tails_animated/shark name = "Shark" icon_state = "shark" - color_src = 0 + color_src = MUTCOLORS /datum/sprite_accessory/mam_tails/shepherd name = "Shepherd" icon_state = "shepherd" - extra = 1 - extra2 = 1 + extra = TRUE + extra2 = TRUE /datum/sprite_accessory/mam_tails_animated/shepherd name = "Shepherd" icon_state = "shepherd" - extra = 1 - extra2 = 1 + extra = TRUE + extra2 = TRUE /datum/sprite_accessory/mam_ears/squirrel name = "Squirrel" @@ -516,7 +598,7 @@ /datum/sprite_accessory/mam_ears/wolf name = "Wolf" icon_state = "wolf" - extra = 1 + hasinner = 1 /datum/sprite_accessory/mam_tails/wolf name = "Wolf" @@ -526,26 +608,13 @@ name = "Wolf" icon_state = "wolf" -/datum/sprite_accessory/mam_tails/rabbit - name = "Rabbit" - icon_state = "rabbit" - -/datum/sprite_accessory/mam_tails_animated/rabbit - name = "Rabbit" - icon_state = "rabbit" - -/datum/sprite_accessory/mam_ears/rabbit - name = "Rabbit" - icon_state = "rabbit" - hasinner= 1 - /****************************************** ************ Body Markings **************** *******************************************/ /datum/sprite_accessory/mam_body_markings - extra = 1 - extra2 = 1 + extra = TRUE + extra2 = TRUE icon = 'icons/mob/mam_body_markings.dmi' /datum/sprite_accessory/mam_body_markings/none @@ -555,8 +624,6 @@ /datum/sprite_accessory/mam_body_markings/ailurus name = "Red Panda" icon_state = "ailurus" - extra_color_src = MUTCOLORS2 - extra2_color_src = MUTCOLORS3 gender_specific = 1 /datum/sprite_accessory/mam_body_markings/belly @@ -598,13 +665,11 @@ /datum/sprite_accessory/mam_body_markings/fennec name = "Fennec" icon_state = "Fennec" - extra_color_src = MUTCOLORS3 gender_specific = 1 /datum/sprite_accessory/mam_body_markings/fox name = "Fox" icon_state = "fox" - extra_color_src = MUTCOLORS3 gender_specific = 1 /datum/sprite_accessory/mam_body_markings/hawk @@ -668,9 +733,9 @@ /datum/sprite_accessory/taur icon = 'icons/mob/mam_taur.dmi' extra_icon = 'icons/mob/mam_taur.dmi' - extra = 1 + extra = TRUE extra2_icon = 'icons/mob/mam_taur.dmi' - extra2 = 1 + extra2 = TRUE center = TRUE dimension_x = 64 @@ -805,19 +870,17 @@ /datum/sprite_accessory/mam_body_markings/guilmon name = "Guilmon" icon_state = "guilmon" - extra_color_src = MUTCOLORS2 - extra2_color_src = MUTCOLORS3 gender_specific = 1 /datum/sprite_accessory/mam_tails/guilmon name = "Guilmon" icon_state = "guilmon" - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_tails_animated/guilmon name = "Guilmon" icon_state = "guilmon" - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_ears/guilmon name = "Guilmon" @@ -834,33 +897,33 @@ name = "DataShark" icon_state = "datashark" color_src = 0 - + /* //Till I get my snowflake only ckey lock, these are locked-locked :D /datum/sprite_accessory/mam_ears/sabresune name = "sabresune" icon_state = "sabresune" - extra = 1 + extra = TRUE extra_color_src = MUTCOLORS3 locked = TRUE /datum/sprite_accessory/mam_tails/sabresune name = "sabresune" icon_state = "sabresune" - extra = 1 + extra = TRUE locked = TRUE /datum/sprite_accessory/mam_tails_animated/sabresune name = "sabresune" icon_state = "sabresune" - extra = 1 + extra = TRUE /datum/sprite_accessory/mam_body_markings/sabresune name = "Sabresune" icon_state = "sabresune" color_src = MUTCOLORS2 - extra = 0 - extra2 = 0 + extra = FALSE + extra2 = FALSE locked = TRUE */ diff --git a/icons/mob/mam_bodyparts.dmi b/icons/mob/mam_bodyparts.dmi index 8adb82544e63385d9ea08ed94e850c54876b09cc..b8491525a7ade06848bca62bd54734b814218894 100644 GIT binary patch literal 50903 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 literal 49503 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 uflt)3Vq}>CzfsUH7WA6q(*H?6_K@=~{A1sh Date: Mon, 11 Sep 2017 20:22:24 -0500 Subject: [PATCH 092/102] Automatic changelog generation for PR #2695 [ci skip] --- html/changelogs/AutoChangeLog-pr-2695.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2695.yml diff --git a/html/changelogs/AutoChangeLog-pr-2695.yml b/html/changelogs/AutoChangeLog-pr-2695.yml new file mode 100644 index 0000000000..64cedc7d0d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2695.yml @@ -0,0 +1,7 @@ +author: "Poojawa" +delete-after: True +changes: + - rscadd: "Added Horse and Cow tails" + - rscadd: "Added Sergal ears and tails." + - tweak: "Fennec Ears a bit cleaner" + - tweak: "TRUE/FALSE in Citadel Sprites" From 4383f5e70fa92c19948dec339ea8bec6fa3df4ef Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 11 Sep 2017 21:59:51 -0400 Subject: [PATCH 093/102] Gives the webhook processor the ability to self update --- .../github_webhook_processor.php | 49 ++++++++++++++----- tools/WebhookProcessor/secret.php | 49 +++++++++++++++++++ 2 files changed, 86 insertions(+), 12 deletions(-) rename tools/{ => WebhookProcessor}/github_webhook_processor.php (93%) create mode 100644 tools/WebhookProcessor/secret.php diff --git a/tools/github_webhook_processor.php b/tools/WebhookProcessor/github_webhook_processor.php similarity index 93% rename from tools/github_webhook_processor.php rename to tools/WebhookProcessor/github_webhook_processor.php index a915c76ad2..6d62309f03 100644 --- a/tools/github_webhook_processor.php +++ b/tools/WebhookProcessor/github_webhook_processor.php @@ -17,20 +17,11 @@ //CONFIG START (all defaults are random examples, do change them) //Use single quotes for config options that are strings. - -//Github lets you have it sign the message with a secret that you can validate. This prevents people from faking events. -//This var should match the secret you configured for this webhook on github. -//This is required as otherwise somebody could trick the script into leaking the api key. + +//These are all default settings that are described in secret.php $hookSecret = '08ajh0qj93209qj90jfq932j32r'; - -$trackPRBalance = true; //set this to false to disable PR balance tracking -$prBalanceJson = ''; //Set this to the path you'd like the writable pr balance file to be stored, not setting it writes it to the working directory -$startingPRBalance = 3; //Starting balance for never before seen users -//team 133041: tgstation/commit-access -$maintainer_team_id = 133041; //org team id that is exempt from PR balance system, setting this to null will use anyone with write access to the repo. Get from https://api.github.com/orgs/:org/teams - -//Api key for pushing changelogs. $apiKey = '209ab8d879c0f987d06a09b9d879c0f987d06a09b9d8787d0a089c'; +<<<<<<< HEAD:tools/github_webhook_processor.php //servers to announce PRs to. $servers = array(); @@ -44,6 +35,22 @@ $servers[1]['address'] = 'game.tgstation13.org'; $servers[1]['port'] = '2337'; $servers[1]['comskey'] = '89aj90cq2fm0amc90832mn9rm90'; */ +======= +$repoOwnerAndName = "tgstation/tgstation"; +$servers = array(); +$enable_live_tracking = true; +$path_to_script = 'tools/WebhookProcessor/github_webhook_processor.php'; +$tracked_branch = "master"; +$trackPRBalance = true; +$prBalanceJson = ''; +$startingPRBalance = 3; +$maintainer_team_id = 133041; +$validation = "org"; +$validation_count = 1; +$tracked_branch = 'master'; + +require_once 'secret.php'; +>>>>>>> 07c1c4a... Gives the webhook processor the ability to self update (#30448):tools/WebhookProcessor/github_webhook_processor.php //CONFIG END set_error_handler(function($severity, $message, $file, $line) { @@ -221,6 +228,7 @@ function handle_pr($payload) { } else { $action = 'merged'; + auto_update($payload); checkchangelog($payload, true, true); update_pr_balance($payload); $validated = TRUE; //pr merged events always get announced. @@ -349,6 +357,23 @@ function update_pr_balance($payload) { fclose($balances_file); } +function auto_update($payload){ + global $enable_live_tracking; + global $path_to_script; + global $repoOwnerAndName; + global $tracked_branch; + if(!$enable_live_tracking || !has_tree_been_edited($payload, $path_to_script) || $payload['pull_request']['base']['ref'] != $tracked_branch) + return; + + $content = file_get_contents('https://raw.githubusercontent.com/' . $repoOwnerAndName . '/' . $tracked_branch . '/'. $path_to_script); + + create_comment($payload, "Edit detected. Self updating... Here is my new code:\n``" . "`HTML+PHP\n" . $content . "\n``" . '`'); + + $code_file = fopen(basename($path_to_script), 'w'); + fwrite($code_file, $content); + fclose($code_file); +} + function has_tree_been_edited($payload, $tree){ //go to the diff url $url = $payload['pull_request']['diff_url']; diff --git a/tools/WebhookProcessor/secret.php b/tools/WebhookProcessor/secret.php new file mode 100644 index 0000000000..abea10564f --- /dev/null +++ b/tools/WebhookProcessor/secret.php @@ -0,0 +1,49 @@ + Date: Mon, 11 Sep 2017 22:28:26 -0500 Subject: [PATCH 094/102] Update github_webhook_processor.php --- .../github_webhook_processor.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tools/WebhookProcessor/github_webhook_processor.php b/tools/WebhookProcessor/github_webhook_processor.php index 6d62309f03..0ee66acabf 100644 --- a/tools/WebhookProcessor/github_webhook_processor.php +++ b/tools/WebhookProcessor/github_webhook_processor.php @@ -21,21 +21,6 @@ //These are all default settings that are described in secret.php $hookSecret = '08ajh0qj93209qj90jfq932j32r'; $apiKey = '209ab8d879c0f987d06a09b9d879c0f987d06a09b9d8787d0a089c'; -<<<<<<< HEAD:tools/github_webhook_processor.php - -//servers to announce PRs to. -$servers = array(); -/* -$servers[0] = array(); -$servers[0]['address'] = 'game.tgstation13.org'; -$servers[0]['port'] = '1337'; -$servers[0]['comskey'] = '89aj90cq2fm0amc90832mn9rm90'; -$servers[1] = array(); -$servers[1]['address'] = 'game.tgstation13.org'; -$servers[1]['port'] = '2337'; -$servers[1]['comskey'] = '89aj90cq2fm0amc90832mn9rm90'; -*/ -======= $repoOwnerAndName = "tgstation/tgstation"; $servers = array(); $enable_live_tracking = true; @@ -50,7 +35,6 @@ $validation_count = 1; $tracked_branch = 'master'; require_once 'secret.php'; ->>>>>>> 07c1c4a... Gives the webhook processor the ability to self update (#30448):tools/WebhookProcessor/github_webhook_processor.php //CONFIG END set_error_handler(function($severity, $message, $file, $line) { From 1257a2035dbe00f2637996783e2b158ea02375ff Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 11 Sep 2017 22:41:25 -0500 Subject: [PATCH 095/102] Automatic changelog generation for PR #2566 [ci skip] --- html/changelogs/AutoChangeLog-pr-2566.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2566.yml diff --git a/html/changelogs/AutoChangeLog-pr-2566.yml b/html/changelogs/AutoChangeLog-pr-2566.yml new file mode 100644 index 0000000000..6059f590d5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2566.yml @@ -0,0 +1,5 @@ +author: "Pubby" +delete-after: True +changes: + - rscadd: "Crew-tracking pinpointers to replace laggy crew monitoring console functionality" + - rscadd: "Crew-tracking pinpointers in medical vendors and the detective's office" From 39687189b64d92b027da2131c78b88ec707a83b8 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 22:47:27 -0500 Subject: [PATCH 096/102] donation --- code/citadel/custom_loadout/custom_items.dm | 25 +++++++++++++++++++- icons/mob/neck.dmi | Bin 36568 -> 39181 bytes icons/obj/clothing/neck.dmi | Bin 2555 -> 2764 bytes 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/code/citadel/custom_loadout/custom_items.dm b/code/citadel/custom_loadout/custom_items.dm index 6495d38a0f..da81dfb37c 100644 --- a/code/citadel/custom_loadout/custom_items.dm +++ b/code/citadel/custom_loadout/custom_items.dm @@ -10,6 +10,9 @@ w_class = WEIGHT_CLASS_TINY flags_1 = NOBLUDGEON_1 + +/*Inferno707*/ + /obj/item/clothing/neck/cloak/inferno name = "Kiara's Cloak" desc = "The design on this seems a little too familiar." @@ -19,6 +22,16 @@ w_class = WEIGHT_CLASS_SMALL body_parts_covered = CHEST|GROIN|LEGS|ARMS +/obj/item/clothing/neck/petcollar/inferno + name = "Kiara's Collar" + desc = "A soft black collar that seems to stretch to fit whoever wears it." + icon_state = "infcollar" + item_state = "infcollar" + item_color = null + tagname = null + +/*DirtyOldHarry*/ + /obj/item/lighter/gold name = "\improper Engraved Zippo" desc = "A shiny and relatively expensive zippo lighter. There's a small etched in verse on the bottom that reads, 'No Gods, No Masters, Only Man.'" @@ -30,4 +43,14 @@ slot_flags = SLOT_BELT heat = 1500 resistance_flags = FIRE_PROOF - light_color = LIGHT_COLOR_FIRE \ No newline at end of file + light_color = LIGHT_COLOR_FIRE + + +/*Zombierobin*/ + +/obj/item/clothing/neck/scarf/zomb //Default white color, same functionality as beanies. + name = "A special scarf" + icon_state = "zombscarf" + desc = "A fashionable collar" + item_color = "zombscarf" + dog_fashion = /datum/dog_fashion/head \ No newline at end of file diff --git a/icons/mob/neck.dmi b/icons/mob/neck.dmi index 4618dee14bbe3f2f39095298abe0cbe2130e4cb2..e7c2d4025d5640faab2915fe602ca9e6e0022cdf 100644 GIT binary patch literal 39181 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 literal 36568 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�U}**_8I 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 diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi index 0f3668ce102b10edb3d8771d178df6bcd28f1bf6..40c4aa03bc72c8232368f640c2d77576b4ff33bd 100644 GIT binary patch delta 2668 zcmV-y3X}Ew6U-GMiBL{Q4GJ0x0000DNk~Le0001>0001h2m=5B0K2`CDUl%*IT#oi zAz_0caE^l^BaR>{f1CiWpa3W+C@n259#?{bB_5=s03;+NlAr)oR8$;GfPgF<>+90I~o8OG`jIJsnb3DNRr&Y-?PIhID;=YmuZUJeB|emX?+?Gcy5l00V#k za{vG*CnvuE07y$DLq;JzMo<V=-0C=30lfiDnFbsyz%~M3>41&Rx3j!ey>pM89+gPMc<# zwr9lgt&RW4-dZTx>G%o7rx<}Xq(HA1E>n4!5q=aw(>U*?v3q^!!k(Jr{eMIJ0T7?+ z$qODjv;Y7IaY;l$RCt{2*Ns=&NDu(<0I?{3peXUYUh5rddqR||g>sxCDA$%qR47I5 zm-zqx6F0NFfk1XPR@;Pk$HZswtuenhyED6L+9dw35s9eBqfzyEEcUqf>$-Y8GWA3$ zjK-&x!q`mWQ9^xoPA!bgtAB;j1+_4iOe7y8)ECvl$khD&lmZxyFD%3rz*r)=L<3VP zU*GKF;;b6DJU_1lt}HAlfeCt!)7m|N#^Ry^2nk%CUtT5)1roTju(CoH3QX|K(o9lT zC~5ZHM+gZt77c?gl*p5*`3NjSDv8nQ_(BwxA(6z`QZfm;rNoR!n133&k-)jxMIDwQ zl|)e?5h{bCLZUcFRO$v&eq@BuWK?LWDcfxDW*OB z?Wtt^9zd)RUGaV`vW#=Px=M{lS8#6E);zu#>M)q^soVGL+5LsOfpbf~KN4A9Ru*t{ zWktI7V$fSKcPvIG_kUR`<~63Ha2K4u&SK2NRxJ|ZN5 zj0g3r=8*{$Jb41K^+EOWERF*ISWgWmIYs#dk1XB@Y#%73iZ=?|2MQ_Q(hMds>G6Ru zv+>OJV=A*L<-zuWLb7xINOI}7a( zTeKVq=NBQQeA7ZG?S2SM@L6U>>=E*uZ9=$y9P-TxA>m`ZsVCGH9A&)tG_eK8c>ZvM z!$s%?Zm|@;%s_0)fI8#N&XHTNlR$F!5DBDq5558uY!ym;ob)oYh15+MP$ZDtJ$M4? z`sE2EPcR~bVt*0Jfau~Y5k72XMn**f=>{0#Ji7mJ9(ls*FF^oG6Uc;^KnCO=+(6D# zG-%v^eNL#Ve?vGBr#UGr5h2Wo`-?wE$JqX>JfV_D7XhS>E)EcbWl(yCafGT7W6y( z#t&E!gMFL0@VAJ>=`%Byo6%2nkBV3}c;0 zfqvtVz-;~C;B8i(L4&7|Y&50`IAx=$R-l8tCf{$=ipAm^tYa#Hr{!|_Z>(ck0(oK_V9BCwgv}zkOY8$W!$xQ^;;2|tRVzA#|290n?2o-|Fe9q}Kk}3gUm43bdc>OqA zr^W`bK_hen!6k@0&XGn2ET{xVt+WAskbjPo)1$)^5-7G{*HjMy+0+8j6pfJRGX(|E ze_ZS&6wuK56!(i|2$OWssv>y~Z`ZliPuF^j_X% zxdf~HR9#j1?lE4c*Px~b?rOWaogAV7$aFwfzwF0`!7sxF)!e{$aP49qakBGx2Y+%1 zKqr&hDDXX8?-&YjIlLn|;4nPbaJ(0J?LXSG@_xsdbhcDo&p&|DauMSUEB{;7RPhKVP zr&&By=<~dF0YcGeq`*rMibf*^;@@ZY2MYb3w=BRZ8jWoOPSt4ofA`@))qnF)AVBOl zn$BpWfdThT-^3BZo_6!0lYiBk1O$(^YGK%SPJ_- z{4D>KTB%louUa4;Pk;1?&w~IOi;#pp;&VUH$L=8sU8Ql`ll?;96%z2SFT8ax$3fuw zbKe7xJKkTMZsQG@+tT`aNz8N@amN}p!P8K<{`~oRcs>lD4v4^DAXM~x#@9pkY4rS# zMcj__SwUm{rFS>Z!k+Urt^wKWg>CSOF<*n2!?9k2x8uGBdnG+EDz>`t<4(C1Pht{3 aBmM=y5Ivq9J!tg+0000-i# zLnRI~k~XKZ6-vypRh%hHmc}#YnR8w~FTTs?y07cLuKV5nr}CyEDa*&pRaQz(3IHJM z?&jntPWT^TCB*)nSMZ~Nq_mq9l1_|cr;~QEiMydHaJLp{9!yKq(Y$#B6xITNe}8ok z7&cH}SXd~CvBasWs!}KvLqkJtZEYfvSim7ezXMPTz)i82mYSKFAx;Ac7@PrsOeS*x z@bIA7*lG9$=-IjWs8IG3_e3*ntwS}?*?QRhKDrtf#~~d|bW|WC>(aCz^W;+q*ady0%#8CF+Dg|kV@OJyXh>(l3ywmX7%`N&*qochW*a$I@U zcirM)>xbz%y9x3db5KTA!vqHarqSKW!9S^rUoL$_%~c7?e3X^;y!ZWZowKJDLgtbJ z+WFUzu&_=*LRlm(ibPpg&CD9^*@TyR44$kx{k*8x^YQv?tI3KTQ%eR5lZTHsrHp?% zkhdw6p2q|fqq=yv3%MMX!&kUF0~9yjy+v)gQGUm!TH)m|N}!7;Nby1NaL$$ya74Tm z%&=}mv7n|VeFXixnzk()Flh$rIRy?ViK&Gp>m5!E_{Bn#1d7G~U%U9(uF6I~=f{VE-`shCJ3|ufOMcFAvR9IF*19LS5~9Ex`8+gffI1CG-fF~| zSxM%Cqu`Nr06baaLfB5)_t|keL&A-gF^Ty=Q1B7#jEbN?sl%aORP&n&H(nHbLiTug z?U|vQ98X&En(&mg7T_Wt$gE+LY+uYg$?JG?T%ex@4+blv2EV$(_+a!qlqHh-NojaA zZ(86GoG&{1niP^-2g~Qt`qScNuO-MCv+Ph2W*XVfb+;9JB zc-zx+OZ$B!VODNz@B{R87|B*#uTH;OwgD5J}rK4S&;?sGDhgb zdy0|Px#@_vf{BUB+k*&Q+>bIT+T~7dd;7#d1C`(qf{$cXY2WO~D5e!bKl(F#tJJ&J z_Won`^lIn)&hoBfTm4C6G78Thau0XG1aIiV#k-96sb7Zd;{2$im%j|Hc!!(zZ?&Q2 zfpSC-vU6Zh?g(z3&1Qej#lN<9pj9F6@1x&;HOEdQqGohiJ4P?#^Lrw7Ym!NJNKaTz zxb%8@wddy`lV~+suoI(lfRJxv#OG3JBQL&mZ*9BtMwWQ%C#<@GPhL)SKHx3Cg!E~5 z{Cu~~u=7gfVDv31Oq?jOJ$1NPF4I%aE z%w!jTbq4G$g4XX&mPx33ZV5NLA?8t_o2NtWudpqx;xd;RXB5m^6Y?Y?e$m|#J6}!3 z^q&nfoiJ^ekYlPowH5FsF-`zGCN(oIQt?3GJVkO76+e;LWYgsa*Vs7w|gte)1p*VxX6Oeypy__*@FQP4XWA!{Od(v>{sH0IOYYD%-_e27l0ED*diHKw`1D+|d?GEfgNF zsn#5O(g{l>+L}*sCs=J;)7~~99*%H|M*n}FBf#qq6B8dE(`iK8L11ML804sc&xmp> z4D(Pcpy9ZG>;Zk(Z_3BUe5Iam+x5K}V+|*3d(DU9;=qbq)$lV-9+)ej6ghygnot~5 zF@m2tmQ|`mN6KFtGPfBhq`MKd;*XplD?IDgxQ1&-{`IG=0vXT_600g*r%>Rt)Fo;0 z8ouq+JBc(%*Al4@S~T(T&GHOH`6|q0Yg0XW9x0xY zlY*{^LE~QtPYSvrh9EH*fMDKgK~`FlL=EdZBlxe?EOA%-r%&=$E5u#8hGialL7p0S z%ITNJrpFi~wp-Ea{ta%geB_)!i}?4H?&E{>aiQLX|(kKh{ z5ZRz&&a+!bu#QG~-@Zahsmq(fbZVCXnl+NW3@ujcFT)+MWrwiS$B%Z4!p(usO4P2EvLoo0MBnO?z8y4N;45xFU*?Jn_ugp0AIy(Gr6?Kn bWe9e5eI*;8$sRBi|0lrR*~{rJotgGOlG{`& From c3ef612490b9e23a75ae6669499f24ba9f3ed402 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 23:07:30 -0500 Subject: [PATCH 097/102] Ports MSO's fading note system --- SQL/database_changelog.txt | 58 ++++++++++++++------ SQL/errofreedatabase.sql | 2 +- SQL/optimisations_2017-02-19.sql | 68 ++++++++++++------------ SQL/tgstation_schema.sql | 9 ++-- SQL/tgstation_schema.sql.rej | 9 ---- SQL/tgstation_schema_prefixed.sql | 11 ++-- SQL/tgstation_schema_prefixed.sql.rej | 9 ---- code/controllers/configuration.dm | 6 +++ code/modules/admin/sql_message_system.dm | 57 ++++++++++++++------ code/modules/admin/topic.dm | 5 +- code/modules/client/client_procs.dm | 4 +- code/modules/client/verbs/ooc.dm | 2 +- 12 files changed, 142 insertions(+), 98 deletions(-) delete mode 100644 SQL/tgstation_schema.sql.rej delete mode 100644 SQL/tgstation_schema_prefixed.sql.rej diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index c2625e2663..7063273378 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -1,13 +1,52 @@ Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255. -The latest database version is 3.1; The query to update the schema revision table is: +The latest database version is 3.4; The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 1); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 4); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 1); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 4); + +In any query remember to add a prefix to the table names if you use one. ---------------------------------------------------- +28 August 2017, by MrStonedOne +Modified table 'messages', adding a deleted column and editing all indexes to include it + +ALTER TABLE `messages` +ADD COLUMN `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' AFTER `edits`, +DROP INDEX `idx_msg_ckey_time`, +DROP INDEX `idx_msg_type_ckeys_time`, +DROP INDEX `idx_msg_type_ckey_time_odr`, +ADD INDEX `idx_msg_ckey_time` (`targetckey`,`timestamp`, `deleted`), +ADD INDEX `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`, `deleted`), +ADD INDEX `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`, `deleted`); + +---------------------------------------------------- + +25 August 2017, by Jordie0608 + +Modified tables 'connection_log', 'legacy_population', 'library', 'messages' and 'player' to add additional 'round_id' tracking in various forms and 'server_ip' and 'server_port' to the table 'messages'. + +ALTER TABLE `connection_log` ADD COLUMN `round_id` INT(11) UNSIGNED NOT NULL AFTER `server_port`; +ALTER TABLE `legacy_population` ADD COLUMN `round_id` INT(11) UNSIGNED NOT NULL AFTER `server_port`; +ALTER TABLE `library` ADD COLUMN `round_id_created` INT(11) UNSIGNED NOT NULL AFTER `deleted`; +ALTER TABLE `messages` ADD COLUMN `server_ip` INT(10) UNSIGNED NOT NULL AFTER `server`, ADD COLUMN `server_port` SMALLINT(5) UNSIGNED NOT NULL AFTER `server_ip`, ADD COLUMN `round_id` INT(11) UNSIGNED NOT NULL AFTER `server_port`; +ALTER TABLE `player` ADD COLUMN `firstseen_round_id` INT(11) UNSIGNED NOT NULL AFTER `firstseen`, ADD COLUMN `lastseen_round_id` INT(11) UNSIGNED NOT NULL AFTER `lastseen`; + +---------------------------------------------------- + +18 August 2017, by Cyberboss and nfreader + +Modified table 'death', adding the columns `last_words` and 'suicide'. + +ALTER TABLE `death` +ADD COLUMN `last_words` varchar(255) DEFAULT NULL AFTER `staminaloss`, +ADD COLUMN `suicide` tinyint(0) NOT NULL DEFAULT '0' AFTER `last_words`; + +Remember to add a prefix to the table name if you use them. + +---------------------------------------------------- 20th July 2017, by Shadowlight213 Added role_time table to track time spent playing departments. @@ -17,21 +56,10 @@ CREATE TABLE `role_time` ( `ckey` VARCHAR(32) NOT NULL , `job` VARCHAR(128) NOT ALTER TABLE `player` ADD `flags` INT NOT NULL default '0' AFTER `accountjoindate`; - -UPDATE `schema_revision` SET minor = 1; Remember to add a prefix to the table name if you use them. ---------------------------------------------------- -Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255. - -The latest database version is 3.0; The query to update the schema revision table is: - -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 0); -or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 0); - ----------------------------------------------------- 28 June 2017, by oranges Added schema_revision to store the current db revision, why start at 3.0? @@ -336,4 +364,4 @@ UPDATE erro_library SET deleted = 1 WHERE id = someid (Replace someid with the id of the book you want to soft delete.) ----------------------------------------------------- +---------------------------------------------------- \ No newline at end of file diff --git a/SQL/errofreedatabase.sql b/SQL/errofreedatabase.sql index 7f23fcc861..7d6ea4561c 100644 --- a/SQL/errofreedatabase.sql +++ b/SQL/errofreedatabase.sql @@ -12,4 +12,4 @@ ALTER TABLE erro_poll_option RENAME TO SS13_poll_option; ALTER TABLE erro_poll_question RENAME TO SS13_poll_question; ALTER TABLE erro_poll_textreply RENAME TO SS13_poll_textreply; ALTER TABLE erro_poll_vote RENAME TO SS13_poll_vote; -ALTER TABLE erro_watch RENAME TO SS13_watch; +ALTER TABLE erro_watch RENAME TO SS13_watch; \ No newline at end of file diff --git a/SQL/optimisations_2017-02-19.sql b/SQL/optimisations_2017-02-19.sql index 674cbcf9c6..b9017497ed 100644 --- a/SQL/optimisations_2017-02-19.sql +++ b/SQL/optimisations_2017-02-19.sql @@ -38,7 +38,7 @@ Take note some columns have been renamed, removed or changed type. Any services ----------------------------------------------------*/ START TRANSACTION; -ALTER TABLE `feedback`.`ban` +ALTER TABLE `ban` DROP COLUMN `rounds` , CHANGE COLUMN `bantype` `bantype` ENUM('PERMABAN', 'TEMPBAN', 'JOB_PERMABAN', 'JOB_TEMPBAN', 'ADMIN_PERMABAN', 'ADMIN_TEMPBAN') NOT NULL , CHANGE COLUMN `reason` `reason` VARCHAR(2048) NOT NULL @@ -51,14 +51,14 @@ ALTER TABLE `feedback`.`ban` , ADD COLUMN `a_ipTEMP` INT UNSIGNED NOT NULL AFTER `a_ip` , ADD COLUMN `unbanned_ipTEMP` INT UNSIGNED NULL DEFAULT NULL AFTER `unbanned_ip`; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`ban` +UPDATE `ban` SET `server_ip` = INET_ATON(SUBSTRING_INDEX(IF(`serverip` = '', '0', IF(SUBSTRING_INDEX(`serverip`, ':', 1) LIKE '%_._%', `serverip`, '0')), ':', 1)) , `server_port` = IF(`serverip` LIKE '%:_%', CAST(SUBSTRING_INDEX(`serverip`, ':', -1) AS UNSIGNED), '0') , `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0')) , `a_ipTEMP` = INET_ATON(IF(`a_ip` LIKE '%_._%', `a_ip`, '0')) , `unbanned_ipTEMP` = INET_ATON(IF(`unbanned_ip` LIKE '%_._%', `unbanned_ip`, '0')); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`ban` +ALTER TABLE `ban` DROP COLUMN `unbanned_ip` , DROP COLUMN `a_ip` , DROP COLUMN `ip` @@ -69,17 +69,17 @@ ALTER TABLE `feedback`.`ban` COMMIT; START TRANSACTION; -ALTER TABLE `feedback`.`connection_log` +ALTER TABLE `connection_log` ADD COLUMN `server_ip` INT UNSIGNED NOT NULL AFTER `serverip` , ADD COLUMN `server_port` SMALLINT UNSIGNED NOT NULL AFTER `server_ip` , ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`connection_log` +UPDATE `connection_log` SET `server_ip` = INET_ATON(SUBSTRING_INDEX(IF(`serverip` = '', '0', IF(SUBSTRING_INDEX(`serverip`, ':', 1) LIKE '%_._%', `serverip`, '0')), ':', 1)) , `server_port` = IF(`serverip` LIKE '%:_%', CAST(SUBSTRING_INDEX(`serverip`, ':', -1) AS UNSIGNED), '0') , `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0')); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`connection_log` +ALTER TABLE `connection_log` DROP COLUMN `ip` , DROP COLUMN `serverip` , CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL; @@ -87,12 +87,12 @@ COMMIT; START TRANSACTION; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`death` +UPDATE `death` SET `bruteloss` = LEAST(`bruteloss`, 65535) , `brainloss` = LEAST(`brainloss`, 65535) , `fireloss` = LEAST(`fireloss`, 65535) , `oxyloss` = LEAST(`oxyloss`, 65535); -ALTER TABLE `feedback`.`death` +ALTER TABLE `death` CHANGE COLUMN `pod` `pod` VARCHAR(50) NOT NULL , CHANGE COLUMN `coord` `coord` VARCHAR(32) NOT NULL , CHANGE COLUMN `mapname` `mapname` VARCHAR(32) NOT NULL @@ -109,39 +109,39 @@ ALTER TABLE `feedback`.`death` , CHANGE COLUMN `oxyloss` `oxyloss` SMALLINT UNSIGNED NOT NULL , ADD COLUMN `server_ip` INT UNSIGNED NOT NULL AFTER `server` , ADD COLUMN `server_port` SMALLINT UNSIGNED NOT NULL AFTER `server_ip`; -UPDATE `feedback`.`death` +UPDATE `death` SET `server_ip` = INET_ATON(SUBSTRING_INDEX(IF(`server` = '', '0', IF(SUBSTRING_INDEX(`server`, ':', 1) LIKE '%_._%', `server`, '0')), ':', 1)) , `server_port` = IF(`server` LIKE '%:_%', CAST(SUBSTRING_INDEX(`server`, ':', -1) AS UNSIGNED), '0'); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`death` +ALTER TABLE `death` DROP COLUMN `server`; COMMIT; -ALTER TABLE `feedback`.`library` +ALTER TABLE `library` CHANGE COLUMN `category` `category` ENUM('Any', 'Fiction', 'Non-Fiction', 'Adult', 'Reference', 'Religion') NOT NULL , CHANGE COLUMN `ckey` `ckey` VARCHAR(32) NOT NULL DEFAULT 'LEGACY' , CHANGE COLUMN `datetime` `datetime` DATETIME NOT NULL , CHANGE COLUMN `deleted` `deleted` TINYINT(1) UNSIGNED NULL DEFAULT NULL; -ALTER TABLE `feedback`.`messages` +ALTER TABLE `messages` CHANGE COLUMN `type` `type` ENUM('memo', 'message', 'message sent', 'note', 'watchlist entry') NOT NULL , CHANGE COLUMN `text` `text` VARCHAR(2048) NOT NULL , CHANGE COLUMN `secret` `secret` TINYINT(1) UNSIGNED NOT NULL; START TRANSACTION; -ALTER TABLE `feedback`.`player` +ALTER TABLE `player` ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`player` +UPDATE `player` SET `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0')); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`player` +ALTER TABLE `player` DROP COLUMN `ip` , CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL; COMMIT; START TRANSACTION; -ALTER TABLE `feedback`.`poll_question` +ALTER TABLE `poll_question` CHANGE COLUMN `polltype` `polltype` ENUM('OPTION', 'TEXT', 'NUMVAL', 'MULTICHOICE', 'IRV') NOT NULL , CHANGE COLUMN `adminonly` `adminonly` TINYINT(1) UNSIGNED NOT NULL , CHANGE COLUMN `createdby_ckey` `createdby_ckey` VARCHAR(32) NULL DEFAULT NULL @@ -149,36 +149,36 @@ ALTER TABLE `feedback`.`poll_question` , ADD COLUMN `createdby_ipTEMP` INT UNSIGNED NOT NULL AFTER `createdby_ip` , DROP COLUMN `for_trialmin`; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`poll_question` +UPDATE `poll_question` SET `createdby_ipTEMP` = INET_ATON(IF(`createdby_ip` LIKE '%_._%', `createdby_ip`, '0')); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`poll_question` +ALTER TABLE `poll_question` DROP COLUMN `createdby_ip` , CHANGE COLUMN `createdby_ipTEMP` `createdby_ip` INT(10) UNSIGNED NOT NULL; COMMIT; START TRANSACTION; -ALTER TABLE `feedback`.`poll_textreply` +ALTER TABLE `poll_textreply` CHANGE COLUMN `replytext` `replytext` VARCHAR(2048) NOT NULL , ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`poll_textreply` +UPDATE `poll_textreply` SET `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0')); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`poll_textreply` +ALTER TABLE `poll_textreply` DROP COLUMN `ip` , CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL; COMMIT; START TRANSACTION; -ALTER TABLE `feedback`.`poll_vote` +ALTER TABLE `poll_vote` CHANGE COLUMN `ckey` `ckey` VARCHAR(32) NOT NULL , ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`; SET SQL_SAFE_UPDATES = 0; -UPDATE `feedback`.`poll_vote` +UPDATE `poll_vote` SET `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0')); SET SQL_SAFE_UPDATES = 1; -ALTER TABLE `feedback`.`poll_vote` +ALTER TABLE `poll_vote` DROP COLUMN `ip` , CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL; COMMIT; @@ -191,39 +191,39 @@ You may find it helpful to modify or create your own indexes if you utilise addi ----------------------------------------------------*/ -ALTER TABLE `feedback`.`ban` +ALTER TABLE `ban` ADD INDEX `idx_ban_checkban` (`ckey` ASC, `bantype` ASC, `expiration_time` ASC, `unbanned` ASC, `job` ASC) , ADD INDEX `idx_ban_isbanned` (`ckey` ASC, `ip` ASC, `computerid` ASC, `bantype` ASC, `expiration_time` ASC, `unbanned` ASC) , ADD INDEX `idx_ban_count` (`id` ASC, `a_ckey` ASC, `bantype` ASC, `expiration_time` ASC, `unbanned` ASC); -ALTER TABLE `feedback`.`ipintel` +ALTER TABLE `ipintel` ADD INDEX `idx_ipintel` (`ip` ASC, `intel` ASC, `date` ASC); -ALTER TABLE `feedback`.`library` +ALTER TABLE `library` ADD INDEX `idx_lib_id_del` (`id` ASC, `deleted` ASC) , ADD INDEX `idx_lib_del_title` (`deleted` ASC, `title` ASC) , ADD INDEX `idx_lib_search` (`deleted` ASC, `author` ASC, `title` ASC, `category` ASC); -ALTER TABLE `feedback`.`messages` +ALTER TABLE `messages` ADD INDEX `idx_msg_ckey_time` (`targetckey` ASC, `timestamp` ASC) , ADD INDEX `idx_msg_type_ckeys_time` (`type` ASC, `targetckey` ASC, `adminckey` ASC, `timestamp` ASC) , ADD INDEX `idx_msg_type_ckey_time_odr` (`type` ASC, `targetckey` ASC, `timestamp` ASC); -ALTER TABLE `feedback`.`player` +ALTER TABLE `player` ADD INDEX `idx_player_cid_ckey` (`computerid` ASC, `ckey` ASC) , ADD INDEX `idx_player_ip_ckey` (`ip` ASC, `ckey` ASC); -ALTER TABLE `feedback`.`poll_option` +ALTER TABLE `poll_option` ADD INDEX `idx_pop_pollid` (`pollid` ASC); -ALTER TABLE `feedback`.`poll_question` +ALTER TABLE `poll_question` ADD INDEX `idx_pquest_question_time_ckey` (`question` ASC, `starttime` ASC, `endtime` ASC, `createdby_ckey` ASC, `createdby_ip` ASC) , ADD INDEX `idx_pquest_time_admin` (`starttime` ASC, `endtime` ASC, `adminonly` ASC) , ADD INDEX `idx_pquest_id_time_type_admin` (`id` ASC, `starttime` ASC, `endtime` ASC, `polltype` ASC, `adminonly` ASC); -ALTER TABLE `feedback`.`poll_vote` +ALTER TABLE `poll_vote` ADD INDEX `idx_pvote_pollid_ckey` (`pollid` ASC, `ckey` ASC) , ADD INDEX `idx_pvote_optionid_ckey` (`optionid` ASC, `ckey` ASC); -ALTER TABLE `feedback`.`poll_textreply` - ADD INDEX `idx_ptext_pollid_ckey` (`pollid` ASC, `ckey` ASC); +ALTER TABLE `poll_textreply` + ADD INDEX `idx_ptext_pollid_ckey` (`pollid` ASC, `ckey` ASC); \ No newline at end of file diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 12b0b93c6a..1edd5ad12b 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -254,10 +254,11 @@ CREATE TABLE `messages` ( `secret` tinyint(1) unsigned NOT NULL, `lasteditor` varchar(32) DEFAULT NULL, `edits` text, + `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), - KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`), - KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`), - KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`) + KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`, `deleted`), + KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`, `deleted`), + KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`, `deleted`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; @@ -430,4 +431,4 @@ CREATE TABLE `schema_revision` ( /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; \ No newline at end of file diff --git a/SQL/tgstation_schema.sql.rej b/SQL/tgstation_schema.sql.rej deleted file mode 100644 index 51068bed4e..0000000000 --- a/SQL/tgstation_schema.sql.rej +++ /dev/null @@ -1,9 +0,0 @@ -diff a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql (rejected hunks) -@@ -268,7 +283,6 @@ CREATE TABLE `player` ( - `ip` int(10) unsigned NOT NULL, - `computerid` varchar(32) NOT NULL, - `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player', -- `exp` mediumtext, - PRIMARY KEY (`id`), - UNIQUE KEY `ckey` (`ckey`), - KEY `idx_player_cid_ckey` (`computerid`,`ckey`), diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 6c8ea19b0f..72045e50fb 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -31,7 +31,7 @@ CREATE TABLE `SS13_admin` ( -- Table structure for table `SS13_admin_log` -- -DROP TABLE IF EXISTS `SS13_dmin_log`; +DROP TABLE IF EXISTS `SS13_admin_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `SS13_admin_log` ( @@ -254,10 +254,11 @@ CREATE TABLE `SS13_messages` ( `secret` tinyint(1) unsigned NOT NULL, `lasteditor` varchar(32) DEFAULT NULL, `edits` text, + `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), - KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`), - KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`), - KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`) + KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`, `deleted`), + KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`, `deleted`), + KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`, `deleted`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; @@ -430,4 +431,4 @@ CREATE TABLE `SS13_schema_revision` ( /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; \ No newline at end of file diff --git a/SQL/tgstation_schema_prefixed.sql.rej b/SQL/tgstation_schema_prefixed.sql.rej deleted file mode 100644 index dd4bc6a7f5..0000000000 --- a/SQL/tgstation_schema_prefixed.sql.rej +++ /dev/null @@ -1,9 +0,0 @@ -diff a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql (rejected hunks) -@@ -268,7 +297,6 @@ CREATE TABLE `SS13_player` ( - `ip` int(10) unsigned NOT NULL, - `computerid` varchar(32) NOT NULL, - `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player', -- `exp` mediumtext, - PRIMARY KEY (`id`), - UNIQUE KEY `ckey` (`ckey`), - KEY `idx_player_cid_ckey` (`computerid`,`ckey`), diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index bba82e6c8a..5da6c80b3a 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -108,6 +108,8 @@ GLOBAL_PROTECT(config_dir) var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database var/use_account_age_for_jobs = 0 //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected. var/see_own_notes = 0 //Can players see their own admin notes (read-only)? Config option in config.txt + var/note_fresh_days + var/note_stale_days var/use_exp_tracking = FALSE var/use_exp_restrictions_heads = FALSE @@ -484,6 +486,10 @@ GLOBAL_PROTECT(config_dir) showircname = 1 if("see_own_notes") see_own_notes = 1 + if("note_fresh_days") + note_fresh_days = text2num(value) + if("note_stale_days") + note_stale_days = text2num(value) if("soft_popcap") soft_popcap = text2num(value) if("hard_popcap") diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index b42fe93eef..ee13db8978 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -56,7 +56,7 @@ if(browse) browse_messages("[type]") else - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) /proc/delete_message(message_id, logged = 1, browse) if(!SSdbcore.Connect()) @@ -68,14 +68,14 @@ var/type var/target_ckey var/text - var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") if(!query_find_del_message.warn_execute()) return if(query_find_del_message.NextRow()) type = query_find_del_message.item[1] target_ckey = query_find_del_message.item[2] text = query_find_del_message.item[4] - var/datum/DBQuery/query_del_message = SSdbcore.NewQuery("DELETE FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_del_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET deleted = 1 WHERE id = [message_id]") if(!query_del_message.warn_execute()) return if(logged) @@ -84,7 +84,7 @@ if(browse) browse_messages("[type]") else - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) /proc/edit_message(message_id, browse) if(!SSdbcore.Connect()) @@ -93,7 +93,7 @@ message_id = text2num(message_id) if(!message_id) return - var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") if(!query_find_edit_message.warn_execute()) return if(query_find_edit_message.NextRow()) @@ -107,7 +107,7 @@ return new_text = sanitizeSQL(new_text) var/edit_text = sanitizeSQL("Edited by [editor_ckey] on [SQLtime()] from
    [old_text]
    to
    [new_text]


    ") - var/datum/DBQuery/query_edit_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET text = '[new_text]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id]") + var/datum/DBQuery/query_edit_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET text = '[new_text]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0") if(!query_edit_message.warn_execute()) return log_admin_private("[key_name(usr)] has edited a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_ckey]" : ""] made by [admin_ckey] from [old_text] to [new_text]") @@ -115,7 +115,7 @@ if(browse) browse_messages("[type]") else - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) /proc/toggle_message_secrecy(message_id) if(!SSdbcore.Connect()) @@ -124,7 +124,7 @@ message_id = text2num(message_id) if(!message_id) return - var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, secret FROM [format_table_name("messages")] WHERE id = [message_id]") + var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, secret FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") if(!query_find_message_secret.warn_execute()) return if(query_find_message_secret.NextRow()) @@ -139,9 +139,9 @@ return log_admin_private("[key_name(usr)] has toggled [target_ckey]'s [type] made by [admin_ckey] to [secret ? "not secret" : "secret"]") message_admins("[key_name_admin(usr)] has toggled [target_ckey]'s [type] made by [admin_ckey] to [secret ? "not secret" : "secret"]") - browse_messages(target_ckey = target_ckey) + browse_messages(target_ckey = target_ckey, agegate = TRUE) -/proc/browse_messages(type, target_ckey, index, linkless = 0, filter) +/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE) if(!SSdbcore.Connect()) to_chat(usr, "Failed to establish database connection.") return @@ -169,7 +169,7 @@ else output += "|\[Filter offline clients\]" output += ruler - var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, targetckey, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]'") + var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, targetckey, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0") if(!query_get_type_messages.warn_execute()) return while(query_get_type_messages.NextRow()) @@ -193,12 +193,13 @@ output += "
    [text]
    " if(target_ckey) target_ckey = sanitizeSQL(target_ckey) - var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, adminckey, text, timestamp, server, lasteditor FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' ORDER BY timestamp DESC") + var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, adminckey, text, timestamp, server, lasteditor, DATEDIFF(NOW(), timestamp) AS `age` FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' AND deleted = 0 ORDER BY timestamp DESC") if(!query_get_messages.warn_execute()) return var/messagedata var/watchdata var/notedata + var/skipped = 0 while(query_get_messages.NextRow()) type = query_get_messages.item[1] if(type == "memo") @@ -212,8 +213,21 @@ var/timestamp = query_get_messages.item[6] var/server = query_get_messages.item[7] var/editor_ckey = query_get_messages.item[8] + var/age = text2num(query_get_messages.item[9]) + var/alphatext = "" + if (agegate && type == "note" && isnum(config.note_stale_days) && isnum(config.note_fresh_days) && config.note_stale_days > config.note_fresh_days) + var/alpha = Clamp(100 - (age - config.note_fresh_days) * (85 / (config.note_stale_days - config.note_fresh_days)), 15, 100) + if (alpha < 100) + if (alpha <= 15) + if (skipped) + skipped++ + continue + alpha = 10 + skipped = TRUE + alphatext = "filter: alpha(opacity=[alpha]); opacity: [alpha/100];" + var/data - data += "[timestamp] | [server] | [admin_ckey]" + data += "

    [timestamp] | [server] | [admin_ckey]" if(!linkless) data += " \[Delete\]" if(type == "note") @@ -226,7 +240,7 @@ data += " \[Edit\]" if(editor_ckey) data += " Last edit by [editor_ckey] (Click here to see edit log)" - data += "
    [text]


    " + data += "
    [text]


    " switch(type) if("message") messagedata += data @@ -254,6 +268,15 @@ if(notedata) output += "

    Notes

    " output += notedata + if(!linkless) + if (agegate) + if (skipped) //the first skipped message is still shown so that we can put this link over it. + output += "
    \[Show [skipped] hidden messages\]
    " + else + output += "
    \[Show All\]
    " + + else + output += "
    \[Hide Old\]
    " if(index) var/index_ckey var/search @@ -268,7 +291,7 @@ search = "^\[^\[:alpha:\]\]" else search = "^[index]" - var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' ORDER BY targetckey") + var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 ORDER BY targetckey") if(!query_list_messages.warn_execute()) return while(query_list_messages.NextRow()) @@ -277,7 +300,7 @@ else if(!type && !target_ckey && !index) output += "
    \[Add message\]\[Add watchlist entry\]\[Add note\]
    " output += ruler - usr << browse(output, "window=browse_messages;size=900x500") + usr << browse({"[output]"}, "window=browse_messages;size=900x500") proc/get_message_output(type, target_ckey) if(!SSdbcore.Connect()) @@ -288,7 +311,7 @@ proc/get_message_output(type, target_ckey) var/output if(target_ckey) target_ckey = sanitizeSQL(target_ckey) - var/query = "SELECT id, adminckey, text, timestamp, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]'" + var/query = "SELECT id, adminckey, text, timestamp, lasteditor FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0" if(type == "message" || type == "watchlist entry") query += " AND targetckey = '[target_ckey]'" var/datum/DBQuery/query_get_message_output = SSdbcore.NewQuery(query) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index f7b0f8b6ff..839bdfc5f0 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1107,7 +1107,10 @@ else if(href_list["showmessageckey"]) var/target = href_list["showmessageckey"] - browse_messages(target_ckey = target) + var/agegate = TRUE + if (href_list["showall"]) + agegate = FALSE + browse_messages(target_ckey = target, agegate = agegate) else if(href_list["showmessageckeylinkless"]) var/target = href_list["showmessageckeylinkless"] diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 6135e6ac9d..6fbc7d552f 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -577,13 +577,13 @@ GLOBAL_LIST(external_rsc_urls) var/const/adminckey = "CID-Error" var/sql_ckey = sanitizeSQL(ckey) //check to see if we noted them in the last day. - var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()") + var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0") if(!query_get_notes.Execute()) return if(query_get_notes.NextRow()) return //regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over. - query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' ORDER BY timestamp DESC LIMIT 1") + query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 ORDER BY timestamp DESC LIMIT 1") if(!query_get_notes.Execute()) return if(query_get_notes.NextRow()) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index cd0f893fa6..a86b30e605 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -234,7 +234,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, OOC_COLOR) to_chat(usr, "Sorry, that function is not enabled on this server.") return - browse_messages(null, usr.ckey, null, 1) + browse_messages(null, usr.ckey, null, TRUE) /client/proc/ignore_key(client) var/client/C = client From 1cea5d6e4b8fd88da0700362d73619d45d78f5f4 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 23:41:45 -0500 Subject: [PATCH 098/102] Update one_click_antag.dm --- code/modules/admin/verbs/one_click_antag.dm | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index c637389031..de0cb36448 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -357,6 +357,43 @@ return +/datum/admins/proc/makeGangsters() + + var/datum/game_mode/gang/temp = new + if(config.protect_roles_from_antagonist) + temp.restricted_jobs += temp.protected_jobs + + if(config.protect_assistant_from_antagonist) + temp.restricted_jobs += "Assistant" + + var/list/mob/living/carbon/human/candidates = list() + var/mob/living/carbon/human/H = null + + for(var/mob/living/carbon/human/applicant in GLOB.player_list) + if(ROLE_GANG in applicant.client.prefs.be_special) + var/turf/T = get_turf(applicant) + if(applicant.stat == CONSCIOUS && applicant.mind && !applicant.mind.special_role && T.z == ZLEVEL_STATION) + if(!jobban_isbanned(applicant, ROLE_GANG) && !jobban_isbanned(applicant, "Syndicate")) + if(temp.age_check(applicant.client)) + if(!(applicant.job in temp.restricted_jobs)) + candidates += applicant + + if(candidates.len >= 2) + for(var/needs_assigned=2,needs_assigned>0,needs_assigned--) + H = pick(candidates) + if(GLOB.gang_colors_pool.len) + var/datum/gang/newgang = new() + SSticker.mode.gangs += newgang + H.mind.make_Gang(newgang) + candidates.Remove(H) + else if(needs_assigned == 2) + return 0 + return 1 + + return 0 + + + /datum/admins/proc/makeOfficial() var/mission = input("Assign a task for the official", "Assign Task", "Conduct a routine preformance review of [station_name()] and its Captain.") var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered to be a CentCom Official?", "deathsquad") From d0451037449a5f8d08b35b4d2891981c5c6aa9a4 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Tue, 12 Sep 2017 00:48:22 -0500 Subject: [PATCH 099/102] Update life.dm --- code/modules/mob/living/carbon/life.dm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 4f6e28ebf2..9065ceb30a 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -65,11 +65,11 @@ else if(health <= HEALTH_THRESHOLD_CRIT) losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times - //Suffocate + //Suffocate if(losebreath >= 1) //You've missed a breath, take oxy damage losebreath-- - if(prob(10)) - emote("gasp") + if(prob(10)) + emote("gasp") if(istype(loc, /obj/)) var/obj/loc_as_obj = loc loc_as_obj.handle_internal_lifeform(src,0) @@ -117,9 +117,7 @@ loc_as_obj.handle_internal_lifeform(src,0) if(!breath || (breath.total_moles() == 0) || !lungs) if(reagents.has_reagent("epinephrine") && lungs) return - var/oxy_loss = min(losebreath, 1) - adjustOxyLoss(oxy_loss) - losebreath -= oxy_loss + adjustOxyLoss(1) failed_last_breath = 1 throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) return 0 From 2ae18cd35e65abc116389dcbea0b0473f283b961 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Tue, 12 Sep 2017 00:52:07 -0500 Subject: [PATCH 100/102] Update life.dm --- code/modules/mob/living/carbon/life.dm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 9065ceb30a..60900e298f 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -65,14 +65,14 @@ else if(health <= HEALTH_THRESHOLD_CRIT) losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times - //Suffocate - if(losebreath >= 1) //You've missed a breath, take oxy damage - losebreath-- - if(prob(10)) - emote("gasp") +//Start of a breath chain, calls breathe() +/mob/living/carbon/handle_breathing(times_fired) + if((times_fired % 4) == 2 || failed_last_breath) + breathe() //Breathe per 4 ticks, unless suffocating + else if(istype(loc, /obj/)) - var/obj/loc_as_obj = loc -loc_as_obj.handle_internal_lifeform(src,0) + var/obj/location_as_object = loc + location_as_object.handle_internal_lifeform(src,0) else //Breathe from internal breath = get_breath_from_internal(BREATH_VOLUME) From fcbebe64235143a218bb1fa116191ec18319fac9 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Tue, 12 Sep 2017 01:03:11 -0500 Subject: [PATCH 101/102] Update life.dm --- code/modules/mob/living/carbon/life.dm | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 60900e298f..b2e88e278a 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -65,14 +65,15 @@ else if(health <= HEALTH_THRESHOLD_CRIT) losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times -//Start of a breath chain, calls breathe() -/mob/living/carbon/handle_breathing(times_fired) - if((times_fired % 4) == 2 || failed_last_breath) - breathe() //Breathe per 4 ticks, unless suffocating - else + + //Suffocate + if(losebreath >= 1) //You've missed a breath, take oxy damage + losebreath-- + if(prob(10)) + emote("gasp") if(istype(loc, /obj/)) - var/obj/location_as_object = loc - location_as_object.handle_internal_lifeform(src,0) + var/obj/loc_as_obj = loc + loc_as_obj.handle_internal_lifeform(src,0) else //Breathe from internal breath = get_breath_from_internal(BREATH_VOLUME) From dee34c6e7e3dd26d057bd2ed410e8544509d33f7 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Tue, 12 Sep 2017 01:21:10 -0500 Subject: [PATCH 102/102] Automatic changelog generation for PR #2691 [ci skip] --- html/changelogs/AutoChangeLog-pr-2691.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2691.yml diff --git a/html/changelogs/AutoChangeLog-pr-2691.yml b/html/changelogs/AutoChangeLog-pr-2691.yml new file mode 100644 index 0000000000..e4eecf7efc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2691.yml @@ -0,0 +1,4 @@ +author: "Basilman" +delete-after: True +changes: + - rscadd: "A strange asteroid has drifted nearby..."

    QK_A%; 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 S$b$fM9C!9`s>cMvZu|o!Ybr?q delta 104658 zcmXt91z1#3(_Xr}ySqz58VN~hq&uah7cSk1N_UB%NQyK|gMui60!l0$(!C4I?!SKj z_dO2_d+(W38_Wl@-1Kb!xV+R`rgzBpH5`P?yPd;q6hub|nK4DB| zofu$CnP=&GiR-LqV9H#k@aXBU@;5@whfWJrHSZL`VO9Og>u1Ps)hR0*A+1jhJ$Bzp zJiIJV-pF}|TT!X*9#B>7Bqil?`yr(O*uGtN>wfAtu5vR#hmws54y=-qIjMif9Z&zr zYico4=iRff%hJj8>KS9LB7IfOiocdNX17|6VD4bPOaq}H+MquHK zfs3_PY3s17CpO)vnR3BVDf=R!d*AlCVo*Ta`-f|^vIil*wHyPre^cc(Cy$Mr%Un@- zKRx_RaQVNQ%4aSM zV;4MeX**^XpSH4#xL~mJ%v9Yr-UV#pS-Em#o@7LobiWQBR9vZ=)mI`6zj!{kr>*q2 zGn3w3|6xSN#P;T85V?)u$il7DM_U!Jg2AD!q=-fqF7Bdp;YixLR%n$>UYOc?4NLV0!TBWBGvMWH7GAWf z{gX!{_f+kxClqfqEF2C;VCTQwwcViUERTyaOED(t1y~)@KYqs9mq>MP&T>f%6V_M? zG)U^lb?)U0M&XHeLfbY2)!=OX!>rT2GD!zrV; zdnl}&-(G*|SU)eip^GiSrJeCovFT}OPCHQt=82c6g2BX2>T&{p+heS=uUg0l-HHcj zZF#5@4#KN~&pgPtO&N@NjR}l3aJAM*3zMq8#);-zw&1miSX5S8dH`o;t>^S8upl&@ z_B;%yrBrF)S(nCYwNkNs-d*l2hlr?#iQIeP&e7rEl)BT4JZ3 z>_ST#Bm+6yI{9fQ?#+~;=^R|+BaVLLU1>HqQjc`FhV6>3tJS*7BvEwrih|}Ayd@Uj z2^R<(Eka$|ylN}M4F5K9tmZRFbnT5W=B3A$R*FulbxQPL~f?>UX=K z)Xpl-&3Ccwf+C>4e$tn;%oOwohG@$p?eYn#=O`{#%oBU3`BJnpHU1g%M$vhnAEC$} zLQ@bO#7QLGGUtU?K$QXJ_E6^h=nH9XPK*uc#_{D_$}U;Yt1|tyIAY&7+;v!*rk?xM%ub%@gs09X>G3T;z}o7+w!>TN$WW+ zHfFs+z-EcpMOOIIX+8yZ_gK(3-n~~Wk0UlyUQHI3CYUbRYB{H#3>Qo4l=XMX&Qwl3 zdL-n3$Nny#jOh^ti=d8G+|Aqg^Vdr0>IL!*j0KGf^U5+I<8y6{3Tt|A#|E;PI6q_Bu$=eg^WRb7XO zL^R9+-w6j5%&lu9?Ab1tupJhrh@M7tm*=bBC>v`Gn?LP%jNKaYizG5@n2q$%9>b%q zH68Q2CIIACYsvfwG}z>rzLfjc(9NQ=BEWgCruJ(fk#^Zzr_1EIeRoF=+221Ot*!kS zsqCJle!!EgH4r<0CN%9H{AYUVR(rT*c^N7}D!M3yWRsfcc6>ktqBwxR-|TB=wCn#> zs%)12cR51yg7?_(`7)w@(L#1LAJ1qYD*KZbg^XRYJ^A^;ZbmdL!ncT~)U`gnrM2So&o6zl z2j^=Uz7~l{lZ=K!h}=6IGT&93J!}+~vhF`5l}Y{ER-PW{c8dY;P5$nnrLOtO$+ibv zz_<%c#Tz_lHNY8CZ(yIz;hkYxC64m6(Y*Ne^kL+=r;S;@`CAN&SHarYP4&&xt_X3n zm5|J8e;$NWI>f1xSW&+NT*-oM<6-bX(MGO+_>Jl8yQCay8yAt;wPn}Gnh(FVBI@_W zBkY^l%8hb@55oFO8c0i54)(do99H|{P6qFQp!e;TFdA21qIepw;>TJ?dNqZY(9d^k zJCqA)8`oWsChDUysd#hP&U&B}7ftpO;81&4&c&IT78>CZa?RFyPC%s)+G!v4gdv#s zT2Pj}PuL+}Oy%|h+HXqz5HPEpoSca0%;jA)`Wx&fl+YZ+AU7^$v6Wean6OuqLV}O_Lk9%FxuVkH{U8-29 zaQAra?!@{ETj>Q2&US$cRsP$(Srw6HGifrKoC*ZExjL3t6FX@%Ts2LFx}vRY-ke!b z4KedO#tsZWxY)R;a5zC>bsHOGJSM>;`TQ}KAgu~`f4+*UkkY$Odghvhjme=#ATd!_5IFA zQ@c$I2Sk1PVv~y_^$uiJ1{y>O?P7eGOCIJuckmm&GW8qHPI(b`d^k+)M{lNj+k{-+ zPI=3#r_kR2aDDp@)!|?8TpmWt_AUl9r1OCLo$iy|tzIgD&Vk-_AHx+mf&KfY&oBks z+8zwk*D60d2WAhNrP*G(-!+^7ljnGo*U(&qJn-14i*>ySV{xDtUzQlf;Czff25CeM zlcdRV?z|uukH%ILh!GE)InACMS#;HMY-3$9=k>g#j%3ou|8lAwR!d=d&2Xx5FCp9y zs~p)bmAIhe7FD*tq&+p|Gm4lasnWEao11fTOv#(b2nn$&%EbnCiHeg)r=_L7uOC!D z28O>(xVSip)6dM$Cx@x4pPH(+n14z8cudHWRIu--QBZr`yENnW>V%4hkAj-=8AZT4 z0yML_ymMNuU&q5A`1s5HmL9Sz=pGU!S7$-d}Z{fR;DR4MfV=P{i0@mcg8+ z9LQQsd~jz*)6ifT&AZNlhpjzpQ8awzq1Zhcu@5Kpp3?L-mMIhTxHcrXmog7Frhn8>%r2xH0(+j! zTdpe>5R6JmZftS-TPl`Oi??vI-29pcpJ*#$x>-QvEKEnOU@SjoarAB#ir7gB z0Uj;!OtC*~f?+wmEIT}WMoCMH3&JNR9#uiXjUMNZ{Q5PI)ynk2CryRC1EtCccIH0} zULw9aYQDS`nx@m*-*h;3GrqkCjJzNpQ~U2#bl`jpQj#Pie#EYL8;`qKe?)LB-v40T zdbE;x%7i&Y&w$PQSM7!zHs-0uw3s0=y+SOFq+SvWXJ68Ex+7D9wO(r1C7cmg(gw6y z)wJfm5eDhRY9$Qtaj$teIdwI(Q}f9%w!dIZO7Zb&&3PMGV3F}@b9_Aq=&;v+BnBn) z8w2xkyUKtN-yHX3t>4xxQvLn>S!Ze!Jg{~&?d$2~6~}i@(p8UYW>D`^ArA< zR|?pp2NdLW8Z$a7FtP=X*n=11?Dk}K^ii+gD%%o?9|z*;5OtX=g>$I(kBOVPx^hEK z_EcZnXHTK6y#D?0W@{@_f>CKYZij}*ZL60k`x(;82%bW&&Je`?_CcCL`B~wcA}ZkTU}E* z?lo$cjqCN;>ApWI2B>P zho4o~$5*0b;mh`28A3_>ofSE+Uw=mB=B?k4Yke@%8SG44J0T#*{}TWbrzeIzUlh+= z*J`D9mu-n`$E)Q7Kdb%IVO~-YfZWi7Gy?&#c_Ef`P71ylyHSkm+c)M#+Y1x``(@|` zKMxO&nVud|le8?C*!LURxZ%$Em%pV>F8Ash)nkj5E)1z5pR``dR*e@$@PmCwigL@6 ze*O>;r|)sg3y^>Z`2$N$Exc|XRi}+IZvx#{V{^!Aqo6P2{}&3OIsDNGU}?$`KrwlO zjktEMcX@1$_Ay#&YzU*Yf8csmp4C+nyjjEuL-2cIN*_9?Tub+L;jFnRq_(*|l`mU0 zG;ZmAw{$?LcN`PC^5w87%z4(vr%4|91d7yc9+(A()m)yP@FxKG_x_cq{aJ+-K(?7d z4Rc-%y^YtUz2r!El2+I!3Z)R<=ay|iui))W@Q=h}Ybvx&IO=0t>mKA@U8xLI8PZl9 zhi$Tj$x!lw7NZ~yxBd`Y*Dw=G`@yH zhQMn?#N$Ygm+8$vuTjo7F@F!?7xncYa6!ys%4ujqfUIlNexFSK9ZVzoPN*NLd$E!= zJ2B8eJbyC~H+&=G9D|e>)IQ6YQD1!qaDFvvhMMzf}!Xq z>5{|is%vEb4gO&?wb?+Jlob?(O9%xPQX`mEOk}cd$)nO*n3Im(9iK@gJP@xWk*24r zBwHB#`7QRCLp(&hQZ#Vnd#`cKhM;q1_`YzdZH^_TMzi5__SKFEwncbXC2(>R_p1P; zDEbi`RUCu)ZOY$6lSK5_uP4uLcBtXd?%h*T{6JhNC9) zGOCGFF+z#qQ9Q7U4qBSlwz z1MVp7h3iIBN@u~fQa=|Q_KEY*x%94L77%*5m4h`G9$+lJ7FGBQG(%ZLzsgwp2h%deqq~r!YwLLbb2!YOUT!ss{Bj`%;?5kwakM5k^h&^)xg%IO*010?Via8 zUb*`8&GLWp&;;M=Rp|bou=6|~T?AN6A)an{%I8|q{*!RV8+wQFUviMoZ@W^taisp$ zc7DVgaz`6rJ+zBiQaIz^(o!j|rXT-jk&Dwrpg_Ui&~uCE?)r^`X-S<=!rwR%uPf65 z)Ru6U0^`>-b=?(Z?_}^#+5j2vrdO^I3SIp&Y&S9bpJcK!$`f>FEc{a~a)HE891P!3 zI;RYf1~i_&PyP7isVaU@EROu(1YjQNmF$iWU{vv6g){3Ihb1%0Bq$d7CsKk=*_tp2 z-p-giTkwEWc~w*@q@|^;43_$%IwvOLn>U2Cral%rfZllK;o0U6!v;evHbuWWl7sCb z80>EJ0o&pM0V6Y>7!?W;lJX1IDSEqqF+f2?Eia9XE6oVltSI_%!1K#bw{%BnK!dG- z%Y-ZRhelbmyC=^@){_ktTdZI)iI4?~I3Nzh`>W4c(g@6~Dl)ix;Bi&aM) zRq7*ef|OiqTD0M;58IV``3CIl&WmAnhMQatW-Ij6I)2Cf#7s#uHOk@ro2@7zXwsL5 z_y(Sy0wO&Op`KAJwVjGh+h!&j#xsC=3Uq#1hWom;nZkU~zwb;76V$nK9Sl-^_Kes` zdhnQ~d;s2nwuHq~k>!qUo_`ARrN;>ti+iB!^6Dh>7e~Hqr1^M?AtNKBqht{%F4oP} z_2o)$Sd{R31IFYm;X#~P0YUl6b&hMQRV{z{=gv9@tv-sV-isxj?f{2Lpw$6?!W!Sv z^f5t@zsndCedKwT0bhWl6KRk{(P&l!))SRI7<%H5rodw&H)$GmQSp$2|zm;GBKPZm0{KC|x#Pgu>Ja6+ZYgQflmE9!-pF;Q316{252i|kK zSAsSE3-sA8}Gmu4qD6Ia;9G` zu40-^9Sp%MV#mp##0~ojkSj+l78Ad#oBM{@q zGsgx{f&~e(Bni5#5W`z6++1)4ao%_*`M8-RFLX?+%AOfs9#Unhj_Xc{6McmBF)l8q z5Z4m2uda0-vY1)+=xcs}_W88R19~1?VGKTy=;3N>)ZvHjkKy~Hu(M5x7)1D#BBgFi zH3D`v@?|g6th5<;hzELonnJ>)WxZsg6l1^9LdcnnP0I8jlR70k!LS*NrZPoqf>mKu z|0BSFsoRXRzrU&My9n*!-E8+nh&3@~#}0x#N8&39F7ZI(N?O-Ta?`3*^(o!cpkZ-P z`%LWcigtGTIP~>HjG-a58LcEWI!b)<*yF!A{Dh$MR6UltJAv$J;;Ji$e(};Mam-+fV~HD6 zs}l^t$GI!!zfb^?{xZbT)Y7=Sh-fDl5c!j0QHnUxa!NdFARN7e>vDqs3`b4ohJXIQHCkB#|k~&YH79B9)InwgI7_zzAF68Ah zwR*p9f!ZbA@Qitfv-sc|g0It0EM(clJx9u>WoO4y|IvfT>uP5#YBE>g-X1kmrIA=+ zF5|>0Jp3k|@%~Uq8ECLC;^L7DOmIydK8-Fa z92aOEAAm+_K7?a}Nc+xbqbMH-s3?Q<=s+eHzS~Qyia0nz{1V*EpdS9oHeiGw#Hg-{ zA#OtL=@-eT$sy8V_?+M-5zy9_zfQ`+aFG-o24GtZ2$=(g!pI)#busuY_k*vW)hnt- z`0RI>sva@b2Es}d3Ea0!{oFr1DxnJ!EL8vbh~-qD{9R11O|HwTg|aVOgP^=HuGV%2 zxjh6O%eT#q_#vaFUxI%U0>T~#y);Hv9UMVh`2q4DJ%=!Z3Uf|A5`LCdDJuwg7rZgb z!z}kC{Yc0XQw+i%F*UFZhR`hi)E`-%R%OzOJ9e)m^UzfEY-j5c%BmzG)<2St{A(co zps2B2NbAqik_1{+=kvE$p==I)<S?{pqqiN{*H~bMB6N$qE=5ftKjIP|o~BA8>e+ z5*%kxH(a@e=mW9rKlN=44v?|m>~`y<>kXoV$f%tB;rT_JbGZ-?lm)(H`lKcPJkP(9 zpB!Y@-@mtiq#5QfMjRdOd2*m(=`R-9UE+kJL?mw^8>L(F6%j7MR*j zJCcY&;cz(XRHqdWMF!Ob@m{f?GUE16(?@2d9^ypE{Mh7Vp3vh6x7zCSX%DpJnR$5B ztuO{ksDox_W>iU;{{56f7iFa-Ok&MR|jWf-^xP$UyRyjDqj6G=Z9ebRiOd*yK1yg=ZhJ->=OYi9HpAiV|x*K9eVy zpk*(q0C;(!RPddV&cwUP-5Z6YwX@Y#dv?0XbK@ z+j7=(M!NI5d|+dcp)Ydj5j3JyhsfqrLXGqX$KWey-!pCKF&?Js)U=+glydY)M;4?G z$3Vud;aQ!-=?Ml%`j?pobdHk~U1CsGf&G62ZJIwUER3w9@O1lSEA`}CL4qnihgqe4{Y9S?ub*qRGXl^`Z3hkRMLUfv^n01gYP1xy?Ac zy)4+EU?~@P#Q=K_V9QjiHW$M+DhQ~&Yi`#5Zpp?eKGXBP;2i4^T3*iD-mb$}i4K2; zxUaz%f!f!w;sYP^@aAnDyU^jfj~}V3s;VsJO6>v!-0s7`V8u^C+q&n-yOSwVXwZ2t z1C}a&dmJ@?7VaN*lGLI>F>5^OqAH>vs&wy@w2ai~s^cC!!t!Mgx$5S0Uj?FXvyGgbIB;UWR;W0jqmbF4QojFEZhrp8s}xqXm0FoqMLT1N*!d9=)NyWi z=fb_C<1bAkE%joSiRxUw*KlgpdIw@c4ta-(++;>Yb2v1-N>nLvIr`}-jOe8wm&_vD z79&w9cClO6l3@oq%W({F0;RG~ga|AA*LO5+n82TY+0dyD35S>Bv(nuOSvfm%zBMRG zK0gnVmX)p9ypRXQwnRZ5nVC_KXEG%8N8MCI?2DT^p24FQ4zWP`HZdujh-_s9Ip}nT zEBo_sSY8}I6pZV=^3jBc9dZ4VML397#ERYPcba$~cqu>cd1$CLAlmo5GsHHt54Mq! zTPlLmJ!KGQCwA;pPmrMSL>N@|;(KzTtDXDh{a#nxZSATPLK5GX1mo^KfXX`OKUbu9 zHV2yhHJ6Y8jS(Wq&Nibw{^HSYbUw9^IPoup>0Z#B)@V)+(ak6IPLVOP>TgVtb(Zcq zf0iBWh>z+<0*4n~j01X)$4*R4L}q>c8QEHm5+=MDgVjeQ_@tLPSFYb;fHX=pccEkA zU1_~%|42ZEnbFl3H3UPH#p9I49Xer|WnLi1!=tkzhwJ#bzl|OXkFAKlbp{aG^ui}R zo6P&*xlh~Y{bPMGlp`(4;K8!_>fQaPbT}8}2C&=NDd5i1RjCijtu7Vn<3YJ7J8m zHFs)8L5)Xq{RM0i?d)>987trX z6>lZR@_+tqh*{nm!t$j<9PM?aQzmaR|C!18r(D`x($nl;Lt-W=vEfRX8_)3>_dP<+ z+|Zy*k2ndY_U%*AZ+)~}9f`fB@tnno^G|D=^N=%a>=m5Jq3?LZ+Zjj0ucI!<*4@rd=mX9P5fY4lF7!M`!FYRVf!t~#=3)-5FSq@Z zjKQAkl8Wm%7G;W7t{4sntGj8VrP_U{!-El>5xRLaU2&HmVIzE_AATClXKXGAdGjd zdP;WDaV>%}P^Syd|>0W5< zCC(fBpoQ+4w?LrQFm7z~0P@f5j?DfzQ{$UESgXq-^0x;A7+X(i<{^^uEngIqOFi{xAjm;Q zZPybRQ-xG^F$S0qH&6dtHn+2G*T*2DTII!xuI}z8!=eOwy1J=_ zluhV1(^y?)96I5#RVATeICP^VnC>5Z$}h5X#a@f`ylS~p@rN}~cnNahtPa!otk>0l zjJuuhuYApoNHT9&j)5p)47}Z5G7pD02{))}>~CY-Xt^+HRUgNUuFY}gJBE*(NToSo z9TN=HeZLc9|A$PV)@>gX@U7~Lsm%#Uaq|A1S9rW+e$i3P%S>SMm)H&I z_}V`+mQyS7m)HuOs2hzLOyc z#14QSKTWcYmU+w0ipNtE+L>0S!HvbhT-Yy`0$?FIAh7nK$i_F<Kp1)ek>kD zx+kf}_45zU-r=I3*vU!zN2V&M$Jolxy{wmOPjmgH({1861O_@6dMT+*`Qo7b9ZgG5 z)NF9))@v1<+scpju`M<2nDpa-V@}U)S35Zs2eH+;tvlpP6SS4w6Kla~$2(-^OBPy0 zsse=U^LrO1;i<-)8#*r=^M`nkV<-Zy|Ey{~hEq+pKN*i}pmQMHHQu%WRo(zMC$a`|NuU`@ z=U-eYCSWO%7>-Ongfi8Nzr8$MiSklIH23tFk+EtsWKURzi~p$)57fIUi=PAPyufuQ zn5Zss^~U^G#ISN@dnw=hGRNtm`pI!9WlUT^hvM*rA_MhfLb!!BBC$2kN8k=_(Y6h+ zpB`<$dhdnhEZ_7A9|y4AC;7k+uxE5a3VicqaauI`JcnW=JwbZFPexmGtP>y{w?DH! z@86bU4748X-=0&OJfC(yfq-)R9V;a*Qpl0O(nJ!aVHic-`SkawD?lcJNB485t;|CC z=+X~)k?(;&j;h3m;m;~u!l;d8ZGQK6!+w-?30*H(zhMov2fX0s#m!pf{IaDl8MA9n zjx_nKFt)zyuRDrUTML%E3GPT2L@&pt@H@j180XGCz+bWU;YNG?*@_L>~;1g{VbAYO=)=jk4%1m)5? z)WW^DGJ0x$)dR*g?x0%aiNMy}Jubq^Z8YDGCB0930Q8bL+~Gzz^l_qW!QAAEzITLC0s`DW%G``?Qqb)ODXVIT+PnV%{sn;+ zC&HbF3f8pdJ^vkf`u`&`-rNKj@t{PkRJ!F=ERIV4wA-nWKH-mfTV!KfG*rEJC+AR zBc8MRdH36lpo=`i>8?F~P!;GUxaplW1~MF!#tbxLA|8Tlzn?+PVw?Bi&05o+=snI! zidH5p&>b7HF}a+RrI?o?^0!|)OTpU4ILxYO87tj8up-7RT;7ii<~2p_#(5$iL5|Q3 z2SpHwsyxa=z9!=fa66Uq@U&rccNa_byjd)olM+>H8;oGXL5!lwh2&yHLHaNtsae7d z=K7*y;!Klb8@-*It>R4-#~Lcg%x!9yS%m~7NrXhO8erB1Ap)6EeL4sU^vpz<$VIe_ zZDtir5N{J~sm|Rx7;hqb3)bj-iownkg1HW-YXH7oMtS&o`>ps&{*XeQuagP`$AQMs zZl7_@y4~WW!k|MNLouxrDA3HyMJ1oUM9@>7@+6^CBz0}KFJKbdbN zht||*Vc12lGyy_>V&KJQLHa1bwZJ@}KgcGJ7NR1LWC4jg!QWcaPq$PABD|P^3P1;} z`5i#FP{z7Aphlm&gs-=39w47&GM$S|U59Z((@%gaA@e7w&EmR4fq3UP4}!3Sf#(s85&bO4_QdWGWxcN1-GRmK(+zIP(Cxsh ze!DE^KvM`4zheRM)P@ekZJlhaO8`ou`8)T`5;O^{_brSj3wV7R_i|_JCEnK+_vJ(X z_~ThOMe;B9OLNkkFoBrzZs0Cd00h3f$H=uTA5$4nPR*&)Q{ydLobOX|?#xEm;vssm z5n(K+8O5F2eOp{A(-=T?EHH?Hvc0%YjRJ3J%dJh|!{}H}ZO{ZTMfVORNdMyb0pR`I zhn&>I%Mc(<3u-~OA{2vB*S?>Wl#8BMzl(@^)RT=kBZbLhBJJ@IQqxOZtf#Ml6f9&k zCbEPS7FB|tYn{vC$A!b8ZFnFh#@fWad5zX}mk@N>;IA7x5$vG9z6?k8zV?3yKX(00 zBnJ{FP7n!^_I9p0?aaX43sHD}i(_@KcxDM~ZUYv13srlAF^YF7+c4xFL3<}tfW*vQdkVWo6RJ2ad@hNmN7|l+Neu%c*+<4 z#b3$q1G86(gLNLGjQU`w;HQ?6?Bs%XO>zdm&*x@8ma%Gdfc>e=T|AZ1bZ#E^dhbnY zOknWphYC${o3j4d^rT{x<}UnbDW!fX1KsE;i(`R5I4E2(IQsdMNvPoWx{7Tcqgyw< zWKYeAZqU(b|1D+xC0xux_V6)vWB;Q^6D!n)LCbUGzU4dg2FDRlzG3@_=9( zbo{%Iq!cI?NKC{=K%vTy>Z5K}hHq7NzC&YEIX5em*U+BE^L3hVjRU%t$MQ9e9iQ_35)nV%lIozR;0 z=|98*6gj%&>CQ@yPMb?~H@a0`-7E-Kc z=Tpov7TPbM1^70Qshs*40E51^iNHu-zrB?0>guWuXsQRh!9l7Y#-?h)rmCHffGLT+ zEv7EPwbmc6?3GXlAE(Kcq1Q1krbLDhD45@Oaeg^_WvPFA1bCd=L@L%k|o~*0ey0(PRg1EEEDQDF-d7H59h%y4Gpv zwjuhA?3lP?#Q#+>8Hh{EuCAdG_Nr|=n?8gkaO_4#V0(Jnw5Y2M&B75nKkzvD$Uz}5 z?QRM!H2fh#O7ir^z-@yS%DP;HwmnN+NcHYOXY0bb?;RawXCfaOe}27J&wnagMLbE7 z*DUNnZVsWDT<|E7;8L1gk1nd7>`Vz1Tx0SZC`%2=31IpB({&A^{r87i3BGr3SmW(P zn@O9PMVSQZ!<)C^1}^&|$Pt8UVMB(JfE2b*0iQTg<5;%QvtAEbi}BCXc(EDg9$!IEfPLMTICMXS&R%zv58-}%>hqlDZ&5yPZ0#Mgg< zDlaenapk0CezuP-q(KE$+SLP}q~9{uhpen;h(J4mpeYgMqu}2A*o$E>G()Vq z6Yjn5dyqtwO8;>FZ*%YOK@yfeS5!=E43ZsG|L)7+5Tm2FBzca_$<#rXUEhbbQOL=F z+Hn<^*{9@k6)tfnCY;KKl%XTCwt+#*auLYPrm@{&dJ(~BJnhlAK|Zc%%S z04FGL19jZ_$2ndq%Ozg*83V||MmS{@&`2NOA(<4P@8O#_?lYl>)=SahpYrscPE2U; z&&|E8Rp5Vy(n~1{XEtIhcrn<}OfRFMK*FqsHosXMqihUj>%_v{-R7+34>$&Tkp4Ov zMUu~^plRwv9|IWOaKrJq zLG!)+IDu+sh$Dz%IfdrOHebR|;F!&dhIZ)m)BR_|HvmRQnOCL%^((i*vd5@HamiWx zQ0xupk+voV=v{?fibow*^YzuM@y3cjq}GYonM`sDV9Ox65L>nrN@i{ibIn( zLyREhpY2pi4*|mR)}=%$*%vXvxK!P)LrNo`Sxl4Hn-G%g2QP4*MC~Wc;BBxTAY4uN zhTvAwN*l7b5BTwZe5`Q{LTE}Ae$Fz4bzQ1?`YpSZ;XO!V{kjQLzQQxSJmfEARtdwU zdfL8L?(`Kc(U=tG6__1T4yBF^V4k>nrxH-@p*^$(1GwD9UwsmVQJ@Dq{0Nokznp0@ z)QU7lb3E`zb4)i57~RLA_d>`! zQSl%lZFzG8#>94G<+1;ECSf5ETycxV7a2;e|6<@ddW)+Br~^H=#8rwLt6hje6@XXw z9}3G`#LWX*f?b=woLf}VsLWdF)~g$>?D44O_P0CkTdrZOi!rD(LXLKqNOOX8OBqe z+j`>4>F%uGfl#WHYiyoHvbXCy4&=oM3IL=94tSbNw#r7^ zyvo1k|9l9ARrRG=4#HpKgccO?D%N52OokM;L}0)h3^vvpK{%cLwZ<5j$3ZbyJyx8c z)9jPIzYUVD0(4*EIN8h}4=FfYB--$|+e;oT2I6q1ibDQq`?TQOBQwEttsNjFWQ=UQM1i(q@ah&ujIg^GXtHwV3ysFUW?y^)Ml;B*s3 z07{MNg5M@jbNFMPc3(9-H|`stLnM)uXwaf2PtnrXaT)whE<{%Cp3W47=wgBz=de1~Ii1Go%k~tjgYMggaKWPl`RfkA_`#gR{3s!Mb!~Coil*B6pY$pko81tg7g@GC-=$bB=eVO?3wC*F$y`10~hJ zTFilmPpKx>k9&iR?|!6`yn`1MC`9?n!o@T{DBNq~A>_5JZ!%UWjKn^T0FpAO^Ip!= zlQgT4TQ*YI(|-NI5C;+)SSw46y*K2f@w7H$W8%>Vh3Fv+ARI3(b%_nBlg5Jl{1Y)n z7rl+8I#SE)oDH=8CBB--^S_(R>|V%kM&nO(2Qa;CtB{_r=&~>5^=YF2Fkt%3<6gUV z$DxTf4y8K!er}2Rl<(>XvIv!FbqQfXUZN#NmGyU&AY?f$%ItSyRle&SxF5aLf%2;tH!}f*q)b}rw!**d%->}s(2QWtKlrbz{+dgI#>{|=}RRI_d zJG)TOGNFOMlIPM7s%u(*)K~{N^l%`ymJ}2Nd?*=9tjU>JexE3_8^|UuEF$@WcfSq2 zU~$+u?hZap${F}~DL7XEd`9vGY`2Po2B%RS#H(2+F)=tl`dL7+QBlX^D$1zg zp%G522kGvkrKF5aVJ%LHIw?wMZ}kE#`b|8?u*Sx9*>5ac0_1@@-<1K3wJm`To5NRR zcD5!Lfu%-V7(wu#3@ZGE&q|-cB>fGSdO{u`vSipMwiRNYb_OpqsBnM2oE|-{P7D4s zzv4e4_8u-LYJeS6BNgN7sI8gaD(r^ldCnB$J3SFd!Fjr#N(K@efazCQ)MUiK$2|Bs z97gj`D@q%IM?mE|!gI687%j+7Y%3eQ=WLGValVwjDwB!{Xn{8{^$dI|pX)fLU_zD` zXK#*Y45At`Hi7%;WU=Ey^nE)fQoUE(k{J&oWQ)m<2Hwp2;>E4t`o#|G?>Bt?0kTJNd&_UD~EP|Gb% z=yFzKgv?TLx!(CZ8b3659m{FO&y>F}c0M%90pCmR$bR0{4oIQN9hT7OM7f^z)>`e# z_JaJ{?!HDyp1h9`7488!ZmO%UO~ z{18o6v2^-fTB$&KdPuK#3Wbg*MapJ3zTf_&w{`o|MqlJ8`ySbDJE zm`@nE#*0zf2J^*a25zSQi;>T-4t*b)k^3#UE|Q!eztKbj zmjIh%X+>1b@#`4@j2hU)No395GuOzwa(Uka2u4#3e#(GZ>!VDv^`@I~C9e@Ey#f#W z3jnc-g1=Xg?C%dpd*Q+}7*lj!z>5lx5i!CtO7d|PZQnK?6OWki0zGesY$ zp&xe#z;+TMDCYw4D8R*L;WBjwc>UuORoxPePx0<8}`YKvo9L6g?)T z#s4+z0WvOl_sIbljL_SAKDok1-Emt3>vQ&}Hw6(A08Ht{fQeO)2@`nhS-?%o{)HA; zgeenbZ3enKUlaC>b#C9g)(CD?GI#XG(fLPm_C%Mv{*lWcB0u91XnJp&V)?_Mr)%s> z-6?NisAJM`cyIENeZl6mHfciq@w;~k+V;q#h=+zH#jlLsgl_^L$}ZJaRTWi~;@zsr z$AJ2V`xJg43;h-EeUE#pIEtg`^zvd62y(sqdrI?s@!@z~eXy-;9n@Z1c!U-XZM_F#|`zHsyqGJ_3)+)cm&| zN#%iMDCq)Jwj$h@brcm~Ll)c?qw(CWIsF zMx-X0akD5#DOi^y{XAyO&~;qkmw4ly>!L4SslzM)9WH%mDTx@+wT622hh}Fs|H-f{ zMuCk-V#b1vo5m2_19RXFIG)D=3ZDJeevZhF(f=B`iK*=Wis^C$KFGQ7jW_rpzWoaS zOc(k19w^GKg@cebn1V}o!cl92rzC&lODIH_zlFRRPo@z?D#s`J&p{DPw`$RUw)+z8 zRd|{S`e<@G;B#u#9qFN`M?I`$WMZH7EI?dL44D57ziJU%LM*}wf72efnVHq!-zHCJ zSlpjJG92zQsom19fuc?m(*ZOHZwDkm5W<|1@wRg!M!&-e+Eze7K|qkw)chBx>6mr6 z&f>y)J`e}47e}X!vemc5D49ij^+Fsy}=DN?g(p?BEk5RTMV0B3@8A z5HtT91^q!F#j&n#ZFx;_9K#LgkO5$NR94Atf_&70xGpVskHMxZNf9IW?q&{PBgUZn zH0(ytaQU8r5INld-rE2;jbOJ@^XYKe0NOyWXlL)@p`UZ>DNYB_fPeO38bIv2xg903 z0dg(g^VE&>n5qG?HzR5mqZ(_A!y?{(&adB+;;__=G?GFM&>jGRlT}Z{PQBg!`19g4 z{eZeRUV^*CSkL=KLVkV`xE#(B|K|orocutw-$=`#q>#o+#aoQa-Fr8x6KC zInso8SNH$U!ni{t!KR_fu2eS#VAECc#}^bOWldq~a+RP0k{5+S+THp>f^|C?hD4;gH^BW_jRRnS zN>1lj_*;P~r9sI5r=dL?vLiw-Ar+I)sOIy{TNj2}+hjQR5QxR3hbT1`bTrqW?Xut9 z1?b(Gbf5)hse9c$I<8o>?!1AMNk$kOTvm}Aq5)I0KZ``fR_|GS9f4*2a8$E_ayFk^ zXEylkhuq<)M-9o6M*D$MV!n<>Nr}+FBp1J%4uL2i80&#Iwx3k)TD-?`@znd+b&TNK zZ(CnqH@f5ZG^@dfZ*DuTOwL(v@Q*%(u2z_s!E-U(fRho#sjyTDa|er*vwPMjsBFN> zR-Doa+C{et)?CMPDd$rzEYvybV|o$y;Qcf3Pyh>+mwjIfErW`p4ncxW5L6mzeA>9N zy`FpnEwf!9lH73#fb~JE`ixMaz1Q$0Fu*IU0wt##b;Dw?bxN zE|A-`dHdjSI?+u0;5?6JCU4rx3eH+SA026O{af$at`kiUnM$oZaT{&qz;|GmjsEwbQtt0oi1CU%)EH zv8nufsLJ8S;gp1h^^t_?A!?1+Aog-2fwA^? znlGe^cP48kq}n?>yZ^bvI#{vcemTzhaac;qOEoORah_oaX7Jw^6wc1W>K4P^kjd%k z0UN=@s>qt5Sm|!GMA23LAbe87!`{EUyP(qu2nG*2R|8G3Y1o&N`GKvfbH1OpF-&)F z`)mi9*C2Zg$5Me{kyV9gXTO_mS!~=e#qEwK@Fyl}u>b4)paz5W+BmcS&RrR`d6rF6 z9vdJ|HS1jS2g;uxV3+PVh_p51njc95FQ=V$yy-u(z~lek=W@UU2ZI-o)ZNN2sHU(C zhiP3TL$`i00g&?dwI6nc1JaJWc}ncN2*yeP^yA$$0_DiR$Ly6@B7#MCw4K#Lbjew@ zJt=LJOOqLCXsbWL>%1Vs1@HN0G1h|$dUh#!c}4ZlZl^2vkMO{h^a8aw>L zS9;C96Q$!~+#A{GblyxwZsKO-gR^E2yZ1N~u=ImZowmgtvh>T0X<#=h2>)G-~OF4N3(Fdk?=x#7ya*7Db@w; zpEqdnUzGmq$0#in0)cDFE>#M>oLC!6$L%Dn0oIi|QC+?piO!vzXx`hO6trRN!-3?w z3TvBwIguhvvhI879I{K^5GUhC%R5pCvge3N&c-K|XT;G)&B#KaHwkS}54<9eg>2@K zHN*%+dKzp|J?>=sAka$#2`OI`=+JS3J%zrB7~Rh{6X^9s$1!TO3`j!1u?34u1OmNa z`6JE1j$amEu1Px2_Zvn{Dk1+|yI*N_T{${5HW#0?eR&zV^k;0l<(OE2M~wLWRH9rH z%89@Tr^)hqgcp8zTxp47^jK(cqyyjShE#RoS+i-6iEdms7dN_5PvmBE>#dY3x^DzO zqezqxXga+VhWA{bQR@_2@Lb^O|May;yxNG#96~Gu>0ZuO4Rk>7br_2E|4sVHUEjVC45}a*3X|0Ql09;=xzD_q zmfe3c!QC6Piu|E;oTLU$4Hx8#qU5h~VnBR=U;7L2U;ti3Ed4*-f53T_XoK?VXR_gi z&$%HYa5eKb7b$?^I%pYs#s2_T@w^#(*nW8%qdr!Nwv9P(0X}AbCs$Xu2QB z^Gg3;tSSgvbsyufMyocw3CN43B|dy<8k+b2#jB2P@GxVFc7DQo<&yJL*e}>_UwZLbS?wJ(Qs|ZUbu?CSbG#7n{1*fUcDeH|iHnU8jhI4bBzr4>s7enNq+G%n1S_4puF>9)gK060s9?g7;KW z-wxXVAoZLqDUtiD6T->4eAOaGi!ED+|+&P;1L6CN8d6^(nErux~@&jPw zte~z=RHx4{o-Kj*&V0Ik6K*^2}YPDY=b$hY8o~0Kn;1m zeXp*h6ra(YkvB*y!v#s6g*V!!*?s5wHC?v>UBrn&6AiJ>`61Og%*5}%vQ<#xg1jl> zD2RhEWk^E;@3}4Mhf>N0Homm41FAlU;U5`EWfYyA`AbSmSwZq*KR7t}-rjC>aSmK8 zSP#`sNOIG8=ls17s=1vpRFy$z0g=TakPx#l&phFvq+<}9T6b@sr;Es}F;yNy;_JW^ zzDIYajta8HD0McCx+>DVBsJ%Z>iP2QQLL{&tvq;fet)_%)z;#B5es0smQ1Q!dE|wM zT&T5vBO`+z5g8emlCte0x0I>=wF!4P%e%Ag3E{6QYK=$kt5oz4J0!_e9CM2UJbB)H zy!&Ku&C0`rKM>8pxwf{JLxcV1&6^xs+VD5wPt$D!%@lYa;bSCBg=8Hv)_K>ho7`Vf zaj2vQe&4W2%zE5cZ9c#QT<-7hH|wSxx~$5{axIw+H&zu~W6mc#-AOV9=;t;vld$%s z5b2T(7d^d1-*{L1t%WL@T`hv^F}$0r{x0zH$9)@!)~GqCcevl$!v9I|s>qVFXm5mP z`u@h~o5kXirgBj{`k^AM;04j*@839`Ijv<3RxMQW?}%paChU*#0Q}B9T@yBb@s77Y z*NwQA?B^=50yBx};b2&H%XetOWyjA&ldrcKFI;gS5GI;k4<~g-@_+gV307UDEmt;d zsak%DPY`MqE8xTyWn^UPL5u9dBybF2dL~W8Yx5h^EbrCjd8gFtn2ox)Vo?)3ndf{a z@O9EeFz*jJ1qF#8;5IhWNc&NiFW?A%y!WI1H%vL_ku#PARQx75cyeYrocZ?`i&NY= z{_f8os6j+mx5_kxg&7}>1)my5k~`#g@W*S z;&AcT$Pd;>vJ-Rj!y;0SEENsV(^D11w=I9{H0XWib^kfwO;ahP`Teg2QlpX?Wjp44?B3F%;OpCRM%y5AJNqA7|B9k{ zPM^$teEMa`lVWk5S3)9FaSEq%z+x}BL?JRF;vsc25%PVl6&gg?X({C5!i$uVk#9)Y z2c&IWeqeb*;&REzbdxTyK1!Ko4a4%DyZ#pbaht(ybC{ysxLuzDDvk4sPe^dJGYBJ9 z3Xm*R&yG&w){VCfBg(I+AWW>>rte{N((i!m*nXOvG)?sj{4)5|!+Up)iW-uJc7u)~ zosKKhBQqs;85nrZsOzfS`87QO_i+IA>H{2AA7FX!8RYodk-&5JCwtVB0BVTK^T6M_ zXBHMgZzN3F#>a~e|F+xLQT9J&xCxC3IkdhQHPfY;xHk zw0T;mP_!Om5D~44gX6u<-d0yf4!ZM_=bqAj)w!gBnBsgdmLUm%aImwVUr(+Vp=d!E zAAruiGSGZ2L!$cx+$imN*a`-!hJV(OM1d~3x5LHl=F)rk-_IXF6P#gD-$%>kLJt+% z1S!6ECw4vb)}Y}_;K46a)88UOlU6i+I*F&zCG}wUO2kaIXL5dlr6r`XvC$j^d|7nw z;Sp}7N`p4gzV2oUh3$;Q?GIqGBNd5dAcyPWV#7TKgqVsVSb0qMcq0MtWY)kryq{El z645^0#S>i^Ng8n9af29%wu<|2c3N9oNyx~8sf>Msib(^6{(tzw-D%fpRgtx)oNzPf z+NQGgwU|E00Nv$6L5KU&E;+bb>LT%GH^)8f*b@DW)U7SR)Utz&Nzu?=^Z1_{?4>5r zZ?RwS%WNAHr5>(tS-icD$O4ZI?QU@U$A&hN5ejJcTqDrx{2Gnx2;(1Lbd$XCNFY^3m5rsJnc(yV~c4>k=H z8CIRd*!U~}GybALz?_ly`*v*e)3F$0?DF6*eq3M_9xUTadXv6$AjRQ&)00KKW;&Pp zzZMCN%uIh2F*k~D1JVmitn2g|#BBUT zaPIiqQK#OPiE%%>i?N>U;v&PF8B4ANzVD4_EG7Ws!`__}Jf~zffh$J~_q&oBYf=iu zvqaUoA65-U`bI-$sGjnO{W=`0PE{te-pEv+J)W_+>6?Zic^w0WwNxD-D?or1* zZ08?1$saTtaPd4uTZ_Yq376CR<&xTC_JQ#0=Wo5t7J6(lkMfDBDTBT=`Ct-8UfuuA z{0JpKUq-^=3(q-OUUmBiOOr?wS8IQllLK;NcqhZm>}LipH0|y8jp`fp>wnwXJ4)#L zix=0=4m`Zre#FfBV-=0{3v0@fH=$dc!$lVA?k+WR%&IosA-+9+^!i+XUertSG&6G) zw*5RCr4~8S(0tRt5xTjkJ8jlB$}7ELx;UDpd8rF zkUfs2u$<`7ym!SwgyU)G-eQ+^Jd9aZni{xVso%eNa}Yper}3!Rw%9J#^yx1QB@J0^ zAwg|C%N`*knC!yI!D2(bp8VOj?5t;;B{at#gCcc*$1I-vh7Z+EUKdR%s|zPIw;Wx( zW;P=IJ$r`tL#J8n^D@Fx2}U5W9H0moFJF%^Igxo$ENOC%$o~*o`Kq{$|J@zCyA=(x zn~@tMg66&R3x8of?*O@?W=@U|y z-;Qgx7|KdqT7OMP3SMjXm636H3mFPN9&_RBUiOBMRT#CJ!45$*Vd8+g$2HL5IPG5q z7K7-jw)J_Yswg4zZ?7b_Yq{hU9EBOjYnSu`k$)n@_bKGKO5n!_E?}@nxYnRIn{)>i zlu@gLYV4?MdPn}WS@V|hJ3JWQXX?gDEBnFBk+M&-W1+>9Co%76lWqyg;&utwl~=~C zehMQd<-?9drrYhpu?~JI1DX-oZw3D{cOmTl+Suq-y>LW^CdYd3GPy`}#GZ)0ME=?8 zLL@503@l4)tIFBrl4ng8EW|pN*cPY#s$ETs!1sJMZ|vCkiw%d@7CVa%CH!=+z49xy zH!pAPnz}+1Jfn~gr&by!T^a23u>FWmi1)4JJC@vU$?xX1+XAd56szY3=MydhSh)IOsVY7m;kkIF_*0xDP4c^`vKwB{S z%(doZ6m5`ThTiEcAGa@I{QOIw=bYiAckJ*|b#*yC1~n~~s+XCVf?Qm~JQx&`oDxUcMg7afU01!79GOzp||`C*v6J_a10bcNip;wPKdrmC(luNF5?wf z$V*;ij<34ktrOjeWTS>se?H96MjOsH7|l7|USFvBB%OD_H}xwgg80*x0mu2@`mA%p znIQYzsHVc8U-}Ms1bh%^|;HRT1rQ zvs^->r(Y$3s@!dB7)$Lz*spUW0ui=|*(oxSKCkrRyW>k%7uu$D$gRA6&@3yrvFWlr znhV?0ApaoTB`J67w^um8-AOSdF+pno+S3B@i+S^nt*r)tdfTh@eWR06sq8*m)h!y#^EgK_ z)JFmIh8{G+vo2_l*U~Z&&v*4&ZUXJks-=aEX>5XhiTKJ+OrptnR=f5et(VgrrmD9srHYD z-q6T|^b8x;N5YJcYCI(DN+&kn&f)B9Nv*R_t2|uvTDXazzs+8VXFrC&kqx-JXlk*~ zbW_v>Q}&AF**v*>l)XA%%Q#cOoaNvT{H!mmNWGHR*wfl8Q>F>nw>}77LL1yg)hpArl}ox|Ga9#?8|wjC;PBJ5kr;;i8mQ%QpLq z{PwYjTxNJi> zb#zAMpU$GhXr(Ix=JqsoXH0fl@y1 zWz?QWo=1sikGZ5y3l(7LiskaUk61Sl0ym&|ZO6aF<2!k9(aUgh)&{3>=@ zxCzKM{zUqBi45)eWB6RndvS)7U&`xPV}CL$iauCHLg6eSOO;&DHlNQ}1VgQBZe#Br z5CpAAA+@(vVj1P!WN>ia_yh@gV0bBZPpK(vZRNgja6w44^I)kSN%XZo+X@a4i-6Ph z9;!IT2w*R;!68pb{i12IqUcg61>Q{qLiYG6nTW~b!LMed!u)yT^hOP1^41;o%rCSn5OPB(;j($36FC$C#a zj=)4H$zy~aDsOwXFAeWdG!;aT2W#`Teji5$*wkOU(3b>V^a9B#J%qFv0cE(bS@$=x58KbUt|>GeUmMBAyqq ztg|KZKcfiT#?qjK^=bl&2B);-4J7BloHdN8^Q@2fvwSPJ8Oa zm5b^c1a-724{KCmXy|stx$}cVW83{q#uI_C&zM3mHvUsS(v)A*|vviv4MlV#qGn2@tOEx1aIM5lG- zJZCHy&Xf}M;NXB_ZR_20)!){a3?@lE7wsWH zAXx$64C#xDaWf-|Ffl#H>t%{z^KUI(>9w|oA@nz?3GAO7gh@FJ~jdOl}x_m7FpW=Dn@oq_qOcYcnu7iur z2<%L2g_WBEyETlODEHX=20u}4Y`-Pm6KMnT%k}G(h{ecNrR;t2c2|%m^2xkLR-*~z zHJUIqa&6XvN#{hWcy3DmEya&ms;a8w8&u!LpneW&+Q1qw?0$FJK=HEwE8Y7Bo@O{8 zUIV=@${1_)ifXdln16478hTql6vXM=X1_$0uJ+T0iU${aJbTL{A60 zZ^`UarGy<8B{N^~qfGg)ZJ_I5?}<9sL-b>jS(3AB*Y{dl9YiEH-E+S}8cRsB2ZE~> zT$`8lenI$RsI+H@XD?b6o!@nSRT#O(uIxIoa!)q+eTvpj*|rl(yT^2-V7u`5*arhX zH~aJ$dD0Y9Ard~3>`agt9CMGSU=joj;-Ww7!WI#(l<8#Xy({|lYqm^U`zZJ+wCOpf zA>R4s4`rXHT2zu&XEvqw`WK;Ox32}XXEeyECF}%WdN+u_iBxD9y!@qs3ZFVy71W;# zru+T}d$c_M$T;J_rT68=%lKdzZj{&G)h2i3K8r?ScmLSx}d+yRH2+fQ?Uml~!~IU;ngXB)1|t5bZp{u)Vjv=~573@B(SF z8)U{EBwyS(9|JFJc@WjOi2Md9oIQ9VMkn%aKq{9DC-PH%4u8a4Bs)J*iI3|A?`wT} zJ@-=_uCMc_h!ZzbKX3^bX40<;&1uA2CZ9{W{w#QqjOTy9ONHt+uwn6_sZaeY}-SQz@}&lU`Rjvr_WzqA}`EiDLC+I=u5`x(08&!S(%q@8UyHSCK@jt?A&oY>C4vS8p;&$1ZB zAgVqn%y#)5@9HUq3=i&E)TnA&r?Q$DOdHRU?CT>Fcr z1GDNM23 z1a|rk=Z=MhO!1U%oJ8s)uvlAMoMJ-kI%Alm)a2x_;?NKLP6TH!TZ7Rsu&ZEjh7Tz0 zR3ZChb=HTHPvUeskyy4^Guw}L zG*7N?zi5qI0_~oz3x+2-5g!9)b?_jy*<)ev5Jc-Veeu6_M zLQ*FOO~TcE_Q0{0omP@O7A?gKD-!y5>gL`8OkwF30PAI=L!vW8n+sE$q61SEOHOm% zZ38Fxun7;6y_hsU6W*s~YUgob@F$Vf`XT^@`;(vnP-@PtXdtZH)cxPcfq-I-D+%H% z8CX)wGvOta&YrqrbV>aS1+i*7of|JYXB~!~yoZFMKW;9M<4im_j0V%ei4I7)TF4l#PP?!nAUc2F_n}i!yg_vd-v=D^;0Hv}kKvF9h5VbNUBMp@ z7Oma4zFE7OuD+FbG^Eaww4dcUIcz;rdPJ6`Qh`MRV@?iwu+i`(`?avKYbgCbJi0yR zAz{$gq(+)Ualo6LDVe(wSmIHj`9Kt~SyGf0&tAa3=6kHi&Lw{tOetr}zUpN#^75CE z>e2JscGAQ_DPiUt1zjB-j_0U+5#B^Bk9bDNauYVAmn|j{fy+-W&57EU(;Zi`(&XTV=tM*K`8en2_5boBsQLfT-=D z8t#hhH>kQh@qQdhmxLwqB|s3p5gu?o$GY_ZjG6M0JG(wqENlRTT~!?&5AggW-LuPQ zmXy_-kaLg+6*>K)eJJ{uYlY*RmamzTSj%3y>WkW)SFhMH02jLny$adRsz^2-M97PG z10DYAhR?#8ZY}piPS#)4+@~G_Qn_L{G}|1?awHCLSY$rX9Prj}B!+u6^cCIF*OMNA zk{Cu6M?pd101hwT)v4VI>`>;)yFQEfcr~%k0_nj%ACY^`H?r$qrfjFvkh4-@=}>v(v0v5RT8E&g5hTCdZC@%aQ20&jae_JyY#qhD|aK{U$8qsZ4h9 z1aQ4TR<`I9G3x;5yHb|Ms>fv695mVox%vr9lS~}jHd-lung=NI%@+%Bjh?0qL&rb1 zWMK}Aumhhw*P1nC<54&_=SeKZ}n1mwY!Y{1#C0T0We!_K9zEXoa71_eZEsn`fyers_>}WNcFY3IH zoIoM{nwdBU2FohlBLlq^=q#AQ%F4(SM{mT*1E%kmw@$4G!XFRL=MZP_)Eh~igY{~b zGqJ?efd-(#<(Dxs(q!|C$z4e$fx@evZEYGaUlaL5XN!D;eE1{`L`~%Rnx4fz1Ljdf zTZtZ;^9;K`r}0&G)g&*J0Yq4+5U`kVy+@SNx*tr==k6KlXlQ7-wB_R0d-Y+T@O`HR z*~0kB6Zp5AmD=3f*xNsjli%nb*TywmG&{rr&VisCC^E7`Sluq|Uj|Ap%1>R)eRBRb zEi9@bs%dX~UVtfnz*J74v0-cS-V*TbQ&sV$H9-yQZtx#9E5MN5cx%BfXH{?hBqk-j z$;W45SYin=w5T7(`!Q>b@;|@0NbluX2ErCTP1(QklSoY1{Jii)pj zyOE@y-?ggBZ`N7W#PCt;pDzLApjlj=vm`!WV4flEh=kyi9f{^lk03c0_k@1I?Cb{* zUNl+B@abqDFCGx2dYh-E{_o2pmY-Pa2i8X*+9>+30kbv5#-KZ%`$kSkX^`$7a3;hyR546|6aiV`vv}Z8}z=`((EU}H~$lH+^Q|! zTIKSr?u^{4ci6fN2jHKzfuoV|>#eRXRfW;fVq;}<%r^`AQw|lf1gBv~krfEDD(=zU zD3`Rawu`<8$$=v&=x=e3*Kf&(#vqUG7fMTLBW8m3+%eE|UzfKK^}GL zngmXE={?+ly{@ql&L-rcjtcPF52-m(RFzeFRmZ1`^Hu(zzTh(EZa^fNK#vPp_0rWi zAWH_B6}4H(iIca4VriKHOP`D?oUAp1k7K#Yt$i0`l%rq&8v;SgQhE)s*xl(ux4UMO zKXC($M?#xic$7E#doXaaj#dsiWssPZ|z`IYg=npkn?@ z5Y)^{Lrgnkw1ni1ua{;k6q{blp4y+iq}|MWY7C6Z95nx}IsMpkNj|oaN%afK?31F&16`FPbE3mBKeIBsdEf z+eNR2n=FH`rr`G5_-m`Q9hIG{Ibn9558uW^yme97)B)$y2AnD{K0hmp;oLa^A(E== z3Sa4?SuslsS;(XT8F!P z4`O)=NT|vTYe*pA{IH-F_I&k(tyMx)=;+I{)@sg0({)jjHC&LDoNU$ zrH^SQv#zefx_o;-#7%wuGY%Z#lWW-4)L}IP}s4#v_vMdymXQ`4mVBJk2HhPLZfM; z`kWLn#T5=f{>y6gs~=P@H>HrL!Z62FG29Rg3J+sE11;F*sVzCHaTn8hyi z%>@M}yPqSM`kV6e$ZumX?#da|7Fpv?4&ti*k&7biYOl;}JVVq~StIJBSPeP{!#eOD z>wQT*qe*G!W&O$thGQPtks8IuXt@_3((hY?sd0=N0;WPwZF0lC+BJot1ksb{uj^~%fry%UTQ za=3(l1*%sDy~Ru`-Mi$#89`QLVE+F6=tgpJSaTym2ytj|WcTba2rfCe+_=(*(cw>w zviPc!6cR%(`qsGVcu%%0MN+Dp_)t-1+CqU%`~#ZQM+BSu)@U66ou~Hbt}X!eju!uj zu*i#izRT>r3s^bKPz&w5u9q74y=~zG<5Tj{Jbcycy=`@IxTK=l^$J4B*=*&$+ZevVPB7KtLR&ty3#za1C2N%KcX7UJ2TTY3f z&kjSi=5RUYuep4TJdTD?I5B$3E~k>6MxPmp&6kR7%!mG`G@Kt^6#*lf@viJ_V*9t9 z&P@0nA|c`oq=YVO-DM(Ze!Ber0j@Sk3R9k^Ir$@d8o0xefKgu{8p^fE=ww-x;Vb;0 zdB37{BbZ1s^{3QDiW&_Uk-w%iuf{_`|Lw&aq%(h*dBD+2crwD7pA3J@4@ET;7bBz` zXN{jq>;BuC(_=x@9O(RYd~IXJuW~rlIcEMqIZ)w}abmDbX!?X8>got2zt<@l8O7zR zUk$iXE9Nog7Tq8(DjhzoNP86@Ah#tEk3PCVuJ$2kMZDlF#T6;(^NM10N~WZ$I=J9;zgivt zkL%q&-TMMPeIByaQ2t?qa+AXKMuj>k5xtlU?KkIq%A23?WPu!VV?6|w684!j$WsEd z06|(ND+x+?vS?)7s_W4vUC!0cvwk(3mBSf@7)`CGv3IgzAz_cUl|P3}q)HmWkUy29 z=tQF3$0c9#vchs7R__*!biY(}PCQm=kka805Sa_YQFKGNpZMP5lu=|4gw5CutRv#n zQzA{~V*`JQ@vmZsLg|jsdgBO;jGbC>fGL^o5Uld%huwwBP4ybm*epO>W=o7Xrcs(C z6A5~XnQuH4Ls6Brpx3>IGFNZv7jtyR%_Id)*W@!<9AAH&NUWEn8m>45xnM4sJkJxh z$+C}{5~THS>>KIXlXPVy`EQCa=e@T5+DP?iykV`*?U8*A%KD?`I3H_j*T6Xgu99Yy zvrXuS1Nftbemol4j|~J))A5@Aw4M~TU;M6#=BZdb9e;WBoqhaL2s0_`xN2DvXS`_h zsX@FxMnHdH36Df|yhy+`^Naz|_lM~=N;eBh(QMuk;dey1rxvwIbm_Fld8xJrexu=Z z+;5>iv6y^YT1$<|7Ep{PD&__H4;r|5H@q8F(J1<(_U31@mW4lyq9uW!Cup~(7C5dA zz3PdID45&u2OUODE zX{L)t&YApsvn2fHYpsd)rLJ%S!D%xn)bB1by7T@waTWm;K!8Ao6D}AB8ldN94BUE> zh)Vjtn1vd#lO4pQguf=pc`Qvnre0wrhx9)?%CD-F?m9XpJ#IR-QN`qKX&dCT3VP6j z&eMvzDaJ>>1zDl?b(a6h-=^#XrEd{&xL*^W=5M^J#to6n@jYu0I=FmPzQd2VhHtZB z{Z6`Y^QG@SppLEoRI#&?1ZU64M2UIlGN=%Z^h3RQwX|^s*-flLY~+BsoStW9?F+XS z4^kVFtE0CsdKil6*%@?Y@Jpg8|LUFcHW+pHhK<_`@lud7`nE=EV7JwJG*KlEFahLY z`Ia;h6WeA7zb{+CKOl?-ZRjIk=|tp-iq0S|oP!J7fO^*v|MrnAXUKqwmj~xjhLoIf zm6!6*KY*9nbG(tQW9;oyL>Gtg$3MDl&??-(7BcgoI_%-eC{X!MLdYO*f;4T-n=rl>v3~bt~n-B!!6$ za8U)C&l(GUuq|;ZFErUcKiwKz@9Lw-I5Dy)0tHUM#I11K#kLx6UfJsr?-mr|YX?z> z38JU+nbXpXS>Q}FCixh3x;@fNWjK1ocrPI*C--6ZX+Or=8kl%{4~%Qv3{CG|PpD_y zbpqN{zL#DN@s28B`eTCXZ$V5>>FVfA6=2%6n?Qcyx*F&8;w>4Ut)0LF*+4_dUioh)R6tWMB1SdFO@JXxqHgEU?}De+zdy%B@A zQtwA7K!=lD>~s;e>iHuc9S6~7X7UhX%;m3xrjRk(*O>krVp<_^Xt^oGsZt$_U6ee`JLT~vIc1*zsWL6y__&+Y7o z1l~;#Ag7vV3>y`#hw(>kr-Y$UxaXXaIC3@EVW}zZ-%R82H3e!V<}cBZ@-d+$6J)-& z-R(TC>%hQ^c2czyZ@(~D&jdX8o6mH*X^us#vU+}!c~`px8oQk(_?;sX{3hl}ufALS zq0yKN|Bqh}z#;JKeVRmH z-Kz8As2T2uoKLt@Nstu5e2hvc19vgbHTg;o_l{-pjExHH{1R_K_Y0_(D6jV`Pu4E; zopVWhpXQFF(cy!RgiWr0((~IUr~I<_Jxl)C`3tYWvMguvng8`nl`Tkm|fWp1Jl>r|ncnX@f2EA0v~OG6~rzT-_>?TTF&&@hSqu zeRi^?k`}Lk9J`?sfN|$x2%OH$s9t&^5ICEqrG!=-ore0*ol<+~bbnQ``5q$u+KOCa zoi{k-^H{1CvSmtHzUECMRKa-R*_W03{336!4qYBfa=9FAsG_#4-IJA2UyX8`(g=wn zh|tcX#wy5-F}i3oWwTn8afG zyc@DElRA}}JlTnEF1ox%bi_tLQOiF*G?ZIaHA#HZS5Qy@{~#ult(eZ39N@|#&YN|>ilUPfqQ+@UDnmt-#&3GI%%%NL*R|}QCnthF4rUW6D?7CC`c9eX_{BcT#=?pUwFaV~EYXgSe71iOMmCvgYLElDDU!CdUCfy0dkI?!ojF9jtFQ2oBu?vWpe}&U^$DaC zvDeW7GIBR=x+qU++iBkAvZn3G16C*ERl}rl!<4_OpNnwjsvTdenKB zt;_wbJGF#w9leMX{q5B`9)HnyknV%APo}f)>PG1PQ4o0?>D_8DQA515Ijo`|y@~w$ z1eW(YsrRQFDwi53rc&%8SS?Y$elrZMJgXu3mypNqii}ZpKxYYe)+b~D5P)zP;XCZT zync6fZ08UA&0B5&B+MhYVLm!pI0#9i`W85A0c z|90_%qzO_1!X%rM5mivS*Gfpi#fNt_mM?VGL`Ns!l4Qj=QZSg&@0K-0`kat@B>SIg z#_{Pl*hGvfvO7(byl{v~J5v7ceAYbV2v1Gmd7*kr9Ds1Vxwp0P)&6y(zWgysysUTN zy~wSE<@FmecIY7%)#=rKWg~T?{T$yj%VBaFQTly%kj}Ul$}qkc-MT)Hd)vp}4zBDo z&I3p1A1-ml87IlPg9_yhOJ!coCwRS6tJ9-n=VEHF$L727inJZ-9t>%SufinJA@(?y zJ&1Ke0oXo=mHeh8vpUy42G{o~6Qa73mvdCqf;Jjq`@Ns@m?1!Z0Kqh5QTK9?-ttu({y>~Eg(F`Ev z6T!6{Wm;{ctjWTE!p;3mU^UbsB{})+yLZ6@(|{}PepR4|5Nc>7|MS1^m-J1`FZih9 zXpY-%pv|5a4h`s)w2v-78wXCz^@54s`@nYsj4zJb&GAa-T?^UHIod(z_%ts}Y){!{3lXS)X7LoH7#{C5=&0yqThm$d~Lq)4Ki zunACE&;LACz~g8bgf{9A#D+L4q&VjrVtu)uzoM+0TYTdo63lJv^msY^BJrncv7{Fy zP#t&ZGV2jUtNlVF^6%w4Z)0{e$qGQp@e}$_&b1S^-}~o3iKFg&(w?A%6+N%lEm?t0lMaWWJ$K8hFtd<( z#9p2hVn1ey-S0AbX|&-CT&HKe^yb@*cMkrirU3WHzf-G!|Gt;ft2Fs4QUk0qNOL{x z&RgZ$i8QOt)#J6XBQAL(sM<59M^vhmaGZ~YVS~2LM!cj-8!c``!E5&u)!l?QQtSP7Hvy!Y4(XNxwJk`GJOk zHUGNj!#hG%b>bl)l+%qL!$H^%{`w9OhX?RPv_xUz>pJyr`(>_%n9_YnZ>B>cn%&kU zI{gAUF8X5S!9?6trZ6uIssW#yfQ7VWaduH04<+?jmxZY-~(>3;RCpazomzLF9rOG!h zKK`@`ey>r8g#by3HtH&eo>HCxg)Hemc0^*cEAEatqduRn_4Lc2-SS~Nyj0S);#cT=*;k}m5 zs)7VW;*J|ZS#D$Ckbv|jE%}8Cd)V>E>-j+@{^-Hs0D#|>tkCB{@?qH?@wfno2*>HjrvlZow zu=prR;L>L-G5H;~KnyZ3t&qC&uihB=VcS!}Z!bO52L_yZj%I@f6`3#>^{>`8kAHTm zz6`K80JiUif|oRv?z)x8f{l%SV`KGN!?}8)FvV_L9GV-C%nIsTqyCHadCCe>y59rN zv}6YsBei0cS55l`z7Z^`EZyNc0}Qd(95$mHK>SJX=9IG#Oa1NVrF-BSwtR%U^~vK* zGel;J0VQi1KZ_xzXU>-9G*$VECopcLu;sz(GsQePE3Q9;Kr7k3J@{w4aRJvdTK<13 z_M_V0jC*@-mygdfQCUz?#6D0hA5(t8d@c?rtPAPX#4NqT{3GH2vFbY$yyaTvwNO0} zCvW0=gKW#Z*R;QRDyV}3TGupmSXeu8X2@kTl6>Q=e z#SG~i)efg|59`d766otlC~eq^x;eY%+Bj|7VaVGO9Jmm1ujG5;nb0RRy(~A`dF=}B zif{KM*JC!V5cS;b4m^WZOVY1zpEjMX$E(m?plEWs{mz?f`SOHSlJ7N;|MGFzLgZ9) z`jG#iwDW!u@4h+V0X>CRhgKTDG=>RScmJJV>Ok$XG@`j$8WY+BmewZYm-I(B;z1_w zbPYYXUztAMDOVevE5l?(q49;vDcB^u&)2*KrRf)59y<)#C__@z!2E%?GIL<0JaU9$ z@z$C2^4U&n_y9e_>6#Q6B`fkdvvYMa!Vvs8HY z)@Tyd>OuR#!NY+^GwX%$k4{?8v-o2Ct_T_;EWBrExYeY-ojxB~^8SJ8^Lh73T9mSD zz4Qdck_dwAoU6%Kav%a=9rk*vGIlHRBl=H5y_#8u5^NX=_v?VA~vY zuW(i|FaYO}faC02F(LZmouCuz4AIVtRFaD{d1V#}3v66}6Jm8M5AA{I=b+koJ$jP* z@k*8ydO_kmxGSzPcecY)iokEhk@oKkgMj+n>V$G0!=Cx zzhcva?*sgMR%nK3&iFx>^$AUu6$T`$AAR6?Io1FyeL~utl7{{aJLwjj8_TgF4)$;-kLgpPDxwM>+S}dQ<>G}!m-&8OV`c|Y}qYP%rhzkV8 zBC8lZMBGBQXm9)EZnry&lL}TZpB}xhLkfy{qge$0GCfOPu;1-B2J#xhhV~VlTDd;C z462pmzE70r8sec0-=$3}X<#*K!2r|>lq+xfcgEUX6p?v*-;S}?&Ax_FCY~&Q7dUx# zby5FjUtDhmbjEQ&Br8G8H0w&slAB`N^Yk=q zcdwj87ho$ywVSY?K(S>_kXS31M~RPz;xam*?8Gs74JzFHps|Gyfvn)&4F1*PV zn#Yw~U0uJq+E_kB7y+Gvwx4u$m+}!eX|)Dp2^3AW+`R7s=J3xotuKy2xYFRf?-#X3 zCA|Fn_XQwOiUPTmA)mopgS7TzBcDZ8s9HF*gqdoTj-i~q79UPOXykCTELQHebBd>B z)Ica>(u_kcH1peI@-cMDLX&l3{gP?rrFORAPwtsc&lVbfK=Uep8AWT-e!79V0}&N% zv~IWVDA5)T3gVZA!|?V8-6z@2ThWrT)xNefWnu#f91`?nf0C$R8yg#}*Dq8UdSj2K z5@lP!axrka<@3>*nLw=T@{P@v%i1yl55D5Q!@2rsFRY)wOWef5X9H?amKUV1eb(7^ z>cbx9`|O+n^=9l$x*|A#-JpH3+}{rq^w>&;uBC>T$WnL;%@R8LG_uNaYSbVEg3D|q zLmd?M1~K2IE-999IX&=*N=cuNIn#AyG^Hs~H_)PfhTe&|9Ayyk+h>QeaPJgBB;Gii z;NwSMB!bb@6kc2M{`kEn7bD4L8jkum?`_ILvjYIIBgPXxWh#J-OxPo_inUZLXv(?x zG$=%J^$IGhQ3DqdSEC`?451Vu1qE0X!UTow-otC1iP67?Cj)6(kV*@2WjsYh;xXMl zMchSU*sbB#f_&HUdkl2>Ux`;bKh^u1MeJS6Kctt*B(mA*Bgx( zfB*`SJ0Mgn9ijE*i*Na`OuCD%)2#6iuH`6(Opqy4=iZ$tD;+hQf*Zp3%RhGc(yg3- zAGHz0FI!H?>65?kTfDe^@}c4(q}}QPBG|2a`#tyaAE8WfTmcrR6T;;>Ejk2i7uN6* zN$RgFUG`=ZeKqM#0!ajJ zQx{X={75@W7CNv;N~bYtRd}Fs_H^HdB`pea`b`<%F|SQbKbHdQV6r`;ZffFeQ6$>F z0Dnh0fgU9pyy1uFD6o%%O3s1{OxZriTa=^p)Xd?b8B@08XL^ zMyL>mAN(>*mt=!NL*~J-?;89+j8XXMe>p)X?Q-&_JJt7q)%7jp|;O!gXG>VR{|`N>34==(g2PSJ^c1|MyB~wrT;Lvyc zQ5d0tz$YV!MBq4)=s0i?@#-P-OBZiky6lZAUHftK1Iz4v6AykfSQ*lFH$S%zWF=HH z0g?3T5H6IoKi@pgC*wlc>dlskO;c8`uBThrU?7983}=%v{bI!MeffvE;9UOzon2WT zVUKX86?$Rlv$}1)Pht=Jr}WnMR$?475#$^0(?g4-Q5Z@xx4>=>;2-cs2P+nqSJ#sjnquf=;NH2lEc}6RGwFeLOCtm5YptGcjisj&;uW;_B?MhB`r*W?48_6tEiAKQSrxqvoaJ{kz5>kE zz-u_r6l@i1i)1OFk^ROjW%Tu#|5&7%~?Uea{%r@|C)@e)ny;`FIZV z{aLPP69Tao@c_r>T`1!XDzq9y35tQ^R&M!j%mY8{g~v;DV21UALgwYNULpl^hI0fF zl5=y()iR`7z1=OQ|1_5TM3t5Lhf||mbz^@cir0CiZ?iGYv`ATDv%6KYixZc~XT^oCYMsBJ5W3>YF;4b1ZFqd)Uh(@?!WJa`gSjde z-NxE+y|c%;mS0rlnC5XY+juc&soHWiXdBFs<{}z$3$n=31JBN~LUu1b!xd2I?d+}nIHtfwO23w2x@uyLR|SvfW>;{Lw1M3+>w@s8$?F!3`IThr6~_#y;|CSm0tMqLzZ{s+M`;f&;x*|s&& zxxxgYy3NYA;~%ej%Ycz(h4CDvn;{e&A-gU(@Ni?z&CR_F7BB5s?~VR5e?VUCetD?- zY2+su&Of4X0-MtT4kt1BeZSs4H1@_e8&WD5)7(CT^0Pi*;u5lIXSg{iKQ5Fhe8Y<3VFs1>RQ zS@rsmoXpqQ>ZO6Xo1wkV)W_}`!L)U<9|lN~_g?%Pz zG6?08e?UGe2i zV9Xma*;<$XEx^ha&}e>$W>DcY9U^tzT*^-wclHc1-`mp-;O_xHb}B}eqvSkIk-JiU z-^{d}y8cFZlrep_sQ?1KDt=mOHj9Fsa&atQpM0fVNsNK_>^losG-rX0iOq40)f9JI z9~w8#wo<-BfX!`bFP+|w9Z`adj5FE9Dwv~$Wp#g7c zwtA|>E#-?<#Nmg(5Ua&{H7rt~$L_nr?4Zpey=O%~tH2x4_X_eg64dj0Xq<0E*AC!s z{UH%dl~pNamLmIpDqS|p>UqkeI(^F2J7r!t#GH~(NClk~X*ru2I30Z1mNG&RT*;~o z+5s=fu5~G2*7n=fsOsqGeAUr8xH|vU;?#V7QaG1s`)>EuqO7j#1{iMvV7Mo#+<0l& zCuB@ZALMOo6|3xI#y(Mz@!3&=Tb^6D!KfDsrtWm~BBdnprA_T75Rg|yu*BE-PqFhr zop)j#ps;(f{h|YkoPb#$8=%$OD5RQT#sL+q9-c%Fl*Ry zL1D?Nspt){(Z{w*rDoN|@!svxEW_~2_uO>C>ZZQ$MMcx~0rqDvhwhzXT)x`G56i2m z38p@aIg4n(q7ftyG5Y)S)FXeEd{$oQihV8l82hv9(~PVGm3T<5&r?joGOHa<5i0rW z8*Y_;)J2X{5LS#AgJaDzZ|8+csC)PPe*%@9ImqpTH}J%7^3>HEnrFpG94n@jw8WPE%;|3;fd)!59;%u21b zab00S0TYw?jhMZE23+(r%wlf)d$BZfuchVNY8jwUXgXKk}?S}k*^*W^HRG2eIqzCfD?`g{8lS8XZ5D`C_z)_OThU|k0L*U{zQS=-@%#w+|nuQ-u+^5Mq$J=iE zdVxNFgUZ>w{Cp|~8Bu(T{|ONRk1?XPv&fM_3{!|{xR)qgQL$PX*oGc$@u=t}PNcS< z6Y<~Hda*N(V*D$IDr8#P*b@G znS1WaCOum;BW4q%%G`7>l01CH`c&~9ulegkSzHx*HCvuDrawouP5Jtfr2tLIpP2P` z>-w^7lSW-{+1Tg-fm3YupSu(J;AZO#4oe@+lIj1k)-_tH=K#k6d7iM|ybnwVO(>mv zl%N6M+|SL}t8y+pj@&aO>+|~aO1U|7;JjClYbYu4Z}zz9Otl#p|0*y(wG?+nF5qY; zy)hgL^H^h$Xcl}UI(w4Zdw{ciiB>MiHSMjd(gPuJbOD$jQGy!kAk?kAd(B)8#YS;& zzt4zjEYfxjz+)7g74j&Sjdhe!y)tQEhCVO~#YJnd&uA>kt}$c1)g1Vw|B-VI)Q+6) z7yJ1im~r2|eVdt|A9Qzf83LXRTvp6j7!fY%pEK!5DWgyB#-K8P&L{Z!mL5bR=hBob z{DOcM7*+M6V*%tsNjpz(Z^FcFzRy0M!2C-U%?zE?o12L4dx-Yzk8Kz2!GRi3^V)W) z5bD-Yn6k~#OpNX+Uq8L9J)^zyfAJjg?-zQfs2=3o6Ufgc>Q_YQp@QyHLO&M^jN^Fq z?#EY8PEOM7%5X%D7{r?e7fJ}0d}ng^xT) zZ#J}NSD*o_Gq_R6kd z(R}zm5q#Aq{$_8gmGXKL#XpcsI85)!?J~M3B`S??oT*ny<>Wr?857MOU&v+`@63=B>NrM0KzqoK z31$M}@`Q&_C>2yLjDqV&Z*yyF&3=b`&8eYo9jY+)7M35H&K;3S(Rd`XBlyE>;gjm0 z&B>brwUno|I9AHjUBHX@RLLG^7l_R3n4vdEW^eUu8HehK%;C%);=#Fd5598R2`8z- zV3O`zd4co(@_fe1z|@UH%>+rVjq=C0nInIc7GMXx^UUGk9QMEU(M4N~UN!XtgOk`9 zt|S=s7T#y23qSGCJez6O1vk6GCr{;yj&}->Bf3ssw}JWp1J1VXG4Pq})u8wwcF@97 zFV^Zbj1ZA%L43c0X@=H_sMFPIuM0M4T&QqgfR z9rL4_+S6=}=J8je%&0;n?Bpf**DZtCO&XM$#)5G%xs_-Ov{wlyi_la-XMfucbJMgK zK;H;L(I4qC%%@iIJ>XXqT{F*?pyq~tS3a~|Ej1!mR$H}Bn5}-B`m45fKWMr3`nsSz zT2A1am-qT$bN!C-aUwVId(!W~T3T3`nEo9&seb<41{QZ3)4hg66_Tngbu{gPC~@iN}U(%oUlTT(xF<2 zjOy-wceY$KXWYP}k>c)f`(?ZZ0Cw!_+IXWIzOlU^7h)_ZEF8Bd?UTGM!nN!6`eamr z9y1h2+yRAe16uGNEzmcrNfZ(9oKN!u?lB$%C&~sj%(IJsZ)FDJIU>dr@lUI$9RF}G zZDEV4NNcN>3s>91ltCZvRPQDD!|PMU+FaGj|JxB3p-`Nx^n-$ew_|imiJ|GQ=or6_ zoM!~db%D>uzfOtXne5RT17R|K!6;9pdx49J3ApEK7=Lrqu=Na;IL92lD);g%{SrMr zy>K$fvnKDQZBzHOW0jGaFEVBeFwjFYS}gx#1{FN&50{l7zw&`m6eVIe0l zIUxZ^NXSMxz3c+tq5&G|Rr52l!E?^V6-+Rs^*V0(?-scV4t&wa?(j=!${<3oOfR); zmOH&q?CJSF;x~`2$qFKNt5a8w6{bugp#!)LRJjiU2dCOQSDLQ zs#woilZXD7r8Gx3Wvjei#$ltU|0ILKQ<_n*EgeRf@PQLg6nyr&8jJ+1^|!E6C{a9N z+SJq$_~)&m)GIg{c2bMG+-jGtB77of#PDGu;RL>{Qo|a9t#o|~AU!`#xm}L>vw3MV zMx}MYE=?Syrv;uCG29-eAsL%m=B zynT&`#8*FPLKCnCXn)wZ$N6%5w<@9?4kVz;wtn?OqT+qo`lA0S$&rm=|IORpsb*W& zpM~)b4|yf(KMU#3KQFQ-yQSx*mlTu~z+=AX+!dCBEbfA|wDgAMnr4<3NE!9NQybDf zwMEe#yJ(l?D%^UlILv(C*GOj4GV=6@-=4Ly(9@AcN!3`RBT@grg<2;!eqR-*4SAX} zviBytu0|$0)HfVFl&yk{>0N~AJexV0rC9Wm#CFaImL3!^e=ZJ{UEr$-_HiNHR&7Nw zyKfQyfOx{-;0hrdj}umSg@1GaW18Di-suA(y& zJS00l(u6@1B$j;hiFCf_A9NJrowWnTH&UmbUf0QOg!fBc`Y5GD`rI@>J@ab$yW#a0 zY{uw2j0wYfCSADK>U`z5ne`3&%BLfD%K~5(1p!ko8e^ZkEoaY}ok7%qzU$%uI=W+r zKJEZXIrhmS<=g#prCa@@`-^AsWK3(H$5K9M2@Ey~e<%I(uJ3s2ry#~9eRlCM+iDax zfY$Nm?OojA>rsLgkWeo*Vj09UTOSYwkEnNCXr7LK=!KAkNt6C^3hnxx%V|&Q=YXnX|OKt zN--Ma1q-wC(ZM$LxwiS=-U#&EBpipaPeWf$zthh1;8{n$8_bcatu_8pmtY|>AWLT9 z_;_?t1m|J#;6sikkdW%~UpI61Q&S=UMLYH&im2LW`mzvr=!a3|+m2OwNzBc`Bo@BU z#k2S7rMhHsPvvG0|HSK#tphKMj%@f`%{n|J+e!gQY68E508jG%m3oM+lnXPl9ny-u zJ|_b^pFYh$C?n>Xn4t78Nx&B8DzP`|uiRxu1g7M_P&_0wQCX9RCK8`}(a=x8(+w|F zc4uEa6$Tw;c9H-!u}{7(Njpg9t;90?3}hQZ6=z3*O>@7DJA+@Xt^`nQwqL?bK|hK+ z45Z@o6hSPb+@Vg4f=8gHsn28(MY81!)zBLcJW>B8UEfhJ**L!%qxsEOE2Hwa9Vhfg zLgjAf7C+jtdBF-tQDV-{&H!Hnu2$fYi*YM(x3(u~<0QajPTU%Kq#j}oq}VXDnM>N& z$(7Nr+VR<8%^};>(UivVL(%WRGFqx$hhh;N2IfrqrCZyWBakAI>=ySA$oG|lvJos& zjK&!;SEB;$i18WGUzzKMe?w-C60l{Jc`4%~g8xP<4(6+V8A?}C0W=6>Pq$PZcE8Xz zj6b#m!$;G|M{kar!SnuVY_@$On4Ln>J_YAaUH=8q1XBu?C|AMt;&1U9uRXhKg!3~$FUD&SwMcMoxmyy&Gu`$ky#)BT# znBhUFIhQNQZ1C84>L-zLac!Ggnp)2XyLTm)dfAan9R2zCV+7k7jnkC{^es+~hS>9; zeUARz>R-d9=-nMK4faOc{uf#yh9c}>XoR0D&?xc69rZH!6*GvN#%VkSm!yEes8}in zdB~1~s#!isDC3fzhzKPeOCoEZ61th)@WpGCmnL;5LF;@J-;u7-Be8BgBwezD(nkx@ zL!AZtN==pgX&OA@{MH`s?=M^6TrJ<*(cq4*u654WM=LAbGw)h%?LptuE4JEYpO5VT z8m&69os`Sg`YZj)Sy{!H!H+!2*jb~2#FfMLQV>DX7f5&m7)$0)SDZ%YXLlC6Y!0v+ ztn1N*--|FZ<1<)TXf{;8WNHsQ|2M)pK~pY$Xh4;=$QlA4tolF%hfDPUoYs>+3O{dx9tCF?Y9A_!(R%3ZGu^K>e{4SL zzB}u9nSs^e@WIW9DRaioOO;&Vd5??p}RfLdx#J^!0L?K^Zx-!tyyLAH9)M;cd zy4fFUe5kvW;!sOXr;RvArxzs*45$|mioL9GF(y$&$c46_a>;*QOaOS{(6cPKu-;F= zP3~V%+V!S66`V1cwv_cugxme3mp*48;a^bF8@!gdESA?%!AF1oR2-pw4HRu~m+e+R ztX16Ctz~+TQ`@p3*+0Y%u5Uo`(?Rw$)6FSCi%VXSX1O@HDsWl@l6fm3JD=Zf4V!}N zUYu~{aaPRXDw6GwZreDAHbDbMrS+RZ`9{Rv(^3pRMxR{d$*G(Szv>t#yXL^iUAak6 zy33L;YKRuZcFy%fH0<*V%zvz%7p^#li@*S z^o+vdATCz>I5z{&H-7kiUR1ve18vS5Pi!h^^*MXHo+MYLHy@JQcFpgQt}80Miw^$l&-j~PXQOX1BRC$oUgfvi%aEL)uHFT9%%N6FaQT<1 zG@)5vD(+WE&OpF|vxH-V^qg85>NU#qwjy?;N4foY^6jT!_YgK}zm5+nuB1Oev~Nu zH$>*B1A?2wFOlSI;%j~ZVp;;w_qV*I`B^BVz$~|wYpFwZO^HihUen^r%RVJpK1m74 zuau@cvsupjGArVP18?E}M~8ixF+V^5`ucigVq(6Us=sk*UdG62hF6cGIF^1DqV%Q4Lflp zwSWHlQrWVSKSy)0PMBM=2M<1UB?~nD0Qsm+pN1TDq94TmF7D|Cfr{Q!roq65_MnFL z-bE6VisMqixYOsUQ1dQhCNK3dD^jyIAhLd?tF=4msX%GkG70~u|EAymvyDKTNc;Xu z@i80=#n8z=vF`=^;-r&Zh^hq9=jpynz^o2R+`PcW1}DF&QoDrOzaNnJtl0KbB_fCf zBQ85=QA)d~*Y=Lj5#`|&a`X_E_XqAqm8uC%J>B;SaY>3v*4=@}!|IuI&B#kY%Q_zU zks`1MRY3eeD!nwzv&M_UW5#jO?*52+C`g+)01*-_k0^O)1{QJy0}7kYqP&zESEVIFWwqV z&n1)VQkk&z^l3kgtF$d?unPewU~ZB)QZ^QikS4q;R#V;BjceY2;!DYOF5sgEY;+GR z#Z8}ooPVng+`Gj`<8v$BZuiP%+8*pgHZv__|{-e5bj%<9C-9_JigW~;yHf7BkW1K)_wB;mVvUqmF4=ERqna>-TWhGCauq# zg~~+GzyZx3Wt;(MXAS2yojr`kR+RP+Jc`5H=da`Sp!5|+@frlHiM)K}EAIkJt@wLe zadEn&)%kR}v`gM47vL8N*)J$4Xe>=iO3Is2p6H-PDM1v0a-^r1Iisc_dg)LZ>GK#T zV-kB5IKK_#WdYj_pQPdv8Tg((Y0Gy_R13zWd{GAcvf9F<_(^Z!^S=%23LL;IcF2a z1jSdAMoL!#DJcx=Jm8SHrMCO=Ef;qeM5e~byBScM=bwl+GF}mNOBy|tg1YI`R#wlO-ppkCI zqon4m=$Y=IRx5uAiw90HU{AHG2ZWkVkIf^iAL`6zoAq`)t{6v{JCS7-ZDIIFQK@v zj@Gwk6fu7GE5F6<2`>toSRt*qjBjqDQGYOX+mB%}+T73?ViPx?TjQ(QsS!A}$U@`S zG|lohOR0R3pB84WSVzM`=iF%1zr~peR&u)|RKQX4VQEg_=tBDxSV~XcT}lsFN(*>& zlwj{7b{&34&jgNq=%yG(c!Z&x3~Gk1%HXr2uYMA^nQkzp`L;Fw4%MF$_|c`BGoP+$ z+??)tZLZmrWY}7sn|^U+b-p{fw4+h=|eL=NMGJx4}gB`&_-{UX#fI2gdc zktC7!@;#qPG(9%PkKPS`Pv%StwQwE!vA2vCA~*Y7C2!vbyNC)1tgHfD8Qs&PL7|ao zt5ku_GA6U)iIjC1fRoGh*bdYFZJBDJ#8{|iAbhe=BZS*>%B*QV5N(b49l4!UC^Pwy zP2n$_LP#28dmD-_PAzrwo$xZv{2%?LyqflisGA%aLQ2gFm zU{5PepVli9{V*!XH665lo@jmhDBjseGF1FWfpEG z*NXrpx+(A|(xYOQF)b*`v&0VFV^TPGKL{oM`sFL|#Npl-6<&6-=B*iI>t&km!SnX! zg@$i;{RxD~OAm+y z-~(W&E~yhI4wSUc+!TetljVPwu&6i>Lnjr$T~$7*eYQMTU%IyhYM%Ia!U;f&_C8e^(%T~y&EHQYI^d{xfjg>5f<72J;qH2W_0iJ!9oHQ>RVNlj9;ZBLVm=> zN@JS7MkcCB8{~YNOW2U|%SHlBk6F$g%)J@kWEt8TadM8B-4|Fcn`a(w$SeENt$h$P zG{j9h>$z!b2v^GidxB}>A6`@$ORD>&ahN$%xrpYw#TUN%%)}r*M%UA!xH=9WkbbpH zd8yn28n8z-DFn$l`akL#$#}$u0&ldH-M&<5jk^~=s~jWlB0D*1W&Z-e8$e5{>0$f# z_U-Qt3doTdW5d{^)k^%!#nh);9`)(`CF6{@%RL;oaAL}o5cFKc)xvx`D&~4+AE}?j zN^fpYhb;*&^J}~<#g{hG^>q0zf;~IhP(+dtVa~Vu<^ozRgzU;CEclg#VBVyegI#7p z#M#2S;VBziPR%f&WNO$=<)GEKM}#LQtB}$;gVOEx*sf#BHb-5kdK@(47$5d>olr(t4_%$im#v#lhIVzb?EMk=Zc*ZgSZl*7 z6fPgGuOx6VyfT?_+!gTd&%DvkKC%A<-7)Va`xWhIfzX&|!RoNAh`kiNRt=M{s2y;6 z+NsrsoE&K|SBzxSd{X?&^u&bk#C`64wZ!#5&|OxLG!?meyWEfIx@#-gcCF1sP4xHD z3!TOj99x0{=V@6oC6AT?CgrAvQVsS?Xi&OVLs7`C<#pIECyjVI?(dWwQjuRH&tt=* zl?>s)N5AubZcOLBaw6?rG6qZ-{_wc|pUrBkg1fMq4AfemIs42&>madxas4P-EAdPU z@6pq9?m97|42@?C;{30fvWM7deox$o|HKe~oV&v)pf@ddSP7$mRL{9VV*L9I3WHB3 z?2=KJm+H6=67V)AORiR20I#Iw@+rm#+%`bVrBwpAwXBFc!pq#p}Yt(BpZC{0leB3w7n>MSV1zugX=MQ2_ILI6KYpX#mLOldJgqdV)##rWnY| z%EFg=bW|>!6dPDXXq)GgxFbj|@8CSQ%g^o3@W9gRFe z_fn$@DgjRQEEKg(Nl&jO0)2jG2RKUx*XXFxrlhrM$13mA@h_@|zxv8r>ISjnhuJk6 zc01g3j_=Rz4|=?p-o>Yidfy-F3Xlkx^N;e`3>(v-98zUFp%wUYsy~g1^kKZ`uX?5u zvz`F8j`Xa=m4mX^`cB(Fq4dpw(Xq>lt0KRscsAWx^XQ^=yy`0=D2JE>{=E1_ftG%w zn^muuY3O_=^3a3F-{KM!Cco5yMCeTz5cvzuh@)QUTe5=l3ziOw(3<*`L->I1w~84k z^n>X*5;pguEYVk2!+$joh|{|k)+T*U^TgN6@Z$2CNgf92N?}tHst1R|1W^e`I$Hf> z$C9(Elv)niC%OMJDpG)+ug9{i43GPJfn$kY)PP|1RT60xRHhz}h`%bRoxAi#OGUln zgfLTd3$dc=UmetYLgcH21B^^EweNa*6g(saiuY(YP`J`L}yIZ z`LGnjaxK^}dv?Ns71yD9ct4ci=N7;8k^gQ@!-*ooRC`THHkJJql#Go%3)A*Lft_%A zR$@5D8qzP-Ld)O-HHdjO=Jz*zsAoWzM5D2Fx@@Rgg1owJUrb18 zq035yC@}B1mkA{0f@BLNEh^tJ>{vY({(C!t-Q9E1wW=zl}7%Aa~2Y>xjZUdx)vtg)K;#m}>Z=eDihwhI@+2rWB8g`G82d<4Q z2ODZx@?)-`d!lMd85x=GfHI+FQ|58hB^hc4+Ph5&@UyKHsn;-K8ps@3e@;j8D-E3k zLv)0`p;h0+&h~a_DAf{n;Hz;|YQrsKp|i1&dc@SDQzD)i43E{C3{49oPDQ0UEf$Ec^lweH^^=|~6x=1Z`wF?~iujGB_hWL>VC7ccX@BnE6--0V zgZo|4gRs)is%zK0EPT_U9jscm=AR-efB*h{=5>1uQ5rfo1r%Te8-KReoStzqN3;JS zv2$u*HzodYQOl9@#tyvx0k3r&rfQsQIH_?i}k0ajOjU zhdD)``m(iUN$MZprEHDEJ8D^j5#b8A9};bKAbZ=P?}ol2mxRC_lIaxUT)1Mx!ot32 zXaFS--K+pB>*_?lDhtRCR@w5aHEf=$M>i%kYu@i4b@^SfFsh}@m9_bql#3hgXBC<@ z6DzU8wRb&(FDx4XQgc(?lJ&(Upt-J?W-KR68|1+dNM}F?3x~N`wM5Va+ImxN>Ue%x z6(m1?b=? z-5|EIk)}H@>-wQ|3X)DvJn`T7(9r~_m_j-R-Y-1>+8rR=#gMv#5ZLOCm%g^zbFkEq z5o}Jfp05r9a}ka}gsnXoQ?+p0x1rLr#gfC54)87pW~K6+VoY6CCC9@nz?#-SHV3Ey zdgTGrQEJf8VTQ?}P?icr3^8FFr7>n$TLcV4J{SDD&eX*t`$fAj*&17EZ)UTnKdy#f zCR{Zv_^|ngM$c{PkJ`9F-|l2#d&N5AeAC&O!f4BVIBRo@MA1HjcV`W$DB1;nr&9&k z{Qa4#d1f#lh|g{)2p(Yjjqw@{4H=MCl3%_TJqVmVF4n4&zdeosVm60TneP$ZqVk36 z#dt_0JXV47B%EAaoomyBG{VBKRKN4&gc7`5-rYf$6X*Lz#04cPvh6%@qWRwDR@>su_ueQeb zGWlvpsEkBhqYm_v7(-;rzI9@|5u z9e3MdYv>g?>morQ4&CD!V|58)>u5Jl{r%Bme*PWu*QV=bo}q1}M8#uglw*{cVwMv+ zyGa$YJAGocIH$FAhM4OXHGQ0XGA1CSkipK_AJYSvWa?FkqO~!_$fV_;{Nm_3u71c= zYBDf|OpaUf%Dcn)N9W1+J?<|affZ>ozP1b33v-3kToNHvX3qp4zpuI~#y;hC3+JfSuXWw@VC1CUChZyMzVdN9T&SbbQX-(z{q_xD0n=1( zMZ*I{A|{6|DzC7XR!ta5Fe4KZ7~j>*{ixCA7F;<;j0OS9U>K+xj4LJchWy-{k}AHP z1&JWQ!ab>);2G$|Qe3y0Wa-N*jSK&fe=GoRCvq;AyJ`lVK`)1DLz*V-M8B#lMmOWy& zF4H{iTejnT>HU%@nwCN^IBWiN*KuXnd99+Zd_CFjyso^4?}uXpQJypV483iZF{<&7Kne6Y3rf2cnBs?&_^7w@}T)l(MzgV4K^FcOm0PJR;TdUm0#*~T* zPPhVV7qZCRnQEHLD#peBtc0?1_yzVzXH9%C=36OChjI4dOP$Mm--2PM^q(z$G{;9_ zn4Py3k`?0{DZe}U&R*5Hvb_u1brHa6QCa(Y$4q?D8BvJt@uHa4~k zlUm#QogA;}#Ky)(VB`fGYK#}#aDNLj$lszXx7s^>@qMU&VlCnnVd{Z)`|Ty{<`Ql? zlrmb39c6cm_>tze%Opo;xmf>m735_TV!qckiAMhB!nNdA_to)Si-~n8t8jWZRYTI1 z$u!THdUke2t@6l}_E<-^=)&deRrd~UFmv3EXCP&!>_~&%^1BbRK#@9et-M6zUrt|Q(@duq5Bda zbxy(OW^$!;9+Vh_CY*wt9-9mkIisc=W2x#2aTfDI!ue+fn@Vh14~G&4S0@`(u#XVL zN&qfUGY!Tc;i>BT48e$!yga1k<8BJm$pW>Q_;`1&72C#R>FnP!(u6SGw`_R?^633! z4NmFNY5%FN6V3r6`edY)S4%-zjD&)CHo3n4Ht2g*Jx_tmQ`L z^Vx``_*i8Vt>^RC&s~o@39l|H@+WxyikHJLFbM~8v$ALm-u)la-U6zM@O>AhB&1tJ zx}{V~X^@oeE|HK%N!c)z(%mg3O7})uIz^POO*d>dxygNo-~as2y=UFC*1c=pS+HjI z%rNZv;{Cq&dA|2~ef%1n>@q$cTm&*9{LL#*0Z*Hp*Uqap4Y)8+jGl|({nO4#3<}F! zzisMXQzJYRr~}n7n`zSlMwE8IZuC! z!#gf|Hxi4nug&m|JzTC7(@A;6P~8;Ja0_ezv0*kmFGe4BI-8-#@e(PChf` zOKX-$D2#IDk3^ck>_`m3A*yx@*m$*ZsUHfR$165cNX~m4B`^Eo(zavrZ7Yn;?;~OE z*=H?tDPEdg(T#oYH?;|KjYs^$^kosafNp@>`5A5T*QOE&^DMKt++Pkk5VfT3eGt ze~$&l0i(QWcldiOaa?HNG)|J<|5VFH@+m6JT8OZSokKf2Z?wHo2rXM(G7h+g0+`EC zdeYpC)UNYJ>yaFzzH<#J#*Z%R=Z?kYU*F0js9{5hyfkiqGv2Prd56!5=&_UvgW>Nm zRDuTkW0`3PfJaG$xFw8C(^$^xsz0z*-zyN<;^~y4TZ2D|5K+#vt}%A7J{7zl`YL9h z+8T21e|YKZhx&77a7Q=Z}oB7c6|F5E2_N7DY~%ZXQ*F(*CM7 z&wQ?);Ux{V!3CxI%x-3A>AT2R)1I_qO`#1hC(iQ&D@SuH=J4@nk6DIquD?dPN>eSN zMIr;NZsB8GV^HQ+mAYt;dA1ikwblEL!@`Mjq4&!YxP_D7{rgiNOcMOfMG1=bsOG#y z_AvBE_;i<=tOftFE3aSj>g2Z1UR7kG7%kSk>Xba&{N^nm zH3Iv$oP8am8>><8>4z;`Mfe}ZbfM$Qnz+jsJ}^ zT`*Txx_+yIDHv2`H>8WzMN?Zq5>R(=6mVYYsQm2m-5~l%7uW)PX8SF}&k_B!nAoh! zT@uTnHY!15OSO<_HMD74N+P^sa8SAe(=UnKq>kLLEGoztC*+`V#j|USEc%dwjCK2I zEz7uuMy&q~q-uEdYgrs?i$%%spSPV!Z~v}rSd(0=?TJ)}xD)Iq>|?N)pj-;bIcAcqO$?{hz)#TU^1mun{hT1IRz z^g&lo&({LnHy^MntX@a-2gs;6X2l`tHF90YY5IIOWe~o@UgQJS18+?-^hJ%Yt~)@` z9*+vsrSRsBVDnDR>sp$}Vt|?9wHXsgJqvY+fT|Oe)YN|51)+ZB2_LrVGdeY=R5A># z8^j{?;YmLI7O57?)w+Rq!R=dJ$3%j3Owt^Ee{T1Qi*C^$ zw3XV%JW&~n`uwYQ{O!1%8kH?1@nTk9XT~-bKD`eMBu(Gq7?JKrGZfTQTVT2sG+hNUwKL~%I=ky| zIAZlORt|!>ZZp8LE9^agS#HM1V3?hxq|m;QCs&ij8Ehg^)yiS`Zk+JXKVoOESuYHQ zCtdQdTX>81q0Ltj+9zVUT`gvbNGSyt4ZXati%ARiDXg}-d1!?R`pU9DZ_~;{GW&sf z>*upxyG?-i6>msTmO33yND!3Z%lAIumwo7x%iZB%K!}qVDMy@dNg)kNtB}+|ok)!v zo{Q|jeID?gD!J35+N^Zv@~EN8U(Lv%j{K~b+JeFY*+uQMRqTz{_j=Q>CrV8))&ieQ zN1&;IGsXM&I|QO(x~nQc=v;w?1zna+Qb=lw*92%(;;w2kJ*6`13@v)?RF!zZ_9krD z(bmpynB*zl^J|=aRt_Vj5!JQHj#f&A&w`OrBTci3Fd@Yco~3ximcW|q&TTX+1e zT!Zu6y}S5)0r_T<9JEmlRn|c=iH`naqGpm_6lr>VQro-UNrrE2t4Eb(D+f(t|9t5- z0dh5mDdc!urLooY=LF^lchL+IKldzA%ze!C-;8-5+_#`#8(Vz&#P*XTkz1b_OrNUt z0f&G<5^aD7nbL9!Y`Gyd{mnW-5_5A6eeYzzLu(lDHoKPIK!vjJ<{>sQDkfC<eoHa4Jq-R1GefW%fc4)s#=fV3|tc>jKv_$K^O;PIV8r_ zuVX6`sV@ip-=}EDc(sOYl{=ScCCK`ZV>PWG1 zP83v)|Gt;&NMmtutDoBD{H%wkeeSw~$M2VYw9$Ze#Ns&ec9G9@pKYLx{d$PDeWn(dQ27Fqa3ygx=E9C5|;j^$p ziMkx+Goy)=bE|zgQ<;GCOlw0^Tww#p8C8#T@lB89+wHyLa#0y1ijw z_R4FebU|uu+pBPwhleS*OUcB%8a0-=hD2Nf38fYrU;1^pczFqZv4;PPBCYpP*nG_z zf`IV#K)c{BbN$dJV@Nf^S-B=>;TVk67#l7wZg5_RfR_ZYqlg+ke}T34XuO?*l;~N5 zbY-p}C>W{O0c8C)$8m)_l)U6f_~J#|`zk_pNS#q)vghlla&7Nu?yk(-C#Usq9L%AC zJW*9bY00Xd%w0M|HH5wv}&s0-{{EV+~2I zTfZp({qxx((Bk#`&X)U-{p|*2T9T09eXl~H{w+9VKefz2DP_5PCl2mZH~Ix0W3QA&v=GWIJPolJNCVb4}v$HWF z_(#y>^*=C+wTw#i7o5B~Bp*h=8pQt(r3^(_b~=jD#AUe3L-HgKjh@j7cSIOo6(1!D-1k0^K3ettp-`Jd_>RM*^{qI^Xt2L# z^+6MS@t~$J|MK&{zwV6g+aB*$O=@!Q$7=4c(#tPGAD$iLFP?r0X1=?Dg;jV1-*mvG zfNOErPdQc6_$ax!xOmK(lP|MGUf)!3WF{WhjlKOO{@AY5TGr1`ti=nyQd=A~^Diwb z;V}pZ?TZ3v+YxdST!y~mj;A3 zu%KeBqU~Aw%R(D3>-S<>*2#eCqY*MQF&uCp1>K26qb_G^+_28^ovv|SyEe8ua>WvS zD5j}D-vUvP*5B&K3eomsd#p7kRP%UL0;8`alIu6#3eeJwY#VAcOcScYWR!jVwMX(QDZo z5Lo&&sb-~*ff>SA`*#GFDV{X~OJD})0XzA6(V%~*c9NRMY0IneKhz0GeNAGKDuTX3 z`b#2XIpGBrQqdU}g_{au1LxWj7Aq)csq&-gtv`tI?!i8 z2&w7;*$T@FDQwmx&&2ONtNR*TD`mTp|L0SjC32k-)w2em(2#Y6Mj=~YBo#v-QHxK4 zGov%vHW_DQP-ykp@a)HmA(Fnou^&f=)h8rfXguxSz{bqq(;lf?pgzQn-K0(7Sa{|a z7qjtncs;w037vOo;obJk1MV)v-(Kpx$jAD@$Cm-`L|AKX(Y|A9-#*kvjEI~c*LiQn zh#~008N`EuqGDW}CX|L)>$PT&4^%H;Gdb6ZarQ0qtZR7{IpML8B0i!*LE=$dB8{uP z{ZVY}PjET&d(dMmyhG8bA%l35P4UK6AlrzB2q~8bK4=KSwQ`-c*@4+~bet;OlA0PV z3QEeF&PqieOBZ0FH?M`UQj_z})!*e{BY$6N>8&3t z1!-ktVbj$jf!9m-v!4=1F3;>9xp}m>6XHIRa4BNf_<<2~00x7WIir0@dhfCqZZCB= zU$)hv+a*o{T+hRbsshf+WNA8WkJksSpoNW%Q+6G{oOE<_SW;3_2(L@tGnG0zILM0j z8&m?OT#->xuY8Ue*~s5~ud0eOZ<}&|WbxzD|2oR;+!bmZ9l|rDcO@-%O86q<&REV{c|bT7haWYtldoNWaO|+~=gBW*;(l69GZUmn~*W zws;{%=U=k4*FS_hqxe5z9?7jCiM=kApG4en%_}NiDP~K}EQ)OUf~i=lK22W&pn}ff zzg%!t?Fy~WHvA%{Y)OMN6lBTo1H0rE6>)Hg>5JOiB{vTuydh`LPCz#4@0Zp$=*~4R z3Nts$q(y%1VMvP(VN4>gpg(Uy%MjG-2xh8DE!OoR-KAYx5bVyo1L2*In75d7#?S7N zS%x?aQ?zDeEC!dK<0?0_Sh$)KxPN^A>$rsBd;OTK6*YK)7G$ zo9YTk5d`wcvnZ}FtvCCbf>}dEIp{RdY++ft0gLV9AYir{L?1m_t zjrqnXeku?d_L_>>Aaiv2k2yuoUb^!KF!3elw5$j-z69p$hIm2(iC9l%vJhd~kl5;{ z%ex5cM}YW4w?Dn!y5qeUvtw1#R|&&xnHUt;C_M_GLkd>j&g`-kJI8_IW(1eyk(+@L zlei?*2)Z$(Ufw~fiz_eXJiV*!_+nq6x$95SNYjENCmGTeG;TVgTR$3fTM)H;hyMMB zX)@%O(g3rjQEG0coPj}_E$~qy0J63RvYp#l%Qw-w?uZF-_bvHL^SuaEYwT|&&hx}B zJfL{>kpGQrO%ZrkcFXpzDahw4Dsm8U%3gz%DVpHqu$S%C% z)tHtTS<*$2X3k?Eu&x4a^8H3m=mNN7Y>nm8!ENvV@&D@v{I5G8hd;i5C%JcFPSqPl zyZ?w;?cQIL`&>+I#`@4US&mgw81#_AUy@_Vu0?f4MNpUFX-_*a1PXo=nT75l1 z;T8-mfc)@Q%j($!kBd{e?AysTMX7*4G)E&NstBa#iIRp!uWot_7s~^zrcYNgi6lhS zebKDgdnWEJi%RLwEG-WN;CQ@pZmny3Jz?_r)R9u46;aKT%;^OyF);A03F(Hnc%wPW zLNNiKuf;)^7U;Cg5>_~aqkQA?vh$c-n%0cXeU6IVy>szN(4d%Ox_a&{SYx4F?J3ds zX`Z>bxvkgwVzNa&BgGDztY@x%m493xAeF!mh^@`o3iIbk`(UzgH#R#v3+X5fCQj3n z=V_;$SRJ#4#x<)K^vZg({yIfIk77th%hT6nM7z5MD!NaV$*{!@j5~R-6gu%q)2`KUdOb+&Cg?Q?HbC)0*`SJOO_3QuBb>g~5Ml=8!W_ z7RCaAO;!qyP#KDnoAtG6MWv12%mWaEn+w#P+QQh$>RTpI+#|?<&6c;H50KWX;s?kN`hX0X|481_W=AoZj{~1AsPyIa{$V zExKOa$cX0W&!0?C89PW_#@1)%R#49^sPatKh+m(%wV*(j$D}bD3n1E@_= zyuPR#bvd0-N49oKn77N|JG8movY$4KCgotUwEM2bphFSiE&%%YXy~=yUr&#MK~U63 z?zIISb_lwg^&VZP)ARlYH4Hf&YnCiw=T%3G>&M&%mFsucaB2gmSy?bu=-&huCP3ug zDBdLqTKw}eH>y*iUfy~n6Yd(&?fBRGr=+b73M0a`;=IC;eqy!7a#b$RGuful#;zgK zRl+|rSvd&;OlhU|GPkdszF!DHq}bGi=b4+RXuSV1COTBBxfW*nK>k&s84JXvZkF+R z0*A$XKdN13K5EA&oI#BOvDoBHD`s&`mo#RACH+>P3hjM^ANs({5AlaaTmMW%>S_iEfvka`7tI|^`s!DZs) z;vzje`(+^ZDB=carw;V}$5Bgd6bhX5(IPHFafU+q2Z;CoMJ7wt>G12NLr!48imvly-Nzft9%%5^N74fx5QGpB5&4L$_Ufn*D=RH}C14jB zT`$O3jl_P1SxL3B*w(f$^+|Bm3)xT1+Mf137@ZU_Mqoy`#tSSvkkUKdR1c9fv*Gn@ zi=@S1V{R6dyLm|+t|^k6_=(+@^>C^I22rLLgH>0oKxLY>_V#voF4|pd zZ^vdPfA|e3vz+;OfO{xJ!QLJE;^oZPk8X|(ZON4LRP}M#+nCFr2D-Yeiva3&^>Qn3 zS{K62W7*S1l6-PZ4SR6;;3duhus>7tI*L8p8H+8jxAJ?$QF9!T(M4y5dj$HLl{P@+Zopwkx5`UK2vc<6$j73#vjy*@h+dAhu_x zZbkhMCG?d>ZGWxu|C# z#OH*%z}33Bpk#?#FQozCw%UUSCQIG9oTo-tLLI{f2M4X@>fg6sEcs1Lhly;z`Hp~H zZ(O69x{qzRN1#fiZqNg1J1*5m*HEj}akznphw4{XpSJhl995igIj)DvXpz5%sY~K= zSAtczk^5_+sZ|pz9;O5S_7no2@)s~;a}=Ox9YgZ-;vm6z_^Bc< z?UQ7*FMs5Z9y2Av=UI%_C@o|L1FCE(J60MrMW(aC5QY0D9o*U)IQ3<`$4kbXJ}_Jm zU)=Zx{J^ss$KGg73JBKFIo-sc?KtyMTc{2%N4=*pAE&dY39NuUHqJ*dHuW9YCTtal zA4(4wfR6`onY=Kq+hk=HSIE9rf1pCE`>QjfH9Y_}?PQDANYI)j>9?c>hf;k~*?L~H zLI7TF0;}LNdF1wOf1YyLq6*m7_rE(9p?okO;PEcqe);SBQ80PL+uFL&cGYC?#r;Sm zO||M5mzTf6ABSGcVT$++t3Bj(6`src$507O7rc@@h_t&wNc;OsfWk7w=?VKgJ60fj ztwr9E2SqL}=9qfz*nmjo^J1rm$tJdOeW9VqHnD1nG~oH$^F~8Yw$)m&ujR#xTOA!fx~I#&UV%AGrOgvgBpSMFO{o zXyVs;YWj6Uc9Q1bdoLo$ISMi_gPBYnHhTQM7lozLg6H0IVx8aI@B#&~oUuB#{Z zLWhp6;2L+ANe=o2JedZx9Ex40sTQ3uzZTK~O6AlI>LV?cx-n7x7IN>-3YM+k?*;BD z2a&s+f3~%Up{_x}_Pqvt?GBp&OAS8EQI_pkzUjrl?G?WD2@FE~j)x^rxzkoR;6VxSo60PHP zfJ0pq^lo;qJJz=G)e>S&O<5W5Ub#pFv-P%Ds`GJEFwftA|L&KQ0TL1tTBFisYjrJT zQv-RuECIh@9orFAw+Jaj5AY@s`B%u|TSHq4CJqsSNeMzTO4ozF>%Di6IQiY8kYi7T zPKh8n>R(qvbf>g4x z-pymYy-qZ)r}Ohl^lm8U0!o0D*r$9oZXF$DUWlJe0db#`wTImA9(MX75`-rKDOzMOKXlGLXL@BsoH4l6=5w1bE*T9Pp`(1gRF3LZ( zaG&1U)A4l-pDm4H;34d720*v3ClrtTEqnU~gT&L(j8`9LYQDF@g33A7OLUUd!&!O_ z{5mj=vLo@f1)}#N_8_dd`Fes+U4{u`WwzmpH| z9>_gP?GWG8`MiGbBmmC@pT*VkXv;i-BiBA}K&8&VqF&fAW~yD6YCvx0Pz2YeaSW1o z!D1wlxK$D!nK!FXhQ5t%{jokWI>L#!^Bn@; zP#%JsQO>B}>39FerFk1~#jLM1a8wMbC_+e@*ziIu7%1|aryd2l>@7djDt~|om)fr> z{P1~k<9hq~Um(hL>U4*v>CWV}4Q`gzTrBlYuBYT?M~5Oj1!l?Q_Ko8+i-i6Vzq!1{ zYfS(3Bn8aHy5DxQr*AWHHV8!fX{$ZGwEgXA@heeOM*m8}ZbdY)XGvw{)F5TEjn-jB zmEs?Uo1yPCkhpu?n26T9q2Z-BoIzOboIPUgvFgt_nE}(8#ilIcc!3LJB8l@a-s%`Xor-J$$fR;7$<>osAGwC7xYID zCVd`!2OQ5a-UuuO^*}u>(UJyxz_YzIySw3c*msCqfhF|MJ``)$cCDBZaQnWCF&`W< zSbh(23qigy77kfA+Mz(s%6`B?FY)?iA=zbDnbqdne_Ad>n__t@Jk6YxNHZss&@(1J zlQ8ef{2dV>xL+Hkix$HmL=Zm48kOP=7sQ}VL;GEBV%oE#&H`azW$Zb0fcz# zNmd*Xi!d0&$^OOi@}D)w23!Mh(zkn7NNTZo`M1TCEufGNJktI}*Nxo$o%Rr{mp3=n zVpdO^6o39Ube{98wx+Y-654!Y`G2 zMM#qNp|Xq`P0XRx7N>S_;1mAw!M;-s!LYdEQ!vcMLXm?4d(OD{_wE`qFvRo5b%s$$ zvO`+#X;&d{JE&%=q^7o!)Ax?od-SwG=k)9h@#i%$q7#!iv?0#W0>#2O^E+840_M|4 z44qikc1fBDa2xZGV-{aprDbGd3i|a+rm9*;u1U%Pkrp2x*sa3{h(1PO8mYadk&2&W zO}#(tieP9&V^Bi|JCS{4d!%T_K?Yt-|Dc^>?~Txtt7YzKVEmg2t7+f<4thj>yDry0 zRkyd3cfm-fSQJ62#WhVXb*Jj2pxgCNNO49dS)a*LE?^_@2a!M?ov!B&FvzxjLU~aJ3Mieqgy+c3jP?V?n z{-8$Nw3UDS$?jpl&5h--(tCfz&5c5K7G;Q>O!I4S-3a%yfpqKV#(3Re zlOuJ&8Sybgy=F@75}rf6rjZRO*A7V_l3~yQd6dDfu5Az@H7MJ!qL*q$ye3;Fvy3mw z2N$7$K>0+20tI3Z`wFMN;cE{|fH;4tXb_&@ev9~#nvEcF3 ztQ^({a2!UqR~e|WrHp<>t))2B?MN=5tc1&Cx)N==68R+3hsj)%xSqLT?sc(+Owp~8 zqqD@^Rl`)3p5x@XV+GaTL~UB(kQIXRVnKonE+rRO(V zgfd*CCJIzu_M|#@e=1Ssz_6Zb>5pGJ9#B7-liGPSO!H-Z3&#}~BdBT92r=({)3l`O zUso4`zVM65#R*G_@{K*_RlVdcP=xIxLC;4&mBKb3t7Bv|`%T2Tbj`%j(9nb8;lqcl zmXQ!zTC2O2KLepI*Zpn6Ad~dk$||1?R`RM(vcr>%cYajM(2$cUokm2UvNuB|>cuiq zTv!s;1497kF-|ur)`me|+9Vfm{&ChWk_z1HL~U)`{-e4Q*J;DQf9ij2bRqPw zwFNNhKmVV%-kr~rq6=NC1h$8SFC?aFGfw1kfQ;+6?zYdkI^uL2(1y?H8Y>y@pH)%R zi-`aWA)7vQz2#$cub%B;RBy&FRF+rF!cQx@MMc8mB(nsg#ZSlQL!PPO(2tcJS1<66 zR)WXMQQY`ZUcqe3;HxrXUmjB0AefT8`|shYAfdFTiod+z7YRPO9d2u zO{RTtJH!5#J*g6#@iKzLT;9sixFL`UQ?q8Heww>j{g6?ImUr1{o z60#|dsL4R^cOdxi{)hmaRTBPjz|LyI5Yj^Ba_08m){Sf&sv+4q@rYJ|DA@~|v>)I* z<0QQAMT^NN9u|oiHq+|FH68neQ);fY#B6A>(yV12G)}*-&h~WLxWADx!AwtL1}zIh zHN@fKKiA~Aemv@G<2}v0{4ib}%%r6D`isJ)4#6?65Y3YyF+mN^ha*>xfYzV|4<0l; z&-TI1f@c4TqilCouH$yNWUjB{+)Jl2N?0T;VGWwhdF)Jaq&wg}v}zHsW>#Bzfs1xU z_DsNIXl?IU;;4-p?dW!&*m=qJYkTbB7S&&&5&^Fk!npphZ|~O$>7^AeOk=5>*Ghxh z*1wLgAz?tkgiGi!CyW6AZrr0T9KpN<6}tg08$&5v5;)Bee)B6z1Je(Zy*MMcD~_wa zTZ6@RI8E=Y8Dib4C+DAwkxN)kSwwxIBv8;1x+0_{V4g8l=fse)FLK7qOje>XZ3O1| zz^g%GDC3FT7b}GUetO8ZmYrXpzjZKFAl3TgxG|SradY!fx|_{{hQb)Qs!?5E*Ac*X0XGf_+VTSuE{Xn_#tG%aSm>!WLeq>J%no3Ow_uL3k&0^ zEUqaZ$Jv?rhZftU=T-!iVMDXfPnbH`7YTX$Pt|^gf}+Eq%ey#t^g@pe%)lgdcTw_f zB53b;RK?Ng(-!cOFW)ocNcUZVkea-n&=oNQK_D|0x8(KP@CnwgO}Udv7E)ZMKko*r zLK&A&nDt`Nxsu(ujGkhpNo(F^r%l(KFBC_AT7CNOf-MD6{OHM!;6YF=7eMxJE>5ch}*%0?mfhXP(tA7N6pWP0 z5bXHeLxq2=nd~+5&J)vq$|@h3isiH@j*qY7$Az+3OuRlcd>hQY#Pqd6)Fvz0n{1fa zfq_&6w8B8Se3enXy_RElLx%3Kh_s%+M5`{=+b09@q0ndKxwWeG?A?pq4>tT}}cB{{l0`qWlbTvF2dq?Z#|n=%cq3h5OYf@Xl_z|{jbtm#17jqbHG z;h(Yd8*hB5@%16x0gACO3ip8v)!+?=D+|5aW`Hr82__Kq+I9liJ2uHpQGxDSpAL+w zM?gxL+qK#|E_Z>GU(pu-SVUUXjtQ5`etaAIytV2vLn=$6sYk)|z3L({VTGMUvu6IF zsQ4#|Y8hY%;LzenxxWA6aQVD6q-O#j?PDRTY zh}a(WuTc0vF!bIOQMKY7P5B{w+p;;u-oAMi$>%5Q7U6zHae1xL{9}XqfU6zrp;|QT z?+Jqeq0d%%`O(L?>8Sp-h@b6zOjl#)5#NDd4XY*yF^8MY>h%_Mm3DG|80;n3!f9sm zPJbJ{%pqzum(qT7gD$o6{{6(%C%2#3D`%MKlzCFp#?AQhgMI!xpLO?V`#mG$X%_tu zn~@F5QVbEPt~t-G`+6G8ot>QvWE*jx$D!>$iBp^ zf!ZW@N51EJ?fD!133u69{Ev9&*7z$BRg3NbBNo#pJ+JEhH zs&ELN3EdTiBUMymr5c)=#zjv~PSk)HKt=9GL@ic|oB7Tn@sSi&Dn!I`(0g^`Iu*Zf z=xS)qgH||Q5Q?8R906nK+&cNk#X^@iMjTjLio`_U7p9fWV}K3^O>`dWy1g`=`I0NY zh3@~d-a*2Ec%O}WU)fw(-00Z9*~)8HS@4pIk@Km;nXpbq1l5&Peij-!CkD`Nc>4LH zdr z=ULuD%&~tpfKu4oKFJ&+YD^tKzP>oHR+NMI=h7g?xVTpK&@mrZ6pjh7+!ZB~rONe8 zZ)K1I4(`vvcc;BS53t`)le>%E>9$`M`x3t1~#mlABW!Ybtzy3a|Tg_sF^^N$M3Kp3l zvc@K-iEzP4fRVsGBlo!e?u6sxP@!OfzBqOm$w(lv5L1BQXZ+7YXgY~hCgk-qOi6C=>V26d5Yp>_;^h5t$*vLs%f#{GDG6M&fOg4kibw59hbrTMK_PK+4 zD=6OIY_GrBv40BbdfDB?oFDmdB^wW8Er9F0&#r!4{J_l;NRLQk6rxm10!|;#5Qj=L zyNS}hboTnYDEv1^ctM@k#qU{r0QuKahbUJJW7*PmG2@WecrmNA0uzJGl>M&am5n{% z=o0g2!zArs>H7S0Neo#oLG*FO@cAGA>#lzacpBIWms2*^*@=lq^;%s?L0avev$?w3 zWVym`d|o^og7VGlL`8M~Qvm+^&eYY_|J$8rr9o}wt9wrjXo`??B7OR@-Kqq7yZ*+M~5F}W%;G0WRq3eACFnhJJJq+ zn!Rkd!Qn$k-R$m#W^=2wyNa>xIeTsT0T)YccxiCM4Ey}RVXOX)YHKLorzT8~kJmJl zB7yVoiO)&-*kre>oM-)W3pjBpk~JSR|G{@ESj6IF=0UlnVR{FkqA~SlU<*ikJ4-=4bI-hfo>BGD!-U~c4J`9&76W}Glu2%G0_uykXx#ZxM97Ll#aEqLKyYD&oM&F`XZ$RgN{ zLlh<2Yc|C)XpTS&qSFscJm^V5k4q*tYmK3S4~%#-J6f?oi=zPO^EEm!jl3=7zc0L4 z+go)W@d5KkCec_>yIS{&y*SAkK{or)3M?gLz~A*v_s*vyVn-kx%~T7CaBQAS^>zrY zQPV}dCZ&i8>I_fOdmnEwv}f-uX_ku)I{&$QrE~2<+qWPxiNi4gSJcj%y+p;X*<(j_ zdY=yoV4}yCFUoDvOOV%Eq(Vyc+mrOX3dp(1D@aD9xtV9s{!(Q&a)k~RoF+UsfvQA~ zQq6r~Ts~Vnd2nmAZCKNzT=EQrYhy`Fz=;$8-$~9zej0b zwH}u`Y%j=jMIVb3H~G)eskA-v3aRDv#&DHVo>A5vi%`32`+3T8J+Fs#{CDtm3(n5R zbvMPBWLUz>FR8NUmY-+Pc>5d2q0VR+QKJu$-{{2T7)f5*w1Wg}*`XK-ZhUwi%({2l zvBP@Op92v4pXX;0XCN=`2^);9nhxkMy;k>vw4ICTFM8Lm?KQw^cH7A*I|_#`8YlC@ zoy(+174U>~0_II_bcdh`0Q?neb96`aWz_WBD!k>hE5tQsQArD_EZ$I*+VYRG?w#6% zr61&ACP@uFA-!wjWA|u2T>i(QH;_>=U<7F6SHPPtHbq^7AL)$SJ%4*#ewoRzud?Xf zn?5Rg{ApeRT^Bo8Xoastwpk@#CzH@S6F;kayr4-|t81PjlF$nOVbktOsN;CC%+Og% z3f2-<4|DF4WFp(I1R+=gAzu<#=lGDz@8`;QF|5s-?ea0tVrrdvWS$F;MC*|Qxwz5) z*QfvAAC|C1lOc+=&SxALkJm4TW6ID@h9u`+Lkc0ZYgxRogqIZ5^Qbc}J;hiZ3%I-% z)()`avMV9!B#aYaftJ@FB}KBleKq>d)3yEd-L5lE7nw`)@z`{0_m<;Q{`$-#(OL-V zw!vYS&eCmO*IVjST5J9x~O*#Dgztj~PSyF73SmJyvS61}U{AkwYvlXzPASajA zq@}wV;(ukK;o&OVbS8kk#9l7R!aAh?9YE^n;|b0W-%Vxh6*cb{{XkYooZCKtCAv~V%cGX{~z}e(Hc0Zu5^Vr<{sz1TxFN) z@;6GCQ)?w}+C9;;06}-=Yl+9cEWd3pzyw##Kkv-;cqt(GEEZckfI!2R^o{F?-3fcvPA})DUD%TgM?^WB~gB%|M&*bdi?^DwsNg2;ZXtgKNf&0NM_WOH|)7E?8ZpU;+S2dqp z@c_-YnKz9kNSG9yHu)+=0inYSD=sd+Pd+&Qs!5VpP2V5M)iy@^+6$gLF)^iMu*KB9 z@%8Pr`6|ur@$jOI8s1=2HtG}XsMdh`(18_3jcOEb4N&alguz;F&Hu&CJN>6K;SN6_VG1Ct>yFM({U@Gga-U08RL8dm7s^SNDxGR*g0Okz z7mDeEw)HwfT}A5R$63*|fvK@>vzh+kDxEp%9FlqbJXFo0if@yN!I59;&4H6+IF*#~ zj|gyXmXeuH^M5*IWw~o<(2=~-@8c+vZO@9#1NKLt=2y?blyu5zR)Ig;V(O=n2Qux2 zcr#&H7r23rY{zmJPd@yn4;tGlDYeI6O4Sp^*v>f8#2eBWq!&*=n>Kwt85NH zy$uGHo9=-+EWG*dVg-=bpe-#`zA1gE%~&jr+xy3&Nls5jhpm)-T#(nkpVxBi1WI)b z6i!EdA*505gewwa9r?E9|MCXCXe})J(l1X#Uik(|JCNniKuVpi)dJOZg!%_ZMEBY% zw%h#Ed11~pOA=awlv1@S15}rp?+Q_&J}!{B1o1Nyuwu~MF^(Wt1*G- zPeBj+!ow)Y%XHNoF(he>s6f&Q-GR9yZOqN-O&Xn6z!!cALU_Z@OWW_sEYdX6hI@Cb zI$U(g3exOZb!6wQArioevjQY%3U>ze*`bXePw8iU(HZ99>7ZB1sW+kf*KzhGOzoo(Io4$@ZC9An4Vi=gZ-4Mv;GPWfO%db z@yOZhO9L%I_^o28Kb8+BI{soj6RS!w*!~eo3A!@K@#U00B`nlvY_D)Bb;0nsObUF| zA()O75j<9D#G>8MiMDuJWZI-FZm+&6@#1do4`*|JVV7QN}VEqSv ziF6$i2Q9A-rBo_JK{#3!&_9P3_KPGwMUP5$^$)O-AsVJ<gvMH40)n0i^;RbQ0|evvszEY!;AlfN$LdPHYNK)Eo;P z1E&I@U3cp{{qo^uR#7s)zoL7 z;nagCJ{!NgdU}9D`U4N_aAKd$-@o$xyZbh6-E2aqtk z|6WWm&k3_Qbm3I|A?Qh*6y@%7xwX~qa)lHP~sVtb&9)rK4J@ z2owac3+NJ_BGheebcgK};}~M@)uqCuZhlSp?>sLOIca3T3O=rgg5KWJs0y84SE#(q zHu4YJ>mD}gu?1}#yXtonYN?+h=!LmWkv*|*$6u5q4T_&NgWQ1p!$-jHS6p0zb5D4uel)ZjuawRyr#8kBCJT`tUcq`nSllS*$WE%|F!AtD6KkM{cl^syWiTOtZk^Sw$C$+ zdB&Ug2GBXaJr?|TQJetDqJwpH6D^S% z+PX$s0?GP7>LA-*5%m=;gRY2pxDq-ba^`3ESJXEKahX`Nx+d2@pbnqqWHB)Eo@w4R zF%*1ligDK#!LkACm{}+#o+xo_jC{Wp7Y_$0JL*lcm+Gb4lLD9=-n85OR=N57T>=3B z*Vb*xnNgZ1aqy*2ac4C3)k-h4*5^5wf5gL!KoD0uF$+!!fkW!ISkwy>@DJ7*# zT0lxfVkj-b=o~z#2-4jtC?zE|x;v$t(cLh%QTra=_x-N#zi-#I?O|NIw*BJ#&biMy z_l>H9Ue&yN8a!(cw<6^KdT1k`oZFCrQsC7AP=hABLt>bj{5^yY_);jd={bPiR zt^XLs>P4l#FXS_Pnj-isc{PKZ_gUnJ>^Y4(s+0jm#oR%codr6Dsk|cbr0x02(wEsF zZk-YFMQt*rk#Fgs=~pK;sbv0lbHjDY{;zerFT{brr7!nX+L0nTeh7~iV$9IPF|V#~ zmZX0iaz7sn1#()ExT;oC022qhOTnaPCrBc@eJ3b-`wsT7nm*kPGgEY0+=k_Ti z><$wD%$&MUe~&0l%vDkAe(Ip$t=qu^itpbON_rz#n4l6?7A-v7l&|TJeR@%lvfBUQ z$~}2l;Vd_6&NZj+(!0Ur%(sHGBGco8=9lCSmW@Vr1=X`n(bM!&71B|479WO}KuF<5 zmug>VC9s%twEbsDEG^U84Tiv8YYGZ{l)5}@b3z|3;ecvyaY{@+W2ZX~T3W-LJz1@- za-%5L2O9|PXxEz`pxvo~qd_ZfH1h!MV6k!+L%Km!$6+)U`opjyJ%!PL*V}c#R5^o} zzBrGSYrf}uwzz=Jsc+4S41r;AL^(RCPsbIw*7U}NoA+#o-g3&UnA=f;>)#4e-961MQfm+)hcyNm7?J6w~I$SrAd91{xA zNFOCV*eQZ9M1yMS79h3Q>c&P02j9*!0Y7X*en$OS&u{P*j;oX65L8c0ZoJ55U;lka zfuSaYCl}{*I?a-wPB91x!2gn2F@pU>?xaM*s`_<~zvfpR-cU8M=Dc(f$ugsGhLJRv z1pEjQ9Brqi&B4Ms-LP33D{BOOBjBUJq__%=#Hmx|YAZov=&t2s*ftL)G%%ZnG#Qb% zG4{`V4L>!C;6^Zs_gW+vw^(KHgr9pDXi?a{<^9l^CcQD9kdC+L4M&j3bo|Z!*Bgqy zlD_y^zxb8J+|u&#E#0?zPNo1!o!e&%^QA}rEaZ5%Zu9EX$~_$$d+S`b{SqjkmBA~Z zHJyzo^=L?U<3NDaG*Nt@luq3Yhc)@ZwDbiVGHxv_J}zN5Yu2wNHevVEmL*%N3CqID z2=CItG>HLKc5!*x`5l~am@msxSKKyw;6o28pFV$~FHu$mFEJe#lnl;YUjB#yyZ(+h zvm=7R6%~6kz(YHTjA;NeE=x0ZH7N=bxAd8-dT41yjdfhK-qE~5dV_>b+K?e`66sN| zdH$7~!M4r5Tj4zKKXq(pK0ImIfuvIG?!N13m~_APhtIV%4UW-y$oqvF(dykC_}9Mp z)SoQHR*gPVq=(srPsWigbQPf7jjjM&^5{|!wtq$!G1!U20l&&{=>ghfFluxU-lpmKfD2hnbG zWru>5uGZ*-98oWGfiGUtJ;hkzy2)Jlf)^JzfWXl-nb6DGuzbEX?)vc(edGkP*)L}p ztXS;*DPiaT%$ghn^=af?>RElg=h|1e0}WAZ)n(DJ&@sM~GfU;Yz(KR-Jy&CN9>(^8 zf)8>3{!z-p?P54cOL2H(064<-)m+mOyfkr|AeqGIvj;w{(@?ko8j`f+wy4i$p9_Sg zi_$y|W*)HM;A&GyV!|IvYc-_7&Zd|1 zj*FzFZq=WU=!EevcAg(G%(_>+%t0KuPwffgeZkR4NU5E9KWAfemr=t1+wY4buX^hO zRdsbC-wd*hp}ugtlp~LZUvxB z_0K>HW88Xw(rEFTH#Xn__q$UXR-!X}W&r_#dW{5oNt{PsYw*0O%Eze`ntl77*Q8uH zFSUH1)b9r!v!+UTMiYcct!#7gtyCqs%TcmjCP*ii1;OD|4%`Bq(vONHf;k3dpw8)7OWek*BaRVkU;!B(w|;bu$2g7dz*(EVvQ$ zzSq*W@L;vhy9sKO8PAs1(%UB&!MyT}P}sUVUEHv8tNI7}=*l075hRN_O7VTZ^C0`2 zhOHoC>rJ)CYhgM!L0E1Cz?eK3{*ft8$YjJwIMt2r*Oy7^%mq3e=FHAKu1~BtQ3a?r z`M;>*wqMdo{{@Uq+*fc*SgMid)`mu6`yW2Zjv6X<&}v5uTQxs;{L<_6k&qB_)xuR) z58vFaSLW|*9?F9_&$l;%aUBfKK0kY}3FZ##2EyAuD9HoM$gvmZQ_9-YY)k4s=gJDB zXxN5^V@tK86Ic}B1a?Q@fHLca>ZI{tI~6Z3DD~Ok-#8q~#*vhi^kGSu|Fjo+gx0jg zeeOL-ZvtETe(2)aQ><7Lbarlj)WU`8Et#}a@k-rjI+^^{WnFT_gRxJ~RuUd<=<4?W z{D-GO1E`+2slPZ28Ci1hm`P6K;pL47TP4N7)`dP4`e@}h??Re?LRiKX*W)gxkaaM_ z0#5v=Fpv6*gcGQ+r7>XmWHBjRXDGoqsL}pytgB()uOG<=YJe8qpzqG34)16KgG0xk zSHZB)thF8&dST_qWo;+oxpi;+TUSq<477BC?_Jc*dldp+)?##SV_FACtoOgL%WBD- zv&j*Q<%){FF=619pVo#+P}GqKnx}^y+p=4>PYNt{mc?}6eMxTbM`AbRr>1@mmgaSL zJCp-hDbPp-=BUK;8HVRzMBg_)A^>5Qk{DWi!|iktm)A~W!S zlZGMsU~bOnhHUKUu#K#5LKzLRL|JHP+%qsR02>&M+2vYU%Mlw9jI!W@-xM}|F8WQW z+-$f`<{Qj?$O->&`3|38@&wx)x|Vm|%i-Eu&cGo$ngF{P=e>5+yL#Cz$bF&y%p;K_ z9mc<1W)}y4!e;LsRAScS4tpX8G#bwAw0|Wy0QJGiggr6-+2`#@*(Vbwnh3tdm;MB zym_+FsMVS8@|*WMj5>3G=8#d+sWLct#Yn=Dr7xa0+j>PYm6!U9A6Y`*7nWOX0TI6> z-Bi$N3k?>vLtTAJ;Xg>I0CwesJ_We_ykAuxTth*D00*D&u5zM3T{*(I7D?RaCW|mC zKEEdOJUfC2csHBkXiQwtjMa%dd}S0hp7J@gMpq7-xUY=sq}c&^#Nz()%|ZAu>=ChPyC{=sq4q$j@l@48mX;t)9R44C-YK<-9sSQL@L z+X%I_50EQPQ=;z;l->q}_$YndVS9ElPr;86>jWj7DX+;7=k8$r{;fzlH_mR~tvco9k#mJNt zHG6wryEy3AvKJ!Stx&L44zxWB+k3Pf)u0O`aUEkY=Yfp-JYA7)#e@}#;bYVUZH~iq z&;B>1o2jWIWBk2P!VelGzq}H)hl&{91;f|;J58=f1acAUXJVGI&?~~`yWE&?x_m33 ziHz|xro{K?Ozddi5KtnPZSuW}N%#8^kC|BW29M)1&@F{s9(Aeg?cI7mIi8vRA_8vo zTQVIee{pd>YfjP&b^}o|PX9LLKGI+pX&7f-A~$S|F~MhijJO&N{0sM@!?}4bfhe~c zzPqzf;(a(+Rb7}YY0I-V@Yp%S+Bo&lep@-AxGIxi#5$5xccE*ghm_DT*U;ve)`E_ zRC{+y!L=Xo;QrwO0Q7GCWBbrBFrnO7r>j3|GnQ8h0~OWgmm`2nvlPIW5j5#2lXNK` zu}4o}gQ=o-xt=aIpcZ26q8!qWqm6$S3WYur3ZTfQ6uWPNSlxVUK&5E55BWtMtoMAKEscsPvT^$@Ipe_p5Y_fgL+tw-H*fLQsAsWatK) z{<=7Xwd_O9(X9&Q|B$|2U6}Wyqh{WdxHSTLhr(BaEHCMKkT>%jv5wW&a>TpC;b-Zv z;;ol|8*#i*`vZa4bLyZy%6wO8G9@$gVF08@j0n#|_knR^`JaL}yKdponRYa%PV2E9 z?6aLwwm$-ZoeYFBN+$Cf*E%c_P*B9y zOiayvUN~^|MXA@ltQ;Z3irJT;aZqbqVZD_6mwX(v?v;j~r32JF@mM59zOf0M_oF}u9$$$BzqrBw7FpOU5mycac`WIK2?pVgSI%j%_Pa>0Sh|fu|Sj2R{q%Bjavt% zbr!k9e{4&~avV%~SqaTg)&aLb3z((>8~#Zd%}mLi8Uy=J61a2s#QQ{;%(25Ur@&5n zP=U&^w}oR?=WN073)VHdO=MB1CK`1Al{wWD4s<&*Dn96y?~M5~65XTK0AsA(sm5<# zz6F5(`&(b;{Xm%*KBDAnytx`%YP&s3P7%1c&jo4go(4yqntcq?y)BR|0o=k5vK7Ok z!Di-Q%u5*BAqiAqEm`SOIk^Bhoy8n4uB!Wb9W1R_>F;fGJ$s2dn>BRkT-gA3fw$*G zp@B0lD7DsE`k`%e`VTd=iG%DPxDCBI$IMWp*W}lmQ$np8q)CBfOuVqq1r1dDwvvR2 z_G3f|pe5UM0d|xhJD`VOpT38#NG0lG?Lenf+3$rJ^e)P8WP}ok&GAZ`s(1CSQjiZd1AIe>*Q*>r3dfZb)nALO6J(V$DBJ zAl*C3EWzkUnxXN!GY%JW>RP&g(FuZPpCD})MLK!8G0!qq1*m$peH(DuE!v`cGe6TA zypL|b>+$piDC%<`+8y4#W6>;I;IXo)V z8;1L^klX&W_Bf48PKVlI+!O!sLa6F~0^6%b64Hag3VeyOT1{KBqK;Sh_@Hi=LR<-@ zW@lHa1iJ(QjgNMNmWaxo{a!SCnRxzXnZpk@xk!td1=1wz;AJk0u!o;hx?%=mGX;?Z zPcs#aS!(8a?<+*k|K^hPI+b}UTvq2IKdKw=dtKr;wDZ>oHQ{~VPZ|O=a2FK*`c?f1 zUa9roz408Gk@{-sP&o9ypCg@7!Fms}xV7|D`H zgEm%GjscL%t~M?7rESjRY)>CdZZwYN?7Eu|h(zjQczqAZX|6-2cS{`=0Fe-s=c6rs zI!R6T{O|}i!~jJ+)Y^yasX9_@3F+}#T}Ds=aQ5+q`l9H{Jg`p37slO}2)+azz^iOL zV<6s5C{N_ySndsV=*oP6!G^T9jG?zZrFvOOQ`6q7T{f1!kF;A-Pauy7`p!KI8J@`fZ?XP5kQ!yP+o2v)VzUVu65z; zx{Xvq_1<^RZcy6?*s}v8KC8>cdpHkaf)VBE-rpO@V-LN3aX{|50o)0EvubQQHF{ys zJwQ#f5&e;Xii5Dc6rYH6V_e^49jL@!l=ff)y#ZKPWBo$IMSej>K|#zCU$dmQn{#1( zYI=hggVL4&?X|jLp?B0!$&&_OV~@kMhfN|(UW-Z#AsiYm zyoR-R1KSw)U4g8eoPfvjw_iGB#@5$MeA>~7j!RN$Ib7PEYYdCZ9_(Cm5dw=moO8=9 z$2V{@Ce1E1p5jJXuVbZj)=_oj#;r=eI|v>rGA~8(1rv?XFdj4YuJSbVbii08GsNmlyNLepOtx<1YL5^kG0g2zu@)n|W*b@by+n=^NJdTg;W z`qy5+RIS3iM?@CaWU@B)L<5t675GbMd1<{Q9yZ;LP@FhI3WIj}UHSH7_ zf=wqtG_Sar)II2a4L6rS%xVANY0r-O`(!!=ifSX9U9RapE&S`=EfK`{pPDHg_c_PF zQw(g(_spO)LPw^2){y`Yz2|o6CXRO~MnCnPd2~lX@4l|OeBQGzG1u0$qf89!wEoh` zD>pahA@{Ep>L#>8-Fa&mk#Reftf6hARX7DOQbIx>{HyDG3=c*)s3(S_kH@g;xrgun z(zH(zx%F6Y6ywa(J}}eL=9V~a8^2R-h+L@O88qx0Vvyz)0h+;>U<@n*#Wmuk?f?Pv z(MsD9O7gw1S0o;*W$RTj?I%n+GAp8u384pVkAF6iyZgqzoKzh{qMCrKyMU(Tk=j|@ zt|BSA68xDKqh_xd-945sfBIMy@ySf?ewJ_*BI*0e@xF0DCgDJKKC?7awhDP1!=ON? z5ogal%=$q%P^+7(fbKY^Xlv^i+p+qauVj@Lh?MDs*dBN|?@|ymBZd&YWDI9ua37qq zkAnDFt&y3wd<6tPt~zA#0DV1M!IOp&;yeuMqfe*nMycLhaoE>-YM7{@kh#)V`GrMA zYyY~KR>lO!$_M3&{>ba-(MvHE*NO>pQY0(788hhJBYH4jmra28)K|KJw?1-Md)ZZt z#AUCS52VtsINyaUS%yHGa=Z`=c@6GgmWplN{rRtR~B3nVVA=oGA=_9b;Y zpK-njceCmClBc8k&~$y^y#qo}%Wh(6w{%G#-*T%<0~%4h)W$GJZ7TA;AP=^Bo>qpi zSE<-|Vrz-|TTb!U=9CU94##}9R9uU84cFJlONgVfn5HcA0}T_8t-b29%iO}}pJezv z-)5NXioWSw_X(VJ0UUDwz%oRp#4*1cW}j|OdPJrrj`$>xYGVisEC>b)(q?6^&i7dRS( z*udxf22g}nZ?O+bd5~**iTS34iP~`!{I%vr96*&`bIH6v2GU@sj)Y)<6g%R0Px}Fr zY5x=*n_#zFEI(D6|2~2Wdt&OivCHjGo>!pim7GFK2R{|}KAl!A1IGYt5qj(eL3B#B zhLQ3cav{WuB(X&l|2&?nHUAu#gly~p8Hg-yVC*~V1uE9Z+YR)bNQCz}?U1+{QdZTM zf`j{aW&!+K*am7a3vDXIw>SULr$a!d)|DG$54^g-yHz^<%EG|F)2+|~K3MJkngz8| zQf{TD=_c%(8*_Vc>aST?y!+l9jXtxVA@SV!c&vEZ<#_}kVJ1bF|8f1%|h zmi0Wino^zp&d<6;mGxlwe|-sF_ecq`DFtcBQ~=bc#e~_U(uk2_!dX@NjiwGfS~APH z%*_hq`E2w`c+JR^tdDt<$$XDCtPtUzs?HYp-X$})4puU=cJ9&^K&qqN0O3 z#KR0E;@cRE3V$7m31?wW*G=E%OH4^#~_f^UdQ@xRVDeQlV9P9jkR`}y?)=PRzrRd zO>fhYC#xcg8IwO(=}h-Yow&h|epkVj^WavwR6Hz2?O>sSEfE5pH(3Td$r6=fjE_yoH7@^H`4fa~Mkv7Ho1 z!FN9&Y<}qibEwZFs--tYQl;e>^C#c^{b1NXY2>NlAlN^u-YCxR42^V;WC61kjckbj zHiJF1ddBl`Eu`yi!j{{=EWx4D_KQ=qeNycl)kd=p`08xye{R6?>rTq`d*QJ+uV??i z*Z=$9|LFBrZ>=uh4^K*g6)G(F67oZOx z=8B?V&h@bUZ{zh&Lqa@W^JM84?|>qtq$ve;yq`!*dk~ccVxi&h^xjiBW`HC}BvY*> zmQr06to_e_RuGH6^1bwJiVG5=FmA*>?E=L=tJ<(k^m#8i5toy4Rr_;owh_|S=QYZ% zm*&q;l3(z14QNCR-YeK)sAjlrbFW1+H-iiJUPj&u6L#83k=|B~^Xbz_91uM_i0on_ z1Frg{fz`a0|65A{C>35FSITxB;}NY({&g@eK;?3ZePTz)c^7}^ENA+jk+3(dy3o9& zE(H)gea0!`EW)GV{GM$QKOo%p^e6Z9-?NJA(vDVpxLNruh1{Zx80aUdYrXNuQNT5> z|NVr#7p9iMhZalW8LvZpc;4&o<0FY>VF2 zwY^Rj%r|Z*xhaKrKbThoKfohht6RJ_wdweHnNd7MM5^|a)fo@9#-oI-{HZEm#!z*n zZ%1qIEh3=f+#NMwJ#2fL5-+fX=80AdA%Hdib3FETmm0HPKtQ~V(t{|A3qHMTbj^2r znKpIz_tS!$$G_VTPL{|9P-BzXPgR3ajb`MWH)V4mZW?%getwT{$=SXppby#*K_+F8 z8oldWu);wrd9qjWg#$;UO|okAVXQ+g>8BlCLg3UzXGg1NzzIZO9K^ptDk~Q<{Q=Z5 zMHvs}Lb;V@JhuVMYzP>F8&ZE>ske4opg>PY)}+K0GrtP*qz{ot2!}|GRi*!BgRsI9!pS8%Z&6{k}CRZ9-8PU+u*&D9#V;eRUyIS?`I8c&=sNrR)4 zgQWz63~1vF@r@_~x~?^SU4m+hOX{_nEv1FwOQM5|>2G9A%1Egy|L|0j{Y{a_U@d|@ z?odxp6b^wE^5eyVd|3R0)N!tQ5L)f9x%wc$;xD5WYq~zW)V$`h?DFyrunRV>$dVNM z5A6^<{-^t(2@yd_>2}9?s>&|K0~Ateqr4}JA)KnTrS>^L{QwH{)T5U}801=SmKt>^ zol?Sx_Wo6m=Hj%~P#)TH!gQ$KGPHlNbhL-zQer21@ALBYOoYrG;`{1t7Sw2=FOYE@ zV(TJALJG8zMuwK);yXZX5(%bUDZmj(023`m2oJ8H{?F7P(3>N6jod(Ne0;Q)H!;7L<8{`z5jATMlcJJTe0`-r zQX9a0I7{Jm62C<+M+WS;Cy5+UNc-8iUWnAoQV15$aPP}M+UOy#GsCXzFDz`gTU>up z8c7e3u8l`~m8d57buLl4Ix;zf4bk1Dq&iNcot1KRlX+HWXpkujW;SCyeB#RYe#} zOg))nxB__p>?XM$ws^ZqB|pc+17eK6RKZMcLTg5eaU>HR7hB@#%N~12hnMqfcGgPA zuMhF3A5uV}YfpWfB7|%k3I8GPD-G^tllVe*tlYUA!*w3{}1d!6PgWaU0%^`e^ zkJ6d?gXO6gXA{C#>|UCcFA5w~%QJ!rU=IZX2z^6Z1_Yi4hK}V`?gtBZ{C-WoViRwq z5t^#?K=qgDtbEh>8Q~bl2k2UU{VWJU5J9^4=Bom17&zHDK0Tq)z@5rNDHi^_1)iT} zkS1S{^>N9m#^V~Z!O6`XJDRI$b-Fnm8y9!edk&7g{V9@=jPY)yE(wS-c#*uT@GNS1 zdSejrBEg4`+hh4oSLaCo^~yW9kB928`QzD}lE*J;@JB>}`d=c5N40S$f&1uRXCBC^ zR~=D+7%#|;Cm)uc!nX8}d8YQW2&$gV2#XfX4?+3xVI{W3{+2CxRf*Gz7@ZC*whMGu zDSLQ7Q#!)H&VTtz9G}fXSN@bV;+b}Zr>Xd8{t^QzfI>zqd}@DddF7#FJr&*dW;#If zH%)I6YB_-U)I`%?h60amj4PP97)Sdi4;4&#d8a5>WTZk_sus3Gjj=6hh!3L^!IPzF zI-9W-{cA>ANz+gbUM}5@J-n$TT;b3#EuWr}L`f)K?Y>C&t@W4vMtEh3+MkcnM4>Im zOqDt}SD$dt);cIz)`yi94Z+3lR~$-&70dvcFeY)D%dN}9pjr@v4m&1oImiYZyO)t( zNzXsvF-8P}j+u_Wz7m*@Gl4#z&4`chjC?H5tU|d!i?O%EsQANl-oJl#e!9hqw2@?O z^u6+Oa&p>4G)aR;Rol%glBjz(GDPV=XiDYBFpLsYiVf?G#q{N z&Jc|+oNB5+cr0w;!>ptSjK-RU>DTw2eYP8RbH$kGl_k4VH+B7>V12Y;`$*?b$&$6J zD9Cdy*5*yRQjfcW`_jZa6?out-^6P6=iU-`%{8r0nkU4!nUvZmCS(3kC)19S@!&7~ zjQxoT-t{7?X93C@6`4VDD2AW|P-%RXlETepW< zI{MG#W)13KJhPn#i?e3A_?h|1+`ODNXFiVet~yL%B4-5Dsn|bTf0$IQFT<6=y2h&m zAOj${^RN`$kfxlf_a};t=}f4&z4fm$)hf~nCW%&t6F6@H zCKGa_j~J<1lrRo^>JCze2@nqR7@qKmuFLA9tUkDRUj!#=ey~9A&&P0IjBxkO=7mc` zQc5ZKf5$qKX+MrWjrqa*sw;xY3baYU>%`|@%F--g9-HLS1$|zN6Hayuc0I(YtLXf^ zmg{+O+x8)QF@3iorxD3M6@%}AGBReyjzTqQ^Eh{RVhCMj@gwSKN;&az)mL7HwOde+ zozo_yZ641@(;m*u%s7yw#zvo>o|eLPKq7}zc-FOWh!F=xA}0dpMjkFh zFVEls9%8$QCcxu*f4;75G=^RMBPh06H2<9)vu73|e)YadAI{W=osgcm=cH_7_I@dN z=Jnr$q3qkW^$5|~_*nbr!qU~dv7RF0#d!UkN-6;`6VPH}+EI*FdOe@keK5F)+K*yT zURcV;{<-8I)wlTmYZqbO0K~#~xU2u-7(X4ourhbvAF6ml=t@USo{p;XY_i&H{z)?M zmE)X!wRR^*>Kr8cxtUA=d2`_-5HV>ig47>xdCV6n75Sh`6fl7Qo4}(lw>YZ0lEldg zYfN8`j<#IEZ{pvVcaDfDQ8l{ssJYm$YlB>mkB{ea1ACRgWc2xhrpsluz~UeM5=-!; z_%Iw^Imik^-qC2s6Oi&%O|q>4-1DMtyYIkd@lc9JKH%<$jlndMuzbkalT4MMXKeSr zIg{K4={Rl)y!pwkYv{8xCQ)4TOU&1K^VsL-MVAC36ejQS?%Y2vU76EjS5ppu7^+Vt zZ;pZ*7yt&;h3_jrc^Vtf+k#V)awM>5m1}URJ87yvA#9#=;xxC^6~h=86BcX&_*7#{$F+z@!_k`sf?r{&(cgq=46{wRs+WacylfNFo*0eN0up zHk&vseA^XV6`}o>f$4pqXtLYE!a%0%H#8X8J>3Tn-5PI{z45Z9r?FwR@9{VLS8z`z zs3ew-4u$&YfMR_uY1L)5({$ce1YDq6zXb(T_2d+it#%_!`Ul9;Yj=6Da@Eksz_Di6 z+B#7}6xeE7#=i)9S_f;ZyTjkZ%I43HF$zo>$FwUF3@i0Z4FP{yV+o)-W`pEG^&~a> zwfPZ*m)8(G1mk5sCZ8h%Z?Px$qco$a(=DXP32vlsm`|XshqKH#@_2f`=zpj3ucwRoNW?kW=(x4Wp03abfvtvjl!o5hi6|c=g z8bN+Z^GGIua7|Vf@5?&yF}y>KxzDfcP5zYlc`k z(T)d^|yom>_}N-*^COTfzXgoWZ1S8X=7Fs7_MnYzON`W zrFuAIGn$742n0sDGzeSy=X6OuINT2jGs}2oEQ}AGQ@5(35>_ld5ZoiF!es)fxA16F zQ2OOwN(4K>e+(MRle41D=wG@;QwfQ+bVMjBx3(c zXebj)OY5x8{@_J`ak1CRh~?zf%?b*Q2wIIx0H`;l4nq>KTZ0)!($Ky*#FPhf#8>;e zYMavp=R1R9=MCRgVxeh}1r#|HL(P8-rw-g`Sc7z%X-W?cg#Y_s5az_sQcTt{mq!1;i?N)`(!vZ+w9XdD$=HaDjt9vP9Gxkyj@jbG?RP5DJ)D zsUfLZ{CWaZnl3fv7ZlvS)(gBY_=wFf2&UBzZ6NxzIoZTu^{Z^i8dM zj>gooU>(!ujS!1%7L{c}0DO=91B@};q2}BK5-zZ4TD}(S3o`JQ%Nzi8^0oH+` zGOiN$)wjr7AhG{r|H#$ClgsNw2@Yosjrekn_!_BM@t;<~L2K}1LW6!3`t$FF1gEk}`x@3A| zIIZhkbOtys&nG7OTWqM z%x8Z58hr23dsWzJU7H=BsKNDB)ud9&jPHDDP42A$Z=~6R@>{z+UpUJmaQ|x(v{6NI z@8qt-WmL9O1mRVYQM>|XR1}8X`{UVjW&-c11LTr7a&p+U3=R9v_GUq-F0-nt%DCMd zJd4IACJ3{Z=tS)Amo%IucMlA(iHN}E!v^0NhQWt6+7M#h;gcI}J10vgm_y7J`s%vb z1;g=PsVkI7Z9n4kweoQ^l`ISLTfh6Qr~{7=$p`J*(zQ+@+CHsHCOO{(6fFp|`e*w9 z4TraZEt?6qn#m=n(iG!cPNh0JGaIH%&|??Frs=iEJRNfHgTL1*@^KhHa}6^I zPdoik`Rtciq4}?A75AAQ<w}xO2G$lAlL_5yuDf zRl}?ZOL#?v%S(ugN)U_qM}0j#$7u^7fdu4w-kYV?;pmr^LQSM{WLzRTY^FsIu-VtA zDg)V)c?C=g6h=;+K=OU}>17dwdOc<#4x_j@^Gsdj-=P0aF5A~vubLrO!>VgYbtumJ zp5{rBhL*LMjpIc%HP2Hd;<&X4SRLgIM5aRLiWULeT%#ftF44d(D|1Up^bUmYcU{DE5i3`yyWG}>(C(klOCh}v z&wPr*Kpfpb!NTH!-y`AA){7;qSIQLv{N;?HxxQB2w$01Al3$wY;vx6Zb>}aj|Cq=p z@5jE{R?-b{n8*@&#BWXzK+(6DklCvKpk{ z+eyF1)Vl8At=DE|`hg8`&EEVhyyDi1I*&UJP%BWO(fx_!gaY!HyKY5_9=5u@8%QvE zJo1q6XfT0EF_}P55v`{-j3Nq;a3cbjLf8hLXr+;=pUlGt;7<$y(J2Pf_R%=s@;<6x zh~2j~Zhb$zQ}W}_wM**G=RbfY_^;7Bw}KbAKXyG3pYleUfPuw>=bIoz6d_7b%8>}o zG#0GmdjAI+m7GlL!NBD$&6i@xzw`$oZDMQnFP8saqZGvhI;*=E$7llr?~=x&bx3R% zHzn@m6dx)7{J&%XTeR}CE1vzebQHzms8bgq%LFv8a0xqqMfpc<;yA@M!m+cIq+YKq z03%ScS~2(c3#C8G$lKkNh6b4~ebOs4-MYq9Li`?(P=2K}_Mg3a^Kb`KPZxprhS299 zvbO26tX6I1Vl-pn&#O#Q2Z#hxoRwnBTvArLV2Kt0oW`5pXI%Xm#e7`afnaM{oSQV$ zC3?W|PJCge*!&K^+Xk%2B>weN`GhCT11t<2eya#7etaQ@XFbg;2p(8zv8()8IgK|? zbXlb3Skm=vXh$K;?AF|qCmXY`#kb1W4IzQve)t8N)^^sW$zgYMg(3szH;;+dOm{?G zDtG|W{ZOqWv|rhF75(STw%bpJH+R(C3(uEsu$B&?NuxH92@SV-y#W`&ClAjAl0`U|&z*#enhOh7v5U;!{fic-N9`i%H(|YKICVye3K@Oi$(C>FJH{S-TaEYq%Xur%LZu zkYJ~Ej1xW2f9w^Cc65E!o34*C`+03g$B}aX;p_M1-Wwd)3q@|RC}yq{f2Xjk5q~}L ztsk$FHEmjd@+33RR>lw8`&1YWj%t0UN?I5(KJjUzvi(xSprJXI0FcLAE9g=j7TL^#bP!=;OJ}OOGg&4-0Y*0*YN=SSKTml6xOAvQxrlhM-y|9&;l1n#C^CXc?8 zm#;Z1XiaeFh*O-8z|=zd5&y2fVM3e5^a&V()p5SYm1E;mAI#Ue(^)o#Wl1L=y!l1JnD~&MBhvDbwZ8hRb<+siREq8vUP%|00*wg8 zop15@3tGJH6{BME*cvsdi(LT=uwoETxd0;^Oho;fM)IIO3$D3pA=GH{-euxBlrt=R zrB7flMqz+DW6nW!@TaE0$!$Ks$Yo;%LfcRjqzIMah#0guTCtO_P${3D-f`8$`bQtn z`2F0ooAX^WSPl}ATKYa4!pT`eO8;$tw+_~D8D7(H{wVQDc%BBaO*`A;PD9OhB%_G^ z+|yrCggg%{z={1b7*B3=^=kdwj*ea?&qrQy==MOhO`|t2sMbmjx!MNwZ9a|owu%h6 zV+9dj_T0R;jiBcD+=7jFaOPKUtTa44=(|8iz%I6~eomsR% z9{H&3TqB<~gdMUN0G10eN7O=hK7Hn>lDw#?+vkW0%s}SM)E`_1=?td+J#3=Bn%%Th zXNN;P<2Osz%bNgzDSj?c+5|g}`XKM?omIRWbY~y4a{%l&Y~*Lu*;z#Ot|K>&ySIn*a3Vrq{*}YZh@QPszdssO}I&_A$LQ`pC%Z74O zTojZr|BQ$AS(?sWVwEEya_7B{&x4pGxBVm8h%IytGn#k?DndW)WUrjxOQaMv=Dm|_ zATp}y#dtH@UNjw$wnx!tY1~8+0lMTmm*Z3>DHeDuk@#)t)ju}v& zZa#Xo_q5LdQ$vx%l8E?)JlcjZ_Rdj6lYe4+0;8*T_gIWWw?@+WGmhiR&`^BY9AilF zo1CIV&Zm-OHqGiMb{{`}6ePPm1_D<}tBU`;^gstdu;*Q~VGE2@R56Vz5dvaMVjon^ zfpGY>WD<7%fs=s%-hx0B=hGaF@QW8OqU&y7C&qiX{hiCWJl(&Y4ew}g|8+3JIxq<0 znGa6|A_P}{;vf2JOj6mK2%O)1+JA3?Igf?Fx8K~hzJxw{!BS9v0-B#u1k&N-xu4}= zDyOjBjJa<&`~Pmhi+@qm#cDKPxm>w9e~UYMsyd3@cA$QZYmG`jS*2b@e`+m82(BHi ze9^I*TmVdcE>1&;OJCJ3f+nP+Q#~cI@?fp+{}vO7I$P=@20yNSRSWJQNVrdz1%9uQ z&e{U%cJMw^+2L@&MwN|Je|?T`c@e=h!aND`kBtT6&SZ$;{4tY(PyU?J&M!CD`D5;^ z+mkbqPFJzt*h*%_C%Aj!vp66*Jr>I+^hon+Oi=n@(w@0aIjl6j?l-mkqPN@TCM za@^NTpgH$UJnxyz5Lgaq{%%}S0!T+GP*q1-g=ESjS-% zTN!h%7i2i?L;xful4=)Y0J#HeRs)2u<#BIP;9#E2XM5IM;w7q}@6}Re0zR=H(0J~q z9TAleO}$Q~5P7P&S@OqAwwtcO1p9@lSoQn}qL2Lg4*8ep?)ha{j&uh0${6t(>u8S+ zCIG)P7}T0Q`6o5Lir3YE1A9|?KR27%I+;${ok{Us#gFPJda;S83-95;7oIxRyYu1c z%C8BHmQfcgf0KV;%y)$S{F4r?1|=b(uQfS3K4o|09$yxg1a*b$M#sl1f}rG7d9Hhy zTY|C+we%`0bF?dkATn&S37bz)cs>>5a^n&6M{sPIxF*$O0>%SZ z6>f!Pa-;$|jnmgZBPsx3TuE)_os7VO%)1j(hc7D&ZtV1#D(gQ)0E*GZj@F-MVasvw zg{9GvtNQBGbSdwvkod&AXi)2*tE)vxR(($^)0-XUG%Sewrp(L`uIaa7<)a=t(4W<^ z(z1q%TyuCXED*wkugNGbr>Ge4m>ss%dg!SMI?RH*s}qpR6kvNBS9z!>o;u4P;;(*{ z{f^rgHJ@0_Ra$ z6zGbnS%3cAZV%Ua^Cq%_{#SUvyZ$Jp%4Ubs7(J;35f5!-cl|4!rj1R$mt8F(e7htP z5QlKqOs0brzKVkU27dj=ZCzqtLi6K6xg44z(Zq zLt9g9*}toelZLbUQi@PK?XH^`hAr1geTN(sWVrFVnhjriW%m2x1MBBk|G1N@3_Q_B=TV8pn}$W z!+fe;DPx51-uO9xgPR3Gu9 zh!(iquBW+KX8|H7KvRvLS90Hh2>x)@`tyh4#O~Mn>BmnxH-?DpP9-uQ{| zj1K{IG6(2a+xcdQSa|9b(s@p<^&?RzDU1F>(z;o$LA%NrO^k+%C>dwH%fKs%2A1xpxlG&QOlN{Z zoQ6O|8U8`reRbio%#5;SVZMi= zZjs#17f8&u0%NJ3i>#$UYRz~%E|Ez$xxOnYK^xpEWLnepEn94mfe(w@G2R_jqL}H2 zDSOd-MX}2r;OiEmD3X$r zM`nvvU!^aFp3+PGceV9xxGz~m}&^8V|Fx;%UVFLUozLwbo?7VXl}-BO@-$ zS6ySe^R>m}VzUKy%UjZPSM~Bpp;1Bpah(Og65u*sioAv}vTSZ*16|!>5;C&z$Vgn8 zQqf-D&fg?VmV6kNeDa+>^Pk-a^G?bzBqv9%b^I8kM@_F04FTd<%hv^9f#}PbHL2N| zsqWyp>K}s=20qaz2rB>05Ni~2K~F-Kw72Z*GcUY2h{5}~74kPEQ~i=~dAQ&pbFrNsF( z>sDc(_~=Fk+-)RGJ86f3$0SH~tOlaW$yjmDhhpM~8v!hvdv4X>o1a#<7YEZB9@ z#e&PXZ-PH_{p5HMEs!S$iHm9SDuGHBkUQGX@gEZ8cJ=yk6<`f_YaAOH#j$QjR-#Of zT2}9=o^yrHemM|oxslnDWL_likT@8Qo%b3-h&A0_{7yBbg9^345Eruz2@Y`hQMeXU zVYw*a+g~byIHU^m`y?!__v8+?P%oH~bOhQ@vs-0{+iRFHM8(_d@BsLSL_g}T{*m6q z+%g9JX>MjRHPkEnd8l+XTbLyiQ8H?~asTVPKQLkXhh0nERo#AX@9!un;)#OmKjo$E zcJmXZ&;Pn6=-+IzfQm%T`Rdl2A>tjsvtuSFFQ2e%*P>WtH`lK7uB;5AO z1+!glU}7TzZD0FDL6R^uGt5L&c%(ybv_V2@5Qj-=O98A|U%KFk9TAT21Zh!6w%r=Z zz8K3k>91FUUdA2((XOnnKmOQ;7mq>ae|Ca`*T{ zEz@z&T#K)$nhhu5qDnZ}SHQ7%5F&DHc?&$KgPc5QvJ~gSDfcnEZmwEls{M3(@Rx+A zU}U@=NM%SCToXCF<6rJrL=YEQ#U+w`G&4y;Uk z%7K`SMvjdm2j7E~7Z)OqHtb)635?UqMtx8L0rlFRlvI%yp#1zTAd&H^+X+KphQ|db z6rySJN!E~9AQ>Ju6Pf5IY!@1Q2qa+&bV`;C-7FVZ2g!v@rHVbYmx4Md--|ke_@<7fQ^55WaezZuRCXD-lQU#~Ox@aJV4s z4bR`MeMHaWih6M9r*=ObppWV0vAGAm)+D;aKhp($y?*SiHk;y<82D<8#Xa@9=;Nmm zKJC%?`!Iu&aR){Jc-d0(5EkiA0r=kCmib`_uF1>T$$4~$Aj*=CK(7P>bYWp>*}Wx^ zN3jA@cZ3kVCY?-VWZ#w*<>cgA>zP=&3R<6|!>J`YJF1Kn)V8uRX@QX|`+drSOs;d>zZq(2(cdbI zn6rG=bmWR}pDNxWzB^moNr@eW?X>LWc9~*s{-%Y#7cMS7AE4;J87v5NV0w#Y44xBS zPAk6pJbR9x*IfNUl|2P`&B~c%AI7t;Thyfs8dclT+bd)i(~y{kogn)Hhdb@k&b0s~ zbOM+2u?zk%`9xvzI6t~5Hv#xXAIB$1D=Y;r8{_jms7b3#cXl!@c&C*yJR{e>9#9us zgsX02zHvhe>Z3`t{TI7)D?yJ-Qz!zuWFlFZH7Z82wi1hqhk#ksHw&M4*OxyQ2ktCi z4|8w+3L&#<-$oLiEIkQC(E_9G`GnGRY@B8L$AS~N~RS1FnXb?Wb(m@lX~Qb zj)I2s)Qas;h!2~zzDOmC{|+#Ne0ub9Ho&r?EJnHiw@1o}gwu76(Bj-_!V6;28j%aQ{u3pRje4Td?Y*s{k&74DL5iF2-k0bdDgLKCP!F z%5-@yOyzSv4oL0+n&EHrK2egYE7e3k^M@>dD`4@O{yROw-+4J0hxWd?r|WfHU1?#V zk*c34hO@Kfxd+mMn%d7wTg4#18A{;xu|uml4xVwdGTHs1Zq<5-$_QR~_Xwna1X>+AIKQU7>a^1P^X|io;So+iVOb7G@c%08uF6}X0 z>{xGsdcN0#SVXP@HTU2@bvo$Natg2`W&<9KsM%vQN5r2y-dhj<%enz5J9^dcB{R7o z>y0dL|{SFXXuHs24JJHge0x%Hjcev3^OphgRb zC!v74y~D1I9O<0*;Q<&gMEve<48F7@5254jd*#!VL%!nPY-L++#D)N~C7^W?v$@Zc z&rlbwD9p({!xeQ`+-ZT_+f^)tI9D_)AO*X5a6%RD5ykdAQYYYG+P^lxKVB1UlqW2Y zWBzEvoP&-Q*#NCw5A7lg8jotQvL9LgOF6>-{;RWd#rz2&@S2%iUyT)USN7m=wW4|M zgmKMsu|obstR=v09T^w4I6lJeLN8KFPDA& zkN2%<2mbGk>9g`|Qn`$KF$2KjBE>WvZDB?uRbOBE-9bS_|9zK68=o}KNjbf(G5%zV z{RHk!@>Rnk0`1UB`0JK9H{kzA43$-{FR^o;)Jx-`$`U7?;NAH5mf?8l)W zaTkVu)x9~pijCOg~>*`nA9Jr1;1!DP+5yA01g^Ac5qe1tCm%tw!&{W zSsO(N)~^Hlq@pVr58;aHcA#4`n^1$|gJt`H(jcWz_kJ=Q-1{7Cw0-&f53*SN04amJ zGpa+tN9S_T;W?%Mlr4Mq`@RUZ@*TQS)l%is^ixsrttubyeN}-`Rl!SPzxWvi)-e|n zJr>trHda7_O*G5m%#w59ob8l5^Xq2etR4XL4x7^PtxfsR{vXF)oK<%oOf)G04nD7~ zJBSwao@IENmU&ijfsWS6PZ}Dp7kIwfDvth1$%xvwL+=Y#vC%#(Vh%^s(5}=zx~ZZg zd2^$WN&0Cvf|nP^d+9x^CPrf_7=#C;2a`BQ|0%xZ+^dt&2%dPwg->lwVqdo0`Rg-- zlzn)Z?1#oZ_YORtCZA(zcg7VPiZaNq3M;cFhBk?c#;1sH8)wy5i*h@@0PX@Q$)~3% zXks`gBilz0LPL2G)m4jWH}?jmAV)oN-!H4n)udNQ6!+|}oAnh|&opB!oHI#)ZEXJ< zx0$QZBd{HjG~7gHhTD&x&LO>%N>eQ?4)(VGR_3HjK|A=0eP4Su>VQ}q#W4ZgmuNO* z-}29fjQGvU0##8dOr7n*jwaX&dG-XY0%x|u*flqhJ7MDlcXw8LU*+D;hEJ%QMTHf= zl3|Ch#$uAL3VdDE@cI7)vWNSiO-kh~E7M0X;`H)rSem2p-@?~n@ozc9-f&8GrYdE; zqBqc+!hyDIBx}uu-_m%eyxG+sD9F2wTBRb63p$H|h)rK@pJPCX`R|V#=#pbCa-hV6 zt;t2%=RfEVYpF@`Sn(~|Dd5twO7c-q|;Ig(4X~s9&P_9bZc`d^zcXQ zSD_zi1RGjM3xx`x!rJ^6dyb+kSB_|Bb%xUQ=vxBsG~O0|s+I)PIPeBfx#F59J9x$rO6^udVDh8rfld90M!~ zDapflSI4BZrl$NOBi{*j1jFojFDZWJNf^yTl4T?-`_TjNE&L#kOoHsE%$>OUj;PPr zbT;m`%A-{KkcFIF+7szr7RV3KDr}2+7Omi65%ia5KXx*<%0S=CKeFkfmfRZuLiK*V za@g-vg`%FpevrQT$R5jACpAf(bT`ooT3&6W5mA@gaUdVYk0>(fzCj5prhD?+U(&q& zJImABwgPQ{wQ_5mVSD^qi5QGut~DZboes6fg{2ixGhRFiP4y=*@WN&I<8{EuxbAUP zUeX)J$cCMee7yBb+E8)d^C~^j(8@hFevfuARFtwT(;^qPdg75}FY4&F;E8bG(Mr1Q zy%j$hwe`Jo8Sn7e*}ax9?XGC;3-(=m8w80^5zz*0+*sfD&0P(Vi|xTcgvG=Rkw(UwG5ne2?C{^w+GVyXAhoWZzC|J>og^q`9(70jyU6)0`IK~< zmeXRwXp&gbV+Or-58Q{2%+TPSo=F|J{{j9VS7BdgY>L80KZs97>jaa~@g9UT+YVS_ z;}XVxzwEJmryA3fEF~w0{e~7^kHjpb-@gKAr%oKJc^{4HX8lHWu~wh5F@&i1Mjhkaa=~+ z%+Dg-=o*fTx_nyn0md3dm&xC2fcbMQF!M;%&TQt~eC;Y3RQAyZY&II&Vt-ZQKaL(gvZpPeMsQ}u93xcdlg zHli;!_|!|)<|-5l6?2k{O|8{jNcxO*zj}nngObMa@H)5h_ z%g#-iZzJw45egPszbtJp7&dmMDxlDvmg;IXWC>H#JTAu#3CFt|M_q_KHrKgro$i^} zU+uEFPM(&P==p;_yM|5C#equo{z<3mfYPpyr;RC&0@Fwibv&r2sd^EQR#=Fm4 z4PGmIlAl>=%WTPIl$n;N2mlB=NU!B4f^)QyWHE5+)Kd6hdM;@G3sDaF*J&x za3QvwL_^Z7OhRt}9RK2|inqpdb>bBPZWX@tcMH|E2a0|@%qe$laC!BZ9-cKvI-Q-{ zk*y~wiualyM)(sF5{3q1>A(B1({F$%p54QtVTbYCpYgM{u{j#Tw263rj|;_KK}^r~ zlv6u&NAJ0POB>r1^PPc>8%72hc{E9Z*@TE)DcSd(Kg7TmoA>>ZuJUP->>P6J7->82oaRy>vB9=28F)|)!#ZY9-_3KO$ z>J#UARC()VwF$a4vWRc9*&=f=_1e}GjumY-qdE&}&hLg#*eKtCDL&#y7Jbs}YrHGY zQ6QsCuOxwy%dD~6nYR=Y6c0~4hTiP+@G^J^ z1%k%IH?$mc1K>P7B)~%aKt)KFH z`^FaTqhXF=<0nI?c=sO$y97LB6U%dfcnz(pG-Vvapm>zb`!W9F)otM~lq zqNc940kmBOZL6iDT>Dz?4tGa*Sg%D2`5{ORBAfV0rzXf%SYm zTSS*sC2Q8l`j7q_$!D30L&L*g!CYFTQp1i6(l?qpELbw*PmRmv9CaC$p9Xv?kTW{&;u-Q2*x2C&%B zZ%nkl?9Z-2bSfm@<7;`M=c#*EW@O~N&`m=Qn(L_Jc1KB(^bplQf6iL}v~!4>I~iww zT~ydkrsB)Y^)r8gFoUd8u(HtLe7x-&Dy3nbPmi@N4*c^Hk|^*&vXSoK?)9W}BQ&@b z+-rhNv{u&Efg=s=-1$5!Q_M+(r^ocu@+LzvvRB(5XcvD8u1skkgk&c&>Wf~vf`A_m z_Lfs3|DY6yjuxG3b%&C!{JP76?5KPT)p$+kawAoePm)i5Mg7{FE{Fh`>uNmCHr}VQ zu(R((a*rAHg#)BKpXyh3$v_npWcm%|#E60~E5jKOi#WW|7tseo&a&U}<&==At35E& zn^}Tr)aW2@VRkBf^EGI0G410*l4c0Sd2uGVc6M`@Q}JzT0&`Jk>8qJrZAsYk94MH= zNU2NTAzzP1*NHT~_bq9d=nxQ^>X4nJAubzt25KeO^zd#Jo9U?;U(k@F5ZZpjgQENj zov^rK$dr`6{oc4r>oPy%O#)Z6A6-bR8UPl}0{0yO60TH9(9c55#@5U~ z-zbn{ewrlNTSWLD(07JK0&q92jzVUv9m;O0HDVgq`7D0OiQ&B>``y8VtKdn<^-5Vbt#i+1N~J&& zrG@w&pSQ!(nLQi(9Z%Pp)P4(od@SEF4^r`t{tuq}j1et=y-XZ#;EV1-hrs=Qh4vw{ z_DcrpJHIJ49&WaviFXDp*m80#-J6^7HSF7KOeYq@p8DElZl5}6*CT{c$W!`1YimE_ zJ7$JhEpO2C|S^UDPvTEP3`MD0W^ zu`k=1HpT{4UVZ(qb%6FR4y;%7$2y_Q=VpD#o7?>Kyq=@b@xG-u z1Cn4FDDdl}IYL|5IEcUbc_g!4c=9UR3oS<3A%B-CenxBv*xG4fuKg`i(Hv10E&c4> z3(^>66>Z-)43(ocX{#kTzNADk=k<`M}#D3Fzd+avu# zq-tWs1Y~q(`>MSz@FqTA;Jx)w$*&)ow8Ed|L3zu<5tv0UjcU8cIOTF+I4rFfj+&}y zJy)J@_NXmjCAVyN_rjqt-+R)2B72pJncj9xlBdGEV&!ro{MFeXuH#yNm{O{9?A1;) z!O#4Pg2F->mrY^$8}dMgX`>~gvY9nl7V>~V!7_FSXBn}vd{d0JArXPEphGmzUoY?+bui-)qC^QT5keBUtf^0dP6fI1R4VfcA?L2=X0cPziAz!pv=~TwHUoF*73z_IjuK!5jaOS;MO6{5=5YwlKz|tz!WYuKr zlK_D4gqTm{REoa+&Sv6tlP)VPRM|ojUSFDwZN57BKBlFrnzgmPEm_9^4w9Y7H+Hz6 z-oq|O#pudUxx$tSJ&KlYu;a{Dl(zpQJ{wYz8fpFo&b=3AmKUGwe8Rf=(Ni^4;6$># zkf(eY&y8k(Yn)QC-u(F{T1Lx`A({-&3T_7IS3BUT{$^7-v+zG6!wDTCt=hOllw-ez zZ>rCq+QnqDExU8FC?D9RiTM$w&EVEWdJIdKj7E=|V1uln;QrVn0YV^@w4l7v+$OK0l3;WVzKde2_?VBC={1YoYgn21wJ$?RpdN zR?>&Js~q=uC(Ij)O6oh?0xXDb#@!DOc$SQkwd+XXvQb=y%ju6Es zRzdnwPq!xhw9|CljtNu(*3vcPg&oVx6rz`8)(5|Z!pV^5rP`io%p$hLNq~Ro+k|D? zI5|A)T&B4>N=a`-i;-(N8BH!JyWP7Z`7reBtj2V9e23>-=2^dP{7qffkeJkxjlDR0 zxah%(@OOv9+=-|CrQc7D@&}Cu;CqR61xfwBjq`IK<(DAaJI1x_Mh=dm`hJC}7=@Q+ zA<&hN_h9nL06oO&IYmOE_!#hmFxSj%-P-a`hH*h_ZT$XMCW?0!NX5lm%=`rI>R)?v zzWypT$WcI7Me|@OIlY5P{yBuPP7ta|WwxX;(Y!{!7bJgwz~_<=(a7*<{l|*!x7LZg z-5GELU_Co%3VCQ*LFpvF-50dgcUyC`(8PXF7f$f9G1<&9aF+$PvKD}g3iT<_ohuZ+ zFRjsK?EK#zTapYOFLv!$|3I6n zw#ONVeITiVfq7q6GXXK6y>SiYXo<)9N2G&OCc;r$Yp!KJy!$f5!bH5g`giXDoP4$3%A)u*X-SwK zt)dSLLr*gv6Jm&Vf){-4gKR|pEJ?eS_@ zffWoB_w39_;WIEP{+ScI&&f-+RUOX(LXQ)}I$rUZ=c_-YZ&p9zaUK}L?mroLH;1E% zQGD0XAS45D!i~kDu*wB>p0Cm0X1|Dgv|(1@e5tG2+54zp&s?p0;Wb^#-wzM)yxe2R z8s49rCnSgp@7JXi)=6iJD-(Nb&rA`B-j&kRg}PfRK2RI45=b2``XKc6Pi9N!XJMQc?DOvF6LY*D;VOOaZ1Ukw#o?>(Sm{VIljS>gZzp z6_4<^y(>2B);PV@AkmZil#-SHR@~aVn%K<1z(55%oM#0j<_V}LwPqTbuyB*EIG}u9 zNN}-=Su1=F9``q4Flj@y?f(XxK{#U=JQ%Dh5)DTw(R5Avo|bg9UjRP~x9I=I18j`1 zx@vSj*~Oy?onQH2rpbs&8qxP{C4cSerfQKj0NHJ7THVshW-TIoKPfn!z}y7dH2--! ztY1zG4*qp*rfEMF11I+s?68r`5K=@1FbK(&-f#>Srv3CL2^bn!6?CBT@(GP zY-YE+?r)VY9VmhAtL_#ix?&puLv8ZEXodO_3WBJVkIVjaI|E5wHh_B`N+@q0#!{5- z>w|B@&mmlrc_q&wPR)J}86|Sp|Df3$-8dYdK7?c?_DuJuM$@esCOaZuWcpIc$ss-S zTxW<^`5CJCz6y-Jum#N9#gLa|zo6nf#d(TS0f~8vqTxT!p`sB0+3nv2!rO7bSTK!% zWF7BQONxrV?3yoCfb~msC;c4^ZNBaWEvn+3M$mW7um|Jc|5nbtQDtpRg0Ed1dZ#| zrO*J_W7OA)nXiAvgV39{*wTAn!9IS1k5xLVtYn{BQ1zpj!%6#o1@Bvbna$xHX>w&< z&9`b*#TAE8WaSvkeG4Ao8+Gf(jQp|KCp@^6AraSM56D%!t8}Zh*{JS(#0t_xH4pT|%&Ij$yJ)@tjVlK$xb^=h-5dX!9z3sOzhrOE z&i>%}EfuV*$Ax?%;DCZ3;47(Q(u^D$HghBKZ#Z_ zKQODoKu`YG#Yto+?oI5HF2azEyg-O5O-*k&JRF-0nRbV(ad5LKiFnfHLoYn$`{ct3 zW6W;HW|4i0ecbB%!k01pS?R1Fr-hn_h+`7lN4QT^Is%0q;}*`mbvrZuY`dooEtwA` z-S)(;UH>lBO$pm@p!1=b6TM~7`pbttJ6#x+0Hh-+1lqFt4jQ?KBsTbVwJi(3NmO!{ z(3d(j(80J{>2MQqW;z7m%W*J7_)jdfO@T{TfF^1=UVm=zo{41@vo z|0|``SbRzIR-tqbH4sWyjQgBNyLVcER>-YZI-`M*;*^bnL0kyr4P!7UD^w{A{aF14 zAeiDGZ3vUS#@LjN-#a=s63*XKV$JBud_6X){#}Jy-_Kjr{tofNEhc7TImCaoD>a6S zjzQgF&|R92mG7=xN_f^VDKkvAB7bA0;I{*&eE(?l-yi@yO5`!|^;6ydIt08XP1+yS z!oX;02lfX_JoOvBk85%VVmietssfilw<2e%ea^q4V8PYicvJ&Ei>ExjtJCdFdoi?P zt2_`!#QUrEPMQ5_I-@Q*T#-0{mM#8XZ6NE4s0Rmublo~soNPlxDBC=R=H=k zRPyOBsR9YoORiGp7311_z-PiJ-@yJ5GE+@mAu{L%(v?i`9sa3Yg4m)sQTd5oS_V#v z)5zL^{nkIJ68}>FEcZ KxfEi?Q=I#XJqtEmvFB>tZ!c& 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 Date: Mon, 11 Sep 2017 13:04:28 -0500 Subject: [PATCH 040/102] Update Malf_Modules.dm --- code/game/gamemodes/malfunction/Malf_Modules.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index 5dfd8f7396..4f3b4c3ea2 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -309,8 +309,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( owner_AI.nuking = TRUE owner_AI.doomsday_device = DOOM owner_AI.doomsday_device.start() - for(var/pinpointer in GLOB.pinpointer_list) - var/obj/item/pinpointer/P = pinpointer + for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list) P.switch_mode_to(TRACK_MALF_AI) //Pinpointers start tracking the AI wherever it goes qdel(src) From 6a47a7011ade85c3c8c3f8ff86f60d0f6434ab5b Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:05:22 -0500 Subject: [PATCH 041/102] Update nuclear.dm --- code/game/gamemodes/nuclear/nuclear.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 59650561a6..1b1bec68c1 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -325,7 +325,7 @@ gloves = /obj/item/clothing/gloves/combat back = /obj/item/storage/backpack ears = /obj/item/device/radio/headset/syndicate/alt - l_pocket = /obj/item/pinpointer/syndicate + l_pocket = /obj/item/pinpointer/nuke/syndicate id = /obj/item/card/id/syndicate belt = /obj/item/gun/ballistic/automatic/pistol backpack_contents = list(/obj/item/storage/box/syndie=1) From 052fdb70eafe8123bf5a0435e1a67cc0106e869e Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:06:27 -0500 Subject: [PATCH 042/102] Update nuclearbomb.dm --- code/game/gamemodes/nuclear/nuclearbomb.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index ee611349f8..5245b00c35 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -362,9 +362,9 @@ if(safety) if(timing) set_security_level(previous_level) - for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list) + for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(initial(S.mode)) - S.nuke_warning = FALSE + S.alert = FALSE timing = FALSE bomb_set = TRUE detonation_timer = null @@ -381,7 +381,7 @@ bomb_set = TRUE set_security_level("delta") detonation_timer = world.time + (timer_set * 10) - for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list) + for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(TRACK_INFILTRATOR) countdown.start() else @@ -390,7 +390,7 @@ set_security_level(previous_level) for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(initial(S.mode)) - S.nuke_warning = FALSE + S.alert = FALSE countdown.stop() update_icon() From 26c6f5cc140cc6f57bdd77e1e5ccfee6f119599e Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:07:35 -0500 Subject: [PATCH 043/102] Update pinpointer.dm --- code/game/gamemodes/nuclear/pinpointer.dm | 159 +++++----------------- 1 file changed, 34 insertions(+), 125 deletions(-) diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm index 342bcac090..461ef78ef3 100644 --- a/code/game/gamemodes/nuclear/pinpointer.dm +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -1,56 +1,7 @@ -//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk. -/obj/item/pinpointer - name = "pinpointer" - desc = "A handheld tracking device that locks onto certain signals." - icon = 'icons/obj/device.dmi' - icon_state = "pinoff" - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - w_class = WEIGHT_CLASS_SMALL - item_state = "electronic" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - throw_speed = 3 - throw_range = 7 - materials = list(MAT_METAL = 500, MAT_GLASS = 250) - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/active = FALSE - var/atom/movable/target = null //The thing we're searching for - var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode - var/target_x = 0 //The target coordinates if we're tracking those - var/target_y = 0 - var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination - var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke - var/mode = TRACK_NUKE_DISK //What are we looking for? +/obj/item/pinpointer/nuke + var/mode = TRACK_NUKE_DISK -/obj/item/pinpointer/New() - ..() - GLOB.pinpointer_list += src - -/obj/item/pinpointer/Destroy() - STOP_PROCESSING(SSfastprocess, src) - GLOB.pinpointer_list -= src - return ..() - -/obj/item/pinpointer/attack_self(mob/living/user) - active = !active - user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.") - playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) - icon_state = "pin[active ? "onnull" : "off"]" - if(active) - START_PROCESSING(SSfastprocess, src) - else - target = null //Restarting the pinpointer forces a target reset - STOP_PROCESSING(SSfastprocess, src) - -/obj/item/pinpointer/attackby(obj/item/I, mob/living/user, params) - if(mode != TRACK_ATOM) - return ..() - user.visible_message("[user] tunes [src] to [I].", "You fine-tune [src]'s tracking to track [I].") - playsound(src, 'sound/machines/click.ogg', 50, 1) - constant_target = I - -/obj/item/pinpointer/examine(mob/user) +/obj/item/pinpointer/nuke/examine(mob/user) ..() var/msg = "Its tracking indicator reads " switch(mode) @@ -67,22 +18,20 @@ if(bomb.timing) to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.get_time_left()]") -/obj/item/pinpointer/process() - if(!active) - STOP_PROCESSING(SSfastprocess, src) - return - scan_for_target() - point_to_target() - my_god_jc_a_bomb() - addtimer(CALLBACK(src, .proc/refresh_target), 50, TIMER_UNIQUE) +/obj/item/pinpointer/nuke/process() + ..() + if(active) // If shit's going down + for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list) + if(bomb.timing) + if(!alert) + alert = TRUE + playsound(src, 'sound/items/nuke_toy_lowpower.ogg', 50, 0) + if(isliving(loc)) + var/mob/living/L = loc + to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.") -/obj/item/pinpointer/proc/scan_for_target() //Looks for whatever it's tracking - if(target) - if(isliving(target)) - var/mob/living/L = target - if(L.stat == DEAD) - target = null - return +/obj/item/pinpointer/nuke/scan_for_target() + target = null switch(mode) if(TRACK_NUKE_DISK) var/obj/item/disk/nuclear/N = locate() in GLOB.poi_list @@ -98,76 +47,36 @@ target = A if(TRACK_INFILTRATOR) target = SSshuttle.getShuttle("syndicate") - if(TRACK_OPERATIVES) - var/list/possible_targets = list() - var/turf/here = get_turf(src) - for(var/V in SSticker.mode.syndicates) - var/datum/mind/M = V - if(M.current && M.current.stat != DEAD) - possible_targets |= M.current - var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here) - if(closest_operative) - target = closest_operative - if(TRACK_ATOM) - if(constant_target) - target = constant_target - if(TRACK_COORDINATES) - var/turf/T = get_turf(src) - target = locate(target_x, target_y, T.z) + ..() -/obj/item/pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction - if(!active) - return - if(!target || (mode == TRACK_ATOM && !constant_target)) - icon_state = "pinon[nuke_warning ? "alert" : ""]null" - return - var/turf/here = get_turf(src) - var/turf/there = get_turf(target) - if(here.z != there.z) - icon_state = "pinon[nuke_warning ? "alert" : ""]null" - return - if(get_dist_euclidian(here,there)<=minimum_range) - icon_state = "pinon[nuke_warning ? "alert" : ""]direct" - else - setDir(get_dir(here, there)) - switch(get_dist(here, there)) - if(1 to 8) - icon_state = "pinon[nuke_warning ? "alert" : "close"]" - if(9 to 16) - icon_state = "pinon[nuke_warning ? "alert" : "medium"]" - if(16 to INFINITY) - icon_state = "pinon[nuke_warning ? "alert" : "far"]" - -/obj/item/pinpointer/proc/my_god_jc_a_bomb() //If we should get the hell back to the ship - for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list) - if(bomb.timing) - if(!nuke_warning) - nuke_warning = TRUE - playsound(src, 'sound/items/nuke_toy_lowpower.ogg', 50, 0) - if(isliving(loc)) - var/mob/living/L = loc - to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.") - -/obj/item/pinpointer/proc/switch_mode_to(new_mode) //If we shouldn't be tracking what we are +/obj/item/pinpointer/nuke/proc/switch_mode_to(new_mode) if(isliving(loc)) var/mob/living/L = loc to_chat(L, "Your [name] beeps as it reconfigures its tracking algorithms.") playsound(L, 'sound/machines/triple_beep.ogg', 50, 1) mode = new_mode - target = null //Switch modes so we can find the new target + scan_for_target() -/obj/item/pinpointer/proc/refresh_target() //Periodically removes the target to allow the pinpointer to update (i.e. malf AI shunts, an operative dies) - target = null - -/obj/item/pinpointer/syndicate //Syndicate pinpointers automatically point towards the infiltrator once the nuke is active. +/obj/item/pinpointer/nuke/syndicate // Syndicate pinpointers automatically point towards the infiltrator once the nuke is active. name = "syndicate pinpointer" desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device." + icon_state = "pinpointer_syndicate" -/obj/item/pinpointer/syndicate/cyborg //Cyborg pinpointers just look for a random operative. +/obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative. name = "cyborg syndicate pinpointer" desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives." - mode = TRACK_OPERATIVES flags_1 = NODROP_1 - +/obj/item/pinpointer/syndicate_cyborg/scan_for_target() + target = null + var/list/possible_targets = list() + var/turf/here = get_turf(src) + for(var/V in SSticker.mode.syndicates) + var/datum/mind/M = V + if(M.current && M.current.stat != DEAD) + possible_targets |= M.current + var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here) + if(closest_operative) + target = closest_operative + ..() From 489b2c6deba9d08a1390bcdbc2dab3f6b01fcba9 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:08:35 -0500 Subject: [PATCH 044/102] Update objective_items.dm --- code/game/gamemodes/objective_items.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 3cfede5f93..c1af4de9f0 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -186,7 +186,7 @@ return ..() //Old ninja objectives. -/datum/objective_item/special/pinpointer +/datum/objective_item/special/pinpointer/nuke name = "the captain's pinpointer." targetitem = /obj/item/pinpointer difficulty = 10 From ff17626ce7e86b464746c9a5218999e0310182fe Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:09:30 -0500 Subject: [PATCH 045/102] Update death.dm --- code/modules/mob/living/silicon/ai/death.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 52c06439fb..d41b6f5f29 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -35,9 +35,9 @@ if(nuking) set_security_level("red") nuking = FALSE - for(var/obj/item/pinpointer/P in GLOB.pinpointer_list) + for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list) P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone - P.nuke_warning = FALSE + P.alert = FALSE if(doomsday_device) doomsday_device.timing = FALSE From c1872907b1f9ae2c07253798b7aa1e4e349f8d43 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:10:18 -0500 Subject: [PATCH 046/102] Update robot_modules.dm --- code/modules/mob/living/silicon/robot/robot_modules.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 41fbc69180..af6f3daf92 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -599,7 +599,7 @@ /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg, /obj/item/card/emag, /obj/item/crowbar/cyborg, - /obj/item/pinpointer/syndicate/cyborg) + /obj/item/pinpointer/syndicate_cyborg) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/security, @@ -625,7 +625,7 @@ /obj/item/roller/robo, /obj/item/card/emag, /obj/item/crowbar/cyborg, - /obj/item/pinpointer/syndicate/cyborg, + /obj/item/pinpointer/syndicate_cyborg, /obj/item/stack/medical/gauze/cyborg, /obj/item/gun/medbeam) ratvar_modules = list( From 6951e39d1304f5189a4fbe87f892a92c20bfdbaa Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:10:54 -0500 Subject: [PATCH 047/102] Update apc.dm --- code/modules/power/apc.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 3b070f1384..b0212e6155 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -874,9 +874,9 @@ occupier.loc = src.loc occupier.death() occupier.gib() - for(var/obj/item/pinpointer/P in GLOB.pinpointer_list) + for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list) P.switch_mode_to(TRACK_NUKE_DISK) //Pinpointers go back to tracking the nuke disk - P.nuke_warning = FALSE + P.alert = FALSE /obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card) if(card.AI) From a6e280cbad4e8109e3a9cb4cfefd5703e1cb2311 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 11 Sep 2017 13:16:16 -0500 Subject: [PATCH 048/102] Automatic changelog generation for PR #2600 [ci skip] --- html/changelogs/AutoChangeLog-pr-2600.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2600.yml diff --git a/html/changelogs/AutoChangeLog-pr-2600.yml b/html/changelogs/AutoChangeLog-pr-2600.yml new file mode 100644 index 0000000000..79380038d4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2600.yml @@ -0,0 +1,4 @@ +author: "Jay" +delete-after: True +changes: + - tweak: "Removes the lisp lizards have when talking" From af5ffcc83ae824da42e181b671b9f846ee8f6d63 Mon Sep 17 00:00:00 2001 From: Ashe Higgs Date: Mon, 11 Sep 2017 14:37:09 -0400 Subject: [PATCH 049/102] Adds departmental banners --- code/game/objects/items/religion.dm | 200 ++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 13 deletions(-) diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index 1edbba1f56..007c590cac 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -1,27 +1,201 @@ /obj/item/banner name = "banner" + desc = "A banner with Nanotrasen's logo on it." icon = 'icons/obj/items_and_weapons.dmi' icon_state = "banner" item_state = "banner" + force = 8 + attack_verb = list("forcefully inspired", "violently encouraged", "relentlessly galvanized") lefthand_file = 'icons/mob/inhands/equipment/banners_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi' - desc = "A banner with Nanotrasen's logo on it." - var/moralecooldown = 0 - var/moralewait = 600 + var/inspiration_available = TRUE //If this banner can be used to inspire crew + var/morale_time = 0 + var/morale_cooldown = 600 //How many deciseconds between uses + var/list/job_loyalties //Mobs with any of these assigned roles will be inspired + var/list/role_loyalties //Mobs with any of these special roles will be inspired + var/warcry + +/obj/item/banner/examine(mob/user) + ..() + if(inspiration_available) + to_chat(user, "Activate it in your hand to inspire nearby allies of this banner's allegiance!") /obj/item/banner/attack_self(mob/living/carbon/human/user) - if(moralecooldown + moralewait > world.time) + if(!inspiration_available) return - to_chat(user, "You increase the morale of your fellows!") - moralecooldown = world.time + if(morale_time > world.time) + to_chat(user, "You aren't feeling inspired enough to flourish [src] again yet.") + return + user.visible_message("[user] flourishes [src]!", \ + "You raise [src] skywards, inspiring your allies!") + playsound(src, "rustle", 100, FALSE) + if(warcry) + user.say("[warcry]") + var/old_transform = user.transform + user.transform *= 1.2 + animate(user, transform = old_transform, time = 10) + morale_time = world.time + morale_cooldown - for(var/mob/living/carbon/human/H in range(4,get_turf(src))) - to_chat(H, "Your morale is increased by [user]'s banner!") - H.adjustBruteLoss(-15) - H.adjustFireLoss(-15) - H.AdjustStun(-40) - H.AdjustKnockdown(-40) - H.AdjustUnconscious(-40) + var/list/inspired = list() + var/has_job_loyalties = LAZYLEN(job_loyalties) + var/has_role_loyalties = LAZYLEN(role_loyalties) + inspired += user //The user is always inspired, regardless of loyalties + for(var/mob/living/carbon/human/H in range(4, get_turf(src))) + if(H.stat == DEAD || H == user) + continue + if(H.mind && (has_job_loyalties || has_role_loyalties)) + if(has_job_loyalties && H.mind.assigned_role in job_loyalties) + inspired += H + else if(has_role_loyalties && H.mind.special_role in role_loyalties) + inspired += H + else if(check_inspiration(H)) + inspired += H + + for(var/V in inspired) + var/mob/living/carbon/human/H = V + if(H != user) + to_chat(H, "Your confidence surges as [user] flourishes [user.p_their()] [name]!") + inspiration(H) + special_inspiration(H) + +/obj/item/banner/proc/check_inspiration(mob/living/carbon/human/H) //Banner-specific conditions for being eligible + return + +/obj/item/banner/proc/inspiration(mob/living/carbon/human/H) + H.adjustBruteLoss(-15) + H.adjustFireLoss(-15) + H.AdjustStun(-40) + H.AdjustKnockdown(-40) + H.AdjustUnconscious(-40) + playsound(H, 'sound/magic/staff_healing.ogg', 25, FALSE) + +/obj/item/banner/proc/special_inspiration(mob/living/carbon/human/H) //Any banner-specific inspiration effects go here + return + +/obj/item/banner/security + name = "securistan banner" + desc = "The banner of Securistan, ruling the station with an iron fist." + icon_state = "banner_security" + job_loyalties = list("Security Officer", "Warden", "Detective", "Head of Security") + warcry = "EVERYONE DOWN ON THE GROUND!!" + +/obj/item/banner/security/mundane + inspiration_available = FALSE + +/datum/crafting_recipe/security_banner + name = "Securistan Banner" + result = /obj/item/banner/security/mundane + time = 40 + reqs = list(/obj/item/stack/rods = 2, + /obj/item/clothing/under/rank/security = 1) + category = CAT_MISC + +/obj/item/banner/medical + name = "meditopia banner" + desc = "The banner of Meditopia, generous benefactors that cure wounds and shelter the weak." + icon_state = "banner_medical" + job_loyalties = list("Medical Doctor", "Chemist", "Geneticist", "Virologist", "Chief Medical Officer") + warcry = "No wounds cannot be healed!" + +/obj/item/banner/medical/mundane + inspiration_available = FALSE + +/obj/item/banner/medical/check_inspiration(mob/living/carbon/human/H) + return H.stat //Meditopia is moved to help those in need + +/datum/crafting_recipe/medical_banner + name = "Meditopia Banner" + result = /obj/item/banner/medical/mundane + time = 40 + reqs = list(/obj/item/stack/rods = 2, + /obj/item/clothing/under/rank/medical = 1) + category = CAT_MISC + +/obj/item/banner/medical/special_inspiration(mob/living/carbon/human/H) + H.adjustToxLoss(-15) + H.setOxyLoss(0) + H.reagents.add_reagent("inaprovaline", 5) + +/obj/item/banner/science + name = "sciencia banner" + desc = "The banner of Sciencia, bold and daring thaumaturges and researchers that take the path less traveled." + icon_state = "banner_science" + job_loyalties = list("Scientist", "Roboticist", "Research Director") + warcry = "For Cuban Pete!" + +/obj/item/banner/science/mundane + inspiration_available = FALSE + +/obj/item/banner/science/check_inspiration(mob/living/carbon/human/H) + return H.on_fire //Sciencia is pleased by dedication to the art of Toxins + +/datum/crafting_recipe/science_banner + name = "Sciencia Banner" + result = /obj/item/banner/science/mundane + time = 40 + reqs = list(/obj/item/stack/rods = 2, + /obj/item/clothing/under/rank/scientist = 1) + category = CAT_MISC + +/obj/item/banner/cargo + name = "cargonia banner" + desc = "The banner of the eternal Cargonia, with the mystical power of conjuring any object into existence." + icon_state = "banner_cargo" + job_loyalties = list("Cargo Technician", "Shaft Miner", "Quartermaster") + warcry = "Hail Cargonia!" + +/obj/item/banner/cargo/mundane + inspiration_available = FALSE + +/datum/crafting_recipe/cargo_banner + name = "Cargonia Banner" + result = /obj/item/banner/cargo/mundane + time = 40 + reqs = list(/obj/item/stack/rods = 2, + /obj/item/clothing/under/rank/cargotech = 1) + category = CAT_MISC + +/obj/item/banner/engineering + name = "engitopia banner" + desc = "The banner of Engitopia, wielders of limitless power." + icon_state = "banner_engineering" + job_loyalties = list("Station Engineer", "Atmospheric Technician", "Chief Engineer") + warcry = "All hail lord Singuloth!!" + +/obj/item/banner/engineering/mundane + inspiration_available = FALSE + +/obj/item/banner/engineering/special_inspiration(mob/living/carbon/human/H) + H.radiation = 0 + +/datum/crafting_recipe/engineering_banner + name = "Engitopia Banner" + result = /obj/item/banner/engineering/mundane + time = 40 + reqs = list(/obj/item/stack/rods = 2, + /obj/item/clothing/under/rank/engineer = 1) + category = CAT_MISC + +/obj/item/banner/command + name = "command banner" + desc = "The banner of Command, a staunch and ancient line of bueraucratic kings and queens." + //No icon state here since the default one is the NT banner + job_loyalties = list("Captain", "Head of Personnel", "Chief Engineer", "Head of Security", "Research Director", "Chief Medical Officer") + warcry = "Hail Nanotrasen!" + +/obj/item/banner/command/mundane + inspiration_available = FALSE + +/obj/item/banner/command/check_inspiration(mob/living/carbon/human/H) + return H.isloyal() //Command is stalwart but rewards their allies. + +/datum/crafting_recipe/command_banner + name = "Command Banner" + result = /obj/item/banner/command/mundane + time = 40 + reqs = list(/obj/item/stack/rods = 2, + /obj/item/clothing/under/captainparade = 1) + category = CAT_MISC /obj/item/banner/red name = "red banner" From b008cdada03721c701a19833e6ac52f624f7caac Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:47:33 -0500 Subject: [PATCH 050/102] oopsie woopsie --- .../clock_structures/prolonging_prism.dm | 905 +++--------------- 1 file changed, 125 insertions(+), 780 deletions(-) diff --git a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm index c6692073b0..9ef7fa4ab7 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm @@ -1,790 +1,135 @@ -#define WELDER_FUEL_BURN_INTERVAL 13 +//Prolonging Prism: A prism that consumes power to delay the shuttle +/obj/structure/destructible/clockwork/powered/prolonging_prism + name = "prolonging prism" + desc = "A dark onyx prism, held in midair by spiraling tendrils of stone." + clockwork_desc = "A powerful prism that will delay the arrival of an emergency shuttle." + icon_state = "prolonging_prism_inactive" + active_icon = "prolonging_prism" + inactive_icon = "prolonging_prism_inactive" + unanchored_icon = "prolonging_prism_unwrenched" + construction_value = 20 + max_integrity = 125 + break_message = "The prism falls to the ground with a heavy thud!" + debris = list(/obj/item/clockwork/alloy_shards/small = 3, \ + /obj/item/clockwork/alloy_shards/medium = 1, \ + /obj/item/clockwork/alloy_shards/large = 1, \ + /obj/item/clockwork/component/vanguard_cogwheel/onyx_prism = 1) + var/static/list/component_refund = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1) + var/static/delay_cost = 3000 + var/static/delay_cost_increase = 1250 + var/static/delay_remaining = 0 -/* Tools! - * Note: Multitools are /obj/item/device - * - * Contains: - * Wrench - * Screwdriver - * Wirecutters - * Welding Tool - * Crowbar - */ - -/* - * Wrench - */ -/obj/item/wrench - name = "wrench" - desc = "A wrench with common uses. Can be found in your hand." - icon = 'icons/obj/tools.dmi' - icon_state = "wrench" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - usesound = 'sound/items/ratchet.ogg' - materials = list(MAT_METAL=150) - origin_tech = "materials=1;engineering=1" - attack_verb = list("bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/wrench/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wrench/cyborg - name = "automatic wrench" - desc = "An advanced robotic wrench. Can be found in construction cyborgs." - toolspeed = 0.5 - -/obj/item/wrench/brass - name = "brass wrench" - desc = "A brass wrench. It's faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "wrench_brass" - toolspeed = 0.5 - -/obj/item/wrench/abductor - name = "alien wrench" - desc = "A polarized wrench. It causes anything placed between the jaws to turn." - icon = 'icons/obj/abductor.dmi' - icon_state = "wrench" - usesound = 'sound/effects/empulse.ogg' - toolspeed = 0.1 - origin_tech = "materials=5;engineering=5;abductor=3" - -/obj/item/wrench/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a bolt bit." - icon_state = "drill_bolt" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/drill_use.ogg' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - attack_verb = list("drilled", "screwed", "jabbed") - toolspeed = 0.25 - -/obj/item/wrench/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power - to_chat(user, "You attach the screw driver bit to [src].") - qdel(src) - user.put_in_active_hand(s_drill) - -/obj/item/wrench/power/suicide_act(mob/user) - user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/wrench/medical - name = "medical wrench" - desc = "A medical wrench with common(medical?) uses. Can be found in your hand." - icon_state = "wrench_medical" - force = 2 //MEDICAL - throwforce = 4 - origin_tech = "materials=1;engineering=1;biotech=3" - attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked") - -/obj/item/wrench/medical/suicide_act(mob/living/user) - user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!") - // TODO Make them glow with the power of the M E D I C A L W R E N C H - // during their ascension - - // Stun stops them from wandering off - user.Stun(100, ignore_canstun = TRUE) - playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1) - - // Let the sound effect finish playing - sleep(20) - - if(!user) - return - - for(var/obj/item/W in user) - user.dropItemToGround(W) - - var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc) - W.add_fingerprint(user) - W.desc += " For some reason, it reminds you of [user.name]." - - if(!user) - return - - user.dust() - - return OXYLOSS - -/* - * Screwdriver - */ -/obj/item/screwdriver - name = "screwdriver" - desc = "You can be totally screwy with this." - icon = 'icons/obj/tools.dmi' - icon_state = "screwdriver" - item_state = "screwdriver" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - w_class = WEIGHT_CLASS_TINY - throwforce = 5 - throw_speed = 3 - throw_range = 5 - materials = list(MAT_METAL=75) - attack_verb = list("stabbed") - hitsound = 'sound/weapons/bladeslice.ogg' - usesound = 'sound/items/screwdriver.ogg' - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - var/random_color = TRUE //if the screwdriver uses random coloring - var/static/list/screwdriver_colors = list(\ - "blue" = rgb(24, 97, 213), \ - "red" = rgb(149, 23, 16), \ - "pink" = rgb(213, 24, 141), \ - "brown" = rgb(160, 82, 18), \ - "green" = rgb(14, 127, 27), \ - "cyan" = rgb(24, 162, 213), \ - "yellow" = rgb(213, 140, 24), \ - ) - -/obj/item/screwdriver/suicide_act(mob/user) - user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/Initialize() - . = ..() - if(random_color) //random colors! - var/our_color = pick(screwdriver_colors) - add_atom_colour(screwdriver_colors[our_color], FIXED_COLOUR_PRIORITY) - update_icon() - if(prob(75)) - pixel_y = rand(0, 16) - -/obj/item/screwdriver/update_icon() - if(!random_color) //icon override - return - cut_overlays() - var/mutable_appearance/base_overlay = mutable_appearance(icon, "screwdriver_screwybits") - base_overlay.appearance_flags = RESET_COLOR - add_overlay(base_overlay) - -/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file) - . = list() - if(isinhands && random_color) - var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") - M.appearance_flags = RESET_COLOR - . += M - -/obj/item/screwdriver/get_belt_overlay() - if(random_color) - var/mutable_appearance/body = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver") - var/mutable_appearance/head = mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_head") - body.color = color - head.add_overlay(body) - return head - else - return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) - -/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M)) - return ..() - if(user.zone_selected != "eyes" && user.zone_selected != "head") - return ..() - if(user.disabilities & CLUMSY && prob(50)) - M = user - return eyestab(M,user) - -/obj/item/screwdriver/brass - name = "brass screwdriver" - desc = "A screwdriver made of brass. The handle feels freezing cold." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "screwdriver_brass" - item_state = "screwdriver_brass" - toolspeed = 0.5 - random_color = FALSE - -/obj/item/screwdriver/abductor - name = "alien screwdriver" - desc = "An ultrasonic screwdriver." - icon = 'icons/obj/abductor.dmi' - icon_state = "screwdriver_a" - item_state = "screwdriver_nuke" - usesound = 'sound/items/pshoom.ogg' - toolspeed = 0.1 - random_color = FALSE - -/obj/item/screwdriver/power - name = "hand drill" - desc = "A simple powered hand drill. It's fitted with a screw bit." - icon_state = "drill_screw" - item_state = "drill" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change - w_class = WEIGHT_CLASS_SMALL - throwforce = 8 - throw_speed = 2 - throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far - attack_verb = list("drilled", "screwed", "jabbed","whacked") - hitsound = 'sound/items/drill_hit.ogg' - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.25 - random_color = FALSE - -/obj/item/screwdriver/power/suicide_act(mob/user) - user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/screwdriver/power/attack_self(mob/user) - playsound(get_turf(user),'sound/items/change_drill.ogg',50,1) - var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power - to_chat(user, "You attach the bolt driver bit to [src].") - qdel(src) - user.put_in_active_hand(b_drill) - -/obj/item/screwdriver/cyborg - name = "powered screwdriver" - desc = "An electrical screwdriver, designed to be both precise and quick." - usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.5 - -/* - * Wirecutters - */ -/obj/item/wirecutters - name = "wirecutters" - desc = "This cuts wires." - icon = 'icons/obj/tools.dmi' - icon_state = null - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 6 - throw_speed = 3 - throw_range = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=80) - attack_verb = list("pinched", "nipped") - hitsound = 'sound/items/wirecutter.ogg' - usesound = 'sound/items/wirecutter.ogg' - origin_tech = "materials=1;engineering=1" - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - - -/obj/item/wirecutters/New(loc, var/param_color = null) +/obj/structure/destructible/clockwork/powered/prolonging_prism/examine(mob/user) ..() - if(!icon_state) - if(!param_color) - param_color = pick("yellow","red") - icon_state = "cutters_[param_color]" + if(is_servant_of_ratvar(user) || isobserver(user)) + if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE) + to_chat(user, "An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.") + else + var/efficiency = get_efficiency_mod(TRUE) + to_chat(user, "It requires at least [DisplayPower(get_delay_cost())] of power to attempt to delay the arrival of an emergency shuttle by [2 * efficiency] minutes.") + to_chat(user, "This cost increases by [DisplayPower(delay_cost_increase)] for every previous activation.") -/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) - if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) - user.visible_message("[user] cuts [C]'s restraints with [src]!") - qdel(C.handcuffed) - C.handcuffed = null - if(C.buckled && C.buckled.buckle_requires_restraints) - C.buckled.unbuckle_mob(C) - C.update_handcuffed() - return - else - ..() - -/obj/item/wirecutters/suicide_act(mob/user) - user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, usesound, 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/brass - name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" - toolspeed = 0.5 - -/obj/item/wirecutters/abductor - name = "alien wirecutters" - desc = "Extremely sharp wirecutters, made out of a silvery-green metal." - icon = 'icons/obj/abductor.dmi' - icon_state = "cutters" - toolspeed = 0.1 - origin_tech = "materials=5;engineering=4;abductor=3" - -/obj/item/wirecutters/cyborg - name = "wirecutters" - desc = "This cuts wires." - toolspeed = 0.5 - -/obj/item/wirecutters/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." - icon_state = "jaws_cutter" - item_state = "jawsoflife" - origin_tech = "materials=2;engineering=2" - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - usesound = 'sound/items/jaws_cut.ogg' - toolspeed = 0.25 - -/obj/item/wirecutters/power/suicide_act(mob/user) - user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") - playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/bodypart/BP = C.get_bodypart("head") - if(BP) - BP.drop_limb() - playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power - to_chat(user, "You attach the pry jaws to [src].") - qdel(src) - user.put_in_active_hand(pryjaws) -/* - * Welding Tool - */ -/obj/item/weldingtool - name = "welding tool" - desc = "A standard edition welder provided by Nanotrasen." - icon = 'icons/obj/tools.dmi' - icon_state = "welder" - item_state = "welder" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 3 - throwforce = 5 - hitsound = "swing_hit" - usesound = 'sound/items/welder.ogg' - var/acti_sound = 'sound/items/welderactivate.ogg' - var/deac_sound = 'sound/items/welderdeactivate.ogg' - throw_speed = 3 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30) - resistance_flags = FIRE_PROOF - - materials = list(MAT_METAL=70, MAT_GLASS=30) - origin_tech = "engineering=1;plasmatech=1" - var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) - var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) - var/max_fuel = 20 //The max amount of fuel the welder can hold - var/change_icons = 1 - var/can_off_process = 0 - var/light_intensity = 2 //how powerful the emitted light is when used. - var/burned_fuel_for = 0 //when fuel was last removed - heat = 3800 - toolspeed = 1 - -/obj/item/weldingtool/Initialize() - . = ..() - create_reagents(max_fuel) - reagents.add_reagent("welding_fuel", max_fuel) - update_icon() - - -/obj/item/weldingtool/proc/update_torch() - if(welding) - add_overlay("[initial(icon_state)]-on") - item_state = "[initial(item_state)]1" - else - item_state = "[initial(item_state)]" - - -/obj/item/weldingtool/update_icon() - cut_overlays() - if(change_icons) - var/ratio = get_fuel() / max_fuel - ratio = Ceiling(ratio*4) * 25 - add_overlay("[initial(icon_state)][ratio]") - update_torch() - return - - -/obj/item/weldingtool/process() - switch(welding) - if(0) - force = 3 - damtype = "brute" - update_icon() - if(!can_off_process) - STOP_PROCESSING(SSobj, src) - return - //Welders left on now use up fuel, but lets not have them run out quite that fast - if(1) - force = 15 - damtype = "fire" - ++burned_fuel_for - if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) - remove_fuel(1) - update_icon() - - //This is to start fires. process() is only called if the welder is on. - open_flame() - - -/obj/item/weldingtool/suicide_act(mob/user) - user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!") - return (FIRELOSS) - - -/obj/item/weldingtool/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) - flamethrower_screwdriver(I, user) - else if(istype(I, /obj/item/stack/rods)) - flamethrower_rods(I, user) - else - return ..() - - -/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user) - if(!istype(H)) - return ..() - - var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - - if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != INTENT_HARM) - if(src.remove_fuel(1)) - playsound(loc, usesound, 50, 1) - if(user == H) - user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") - if(!do_mob(user, H, 50)) - return - item_heal_robotic(H, user, 15, 0) - else - return ..() - - -/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) - if(!proximity) return - - if(welding) - remove_fuel(1) - var/turf/location = get_turf(user) - location.hotspot_expose(700, 50, 1) - if(get_fuel() <= 0) - set_light(0) - - if(isliving(O)) - var/mob/living/L = O - if(L.IgniteMob()) - message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire") - log_game("[key_name(user)] set [key_name(L)] on fire") - - -/obj/item/weldingtool/attack_self(mob/user) - switched_on(user) - if(welding) - set_light(light_intensity) - - update_icon() - - -//Returns the amount of fuel in the welder -/obj/item/weldingtool/proc/get_fuel() - return reagents.get_reagent_amount("welding_fuel") - - -//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use() -/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null) - if(!welding || !check_fuel()) - return 0 - if(amount) - burned_fuel_for = 0 - if(get_fuel() >= amount) - reagents.remove_reagent("welding_fuel", amount) - check_fuel() - if(M) - M.flash_act(light_intensity) +/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects) + if(active) + if(bad_effects) + try_use_power(MIN_CLOCKCULT_POWER*4) + visible_message("[src] emits an airy chuckling sound and falls dark!") + toggle() return TRUE - else - if(M) - to_chat(M, "You need more welding fuel to complete this task!") - return FALSE +/obj/structure/destructible/clockwork/powered/prolonging_prism/attack_hand(mob/living/user) + if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user)) + if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE) + to_chat(user, "You break [src] apart, refunding some of the components used.") + for(var/i in component_refund) + generate_cache_component(i, src) + take_damage(max_integrity) + return 0 + if(active) + return 0 + var/turf/T = get_turf(src) + if(!T || T.z != ZLEVEL_STATION) + to_chat(user, "[src] must be on the station to function!") + return 0 + if(SSshuttle.emergency.mode != SHUTTLE_CALL) + to_chat(user, "No emergency shuttles are attempting to arrive at the station!") + return 0 + if(!try_use_power(get_delay_cost())) + to_chat(user, "[src] needs more power to function!") + return 0 + delay_cost += delay_cost_increase + delay_remaining += PRISM_DELAY_DURATION + toggle(0, user) -//Turns off the welder if there is no more fuel (does this really need to be its own proc?) -/obj/item/weldingtool/proc/check_fuel(mob/user) - if(get_fuel() <= 0 && welding) - switched_on(user) - update_icon() - //mob icon update - if(ismob(loc)) - var/mob/M = loc - M.update_inv_hands(0) - - return 0 - return 1 - -//Switches the welder on -/obj/item/weldingtool/proc/switched_on(mob/user) - if(!status) - to_chat(user, "[src] can't be turned on while unsecured!") +/obj/structure/destructible/clockwork/powered/prolonging_prism/process() + var/turf/own_turf = get_turf(src) + if(SSshuttle.emergency.mode != SHUTTLE_CALL || delay_remaining <= 0 || !own_turf || own_turf.z != ZLEVEL_STATION) + forced_disable(FALSE) return - welding = !welding - if(welding) - if(get_fuel() >= 1) - to_chat(user, "You switch [src] on.") - playsound(loc, acti_sound, 50, 1) - force = 15 - damtype = "fire" - hitsound = 'sound/items/welder.ogg' - update_icon() - START_PROCESSING(SSobj, src) + . = ..() + var/delay_amount = 40 + delay_remaining -= delay_amount + var/efficiency = get_efficiency_mod() + SSshuttle.emergency.setTimer(SSshuttle.emergency.timeLeft(1) + (delay_amount * efficiency)) + var/highest_y + var/highest_x + var/lowest_y + var/lowest_x + var/list/prism_turfs = list() + for(var/t in SSshuttle.emergency.ripple_area(SSshuttle.getDock("emergency_home"))) + prism_turfs[t] = TRUE + var/turf/T = t + if(!highest_y || T.y > highest_y) + highest_y = T.y + if(!highest_x || T.x > highest_x) + highest_x = T.x + if(!lowest_y || T.y < lowest_y) + lowest_y = T.y + if(!lowest_x || T.x < lowest_x) + lowest_x = T.x + var/mean_y = Lerp(lowest_y, highest_y) + var/mean_x = Lerp(lowest_x, highest_x) + if(prob(50)) + mean_y = Ceiling(mean_y) + else + mean_y = Floor(mean_y) + if(prob(50)) + mean_x = Ceiling(mean_x) + else + mean_x = Floor(mean_x) + var/turf/semi_random_center_turf = locate(mean_x, mean_y, ZLEVEL_STATION) + for(var/t in getline(src, semi_random_center_turf)) + prism_turfs[t] = TRUE + var/placement_style = prob(50) + for(var/t in prism_turfs) + var/turf/T = t + if(placement_style) + if(IsOdd(T.x + T.y)) + seven_random_hexes(T, efficiency) + else if(prob(50 * efficiency)) + new /obj/effect/temp_visual/ratvar/prolonging_prism(T) else - to_chat(user, "You need more fuel!") - switched_off(user) - else - to_chat(user, "You switch [src] off.") - playsound(loc, deac_sound, 50, 1) - switched_off(user) + if(IsEven(T.x + T.y)) + seven_random_hexes(T, efficiency) + else if(prob(50 * efficiency)) + new /obj/effect/temp_visual/ratvar/prolonging_prism(T) + CHECK_TICK //we may be going over a hell of a lot of turfs -//Switches the welder off -/obj/item/weldingtool/proc/switched_off(mob/user) - welding = 0 - set_light(0) +/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/get_delay_cost() + return Floor(delay_cost, MIN_CLOCKCULT_POWER) - force = 3 - damtype = "brute" - hitsound = "swing_hit" - update_icon() - - -/obj/item/weldingtool/examine(mob/user) - ..() - to_chat(user, "It contains [get_fuel()] unit\s of fuel out of [max_fuel].") - -/obj/item/weldingtool/is_hot() - return welding * heat - -//Returns whether or not the welding tool is currently on. -/obj/item/weldingtool/proc/isOn() - return welding - - -/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user) - if(welding) - to_chat(user, "Turn it off first!") - return - status = !status - if(status) - to_chat(user, "You resecure [src].") - else - to_chat(user, "[src] can now be attached and modified.") - add_fingerprint(user) - -/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) - if(!status) - var/obj/item/stack/rods/R = I - if (R.use(1)) - var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc) - if(!remove_item_from_storage(F)) - user.transferItemToLoc(src, F, TRUE) - F.weldtool = src - add_fingerprint(user) - to_chat(user, "You add a rod to a welder, starting to build a flamethrower.") - user.put_in_hands(F) - else - to_chat(user, "You need one rod to start building a flamethrower!") - -/obj/item/weldingtool/ignition_effect(atom/A, mob/user) - if(welding && remove_fuel(1, user)) - . = "[user] casually lights [A] with [src], what a badass." - else - . = "" - -/obj/item/weldingtool/largetank - name = "industrial welding tool" - desc = "A slightly larger welder with a larger tank." - icon_state = "indwelder" - max_fuel = 40 - materials = list(MAT_GLASS=60) - origin_tech = "engineering=2;plasmatech=2" - -/obj/item/weldingtool/largetank/cyborg - name = "integrated welding tool" - desc = "An advanced welder designed to be used in robotic systems." - toolspeed = 0.5 - -/obj/item/weldingtool/largetank/flamethrower_screwdriver() - return - - -/obj/item/weldingtool/mini - name = "emergency welding tool" - desc = "A miniature welder used during emergencies." - icon_state = "miniwelder" - max_fuel = 10 - w_class = WEIGHT_CLASS_TINY - materials = list(MAT_METAL=30, MAT_GLASS=10) - change_icons = 0 - -/obj/item/weldingtool/mini/flamethrower_screwdriver() - return - -/obj/item/weldingtool/abductor - name = "alien welding tool" - desc = "An alien welding tool. Whatever fuel it uses, it never runs out." - icon = 'icons/obj/abductor.dmi' - icon_state = "welder" - toolspeed = 0.1 - light_intensity = 0 - change_icons = 0 - origin_tech = "plasmatech=5;engineering=5;abductor=3" - -/obj/item/weldingtool/abductor/process() - if(get_fuel() <= max_fuel) - reagents.add_reagent("welding_fuel", 1) - ..() - -/obj/item/weldingtool/hugetank - name = "upgraded industrial welding tool" - desc = "An upgraded welder based of the industrial welder." - icon_state = "upindwelder" - item_state = "upindwelder" - max_fuel = 80 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "engineering=3;plasmatech=2" - -/obj/item/weldingtool/experimental - name = "experimental welding tool" - desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." - icon_state = "exwelder" - item_state = "exwelder" - max_fuel = 40 - materials = list(MAT_METAL=70, MAT_GLASS=120) - origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4" - var/last_gen = 0 - change_icons = 0 - can_off_process = 1 - light_intensity = 1 - toolspeed = 0.5 - var/nextrefueltick = 0 - -/obj/item/weldingtool/experimental/brass - name = "brass welding tool" - desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "brasswelder" - item_state = "brasswelder" - - -/obj/item/weldingtool/experimental/process() - ..() - if(get_fuel() < max_fuel && nextrefueltick < world.time) - nextrefueltick = world.time + 10 - reagents.add_reagent("welding_fuel", 1) - - -/* - * Crowbar - */ - -/obj/item/crowbar - name = "pocket crowbar" - desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors." - icon = 'icons/obj/tools.dmi' - icon_state = "crowbar" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - usesound = 'sound/items/crowbar.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT - force = 5 - throwforce = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - origin_tech = "engineering=1;combat=1" - attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") - toolspeed = 1 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30) - -/obj/item/crowbar/suicide_act(mob/user) - user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/red - icon_state = "crowbar_red" - force = 8 - -/obj/item/crowbar/brass - name = "brass crowbar" - desc = "A brass crowbar. It feels faintly warm to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "crowbar_brass" - toolspeed = 0.5 - -/obj/item/crowbar/abductor - name = "alien crowbar" - desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." - icon = 'icons/obj/abductor.dmi' - usesound = 'sound/weapons/sonic_jackhammer.ogg' - icon_state = "crowbar" - toolspeed = 0.1 - origin_tech = "combat=4;engineering=4;abductor=3" - -/obj/item/crowbar/large - name = "crowbar" - desc = "It's a big crowbar. It doesn't fit in your pockets, because it's big." - force = 12 - w_class = WEIGHT_CLASS_NORMAL - throw_speed = 3 - throw_range = 3 - materials = list(MAT_METAL=70) - icon_state = "crowbar_large" - item_state = "crowbar" - toolspeed = 0.5 - -/obj/item/crowbar/cyborg - name = "hydraulic crowbar" - desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." - usesound = 'sound/items/jaws_pry.ogg' - force = 10 - toolspeed = 0.5 - -/obj/item/crowbar/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a prying head." - icon_state = "jaws_pry" - item_state = "jawsoflife" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" - usesound = 'sound/items/jaws_pry.ogg' - force = 15 - toolspeed = 0.25 - -/obj/item/crowbar/power/suicide_act(mob/user) - user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1) - return (BRUTELOSS) - -/obj/item/crowbar/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power - to_chat(user, "You attach the cutting jaws to [src].") - qdel(src) - user.put_in_active_hand(cutjaws) - -#undef WELDER_FUEL_BURN_INTERVAL +/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/seven_random_hexes(turf/T, efficiency) + var/static/list/hex_states = list("prismhex1", "prismhex2", "prismhex3", "prismhex4", "prismhex5", "prismhex6", "prismhex7") + var/mutable_appearance/hex_combo + for(var/n in hex_states) //BUILD ME A HEXAGON + if(prob(50 * efficiency)) + if(!hex_combo) + hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER) + else + hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)) + if(hex_combo) //YOU BUILT A HEXAGON + hex_combo.pixel_x = -16 + hex_combo.pixel_y = -16 + hex_combo.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + hex_combo.plane = GAME_PLANE + new /obj/effect/temp_visual/ratvar/prolonging_prism(T, hex_combo) From 447937477e391c299195cf418fdc6c33f7350664 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:50:49 -0500 Subject: [PATCH 051/102] more oopsies --- code/game/objects/items/weaponry.dm | 566 ---------------------------- 1 file changed, 566 deletions(-) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 443518ec0a..17bbb0a12f 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -23,572 +23,6 @@ else M.visible_message("[M] has been banned FOR NO REISIN by [user]", "You have been banned FOR NO REISIN by [user]", "you hear a banhammer banning someone") - playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much - -/obj/item/sord - name = "\improper SORD" - desc = "This thing is so unspeakably shitty you are having a hard time even holding it." - icon_state = "sord" - item_state = "sord" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - slot_flags = SLOT_BELT - force = 2 - throwforce = 1 - w_class = WEIGHT_CLASS_NORMAL - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - -/obj/item/sord/suicide_act(mob/user) - user.visible_message("[user] is trying to impale [user.p_them()]self with [src]! It might be a suicide attempt if it weren't so shitty.", \ - "You try to impale yourself with [src], but it's USELESS...") - return SHAME - -/obj/item/claymore - name = "claymore" - desc = "What are you standing around staring at this for? Get to killing!" - icon_state = "claymore" - item_state = "claymore" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - hitsound = 'sound/weapons/bladeslice.ogg' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT | SLOT_BACK - force = 40 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 - sharpness = IS_SHARP - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/claymore/suicide_act(mob/user) - user.visible_message("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return(BRUTELOSS) - -/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS - desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." - flags_1 = CONDUCT_1 | NODROP_1 | DROPDEL_1 - slot_flags = null - block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY - luminosity = 3 - attack_verb = list("brutalized", "eviscerated", "disemboweled", "hacked", "carved", "cleaved") //ONLY THE MOST VISCERAL ATTACK VERBS - var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE - var/obj/item/disk/nuclear/nuke_disk //OUR STORED NUKE DISK - -/obj/item/claymore/highlander/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/item/claymore/highlander/Destroy() - if(nuke_disk) - nuke_disk.forceMove(get_turf(src)) - nuke_disk.visible_message("The nuke disk is vulnerable!") - nuke_disk = null - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/claymore/highlander/process() - if(ishuman(loc)) - var/mob/living/carbon/human/H = loc - loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS) - H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS - else - if(!admin_spawned) - qdel(src) - - -/obj/item/claymore/highlander/pickup(mob/living/user) - to_chat(user, "The power of Scotland protects you! You are shielded from all stuns and knockdowns.") - user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!") - user.status_flags += IGNORESLOWDOWN - -/obj/item/claymore/highlander/dropped(mob/living/user) - user.status_flags -= IGNORESLOWDOWN - qdel(src) //If this ever happens, it's because you lost an arm - -/obj/item/claymore/highlander/examine(mob/user) - ..() - to_chat(user, "It has [!notches ? "nothing" : "[notches] notches"] scratched into the blade.") - if(nuke_disk) - to_chat(user, "It's holding the nuke disk!") - -/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) - . = ..() - if(target && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") - user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES - add_notch(user) - target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") - target.dust() - -/obj/item/claymore/highlander/attack_self(mob/living/user) - var/closest_victim - var/closest_distance = 255 - for(var/mob/living/carbon/human/H in GLOB.player_list - user) - if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) - closest_victim = H - if(!closest_victim) - to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") - return - to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].") - -/obj/item/claymore/highlander/IsReflect() - return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME? - -/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE - notches++ - force++ - var/new_name = name - switch(notches) - if(1) - to_chat(user, "Your first kill - hopefully one of many. You scratch a notch into [src]'s blade.") - to_chat(user, "You feel your fallen foe's soul entering your blade, restoring your wounds!") - new_name = "notched claymore" - if(2) - to_chat(user, "Another falls before you. Another soul fuses with your own. Another notch in the blade.") - new_name = "double-notched claymore" - add_atom_colour(rgb(255, 235, 235), ADMIN_COLOUR_PRIORITY) - if(3) - to_chat(user, "You're beginning to relish the thrill of battle.") - new_name = "triple-notched claymore" - add_atom_colour(rgb(255, 215, 215), ADMIN_COLOUR_PRIORITY) - if(4) - to_chat(user, "You've lost count of how many you've killed.") - new_name = "many-notched claymore" - add_atom_colour(rgb(255, 195, 195), ADMIN_COLOUR_PRIORITY) - if(5) - to_chat(user, "Five voices now echo in your mind, cheering the slaughter.") - new_name = "battle-tested claymore" - add_atom_colour(rgb(255, 175, 175), ADMIN_COLOUR_PRIORITY) - if(6) - to_chat(user, "Is this what the vikings felt like? Visions of glory fill your head as you slay your sixth foe.") - new_name = "battle-scarred claymore" - add_atom_colour(rgb(255, 155, 155), ADMIN_COLOUR_PRIORITY) - if(7) - to_chat(user, "Kill. Butcher. Conquer.") - new_name = "vicious claymore" - add_atom_colour(rgb(255, 135, 135), ADMIN_COLOUR_PRIORITY) - if(8) - to_chat(user, "IT NEVER GETS OLD. THE SCREAMING. THE BLOOD AS IT SPRAYS ACROSS YOUR FACE.") - new_name = "bloodthirsty claymore" - add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY) - if(9) - to_chat(user, "ANOTHER ONE FALLS TO YOUR BLOWS. ANOTHER WEAKLING UNFIT TO LIVE.") - new_name = "gore-stained claymore" - add_atom_colour(rgb(255, 95, 95), ADMIN_COLOUR_PRIORITY) - if(10) - user.visible_message("[user]'s eyes light up with a vengeful fire!", \ - "YOU FEEL THE POWER OF VALHALLA FLOWING THROUGH YOU! THERE CAN BE ONLY ONE!!!") - user.update_icons() - new_name = "GORE-DRENCHED CLAYMORE OF [pick("THE WHIMSICAL SLAUGHTER", "A THOUSAND SLAUGHTERED CATTLE", "GLORY AND VALHALLA", "ANNIHILATION", "OBLITERATION")]" - icon_state = "claymore_valhalla" - item_state = "cultblade" - remove_atom_colour(ADMIN_COLOUR_PRIORITY) - - name = new_name - playsound(user, 'sound/items/screwdriver2.ogg', 50, 1) - -/obj/item/katana - name = "katana" - desc = "Woefully underpowered in D20" - icon_state = "katana" - item_state = "katana" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = SLOT_BELT | SLOT_BACK - force = 40 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 - sharpness = IS_SHARP - max_integrity = 200 - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/katana/cursed - slot_flags = null - -/obj/item/katana/suicide_act(mob/user) - user.visible_message("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!") - return(BRUTELOSS) - -/obj/item/wirerod - name = "wired rod" - desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." - icon_state = "wiredrod" - item_state = "rods" - flags_1 = CONDUCT_1 - force = 9 - throwforce = 10 - w_class = WEIGHT_CLASS_NORMAL - materials = list(MAT_METAL=1150, MAT_GLASS=75) - attack_verb = list("hit", "bludgeoned", "whacked", "bonked") - -/obj/item/wirerod/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/shard)) - var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear - - remove_item_from_storage(user) - qdel(I) - qdel(src) - - user.put_in_hands(S) - to_chat(user, "You fasten the glass shard to the top of the rod with the cable.") - - else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags_1 & NODROP_1)) - var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod - - remove_item_from_storage(user) - - to_chat(user, "You fasten [I] to the top of the rod with the cable.") - - qdel(I) - qdel(src) - - user.put_in_hands(P) - else - return ..() - - -/obj/item/throwing_star - name = "throwing star" - desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" - icon_state = "throwingstar" - item_state = "eshield0" - lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' - force = 2 - throwforce = 20 //This is never used on mobs since this has a 100% embed chance. - throw_speed = 4 - embedded_pain_multiplier = 4 - w_class = WEIGHT_CLASS_SMALL - embed_chance = 100 - embedded_fall_chance = 0 //Hahaha! - sharpness = IS_SHARP - materials = list(MAT_METAL=500, MAT_GLASS=500) - resistance_flags = FIRE_PROOF - - -/obj/item/switchblade - name = "switchblade" - icon_state = "switchblade" - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - desc = "A sharp, concealable, spring-loaded knife." - flags_1 = CONDUCT_1 - force = 3 - w_class = WEIGHT_CLASS_SMALL - throwforce = 5 - throw_speed = 3 - throw_range = 6 - materials = list(MAT_METAL=12000) - origin_tech = "engineering=3;combat=2" - hitsound = 'sound/weapons/genhit.ogg' - attack_verb = list("stubbed", "poked") - resistance_flags = FIRE_PROOF - var/extended = 0 - -/obj/item/switchblade/attack_self(mob/user) - extended = !extended - playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1) - if(extended) - force = 20 - w_class = WEIGHT_CLASS_NORMAL - throwforce = 23 - icon_state = "switchblade_ext" - attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP - else - force = 3 - w_class = WEIGHT_CLASS_SMALL - throwforce = 5 - icon_state = "switchblade" - attack_verb = list("stubbed", "poked") - hitsound = 'sound/weapons/genhit.ogg' - sharpness = IS_BLUNT - -/obj/item/switchblade/suicide_act(mob/user) - user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return (BRUTELOSS) - -/obj/item/phone - name = "red phone" - desc = "Should anything ever go wrong..." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "red_phone" - force = 3 - throwforce = 2 - throw_speed = 3 - throw_range = 4 - w_class = WEIGHT_CLASS_SMALL - attack_verb = list("called", "rang") - hitsound = 'sound/weapons/ring.ogg' - -/obj/item/phone/suicide_act(mob/user) - if(locate(/obj/structure/chair/stool) in user.loc) - user.visible_message("[user] begins to tie a noose with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") - else - user.visible_message("[user] is strangling [user.p_them()]self with [src]'s cord! It looks like [user.p_theyre()] trying to commit suicide!") - return(OXYLOSS) - -/obj/item/cane - name = "cane" - desc = "A cane used by a true gentleman. Or a clown." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "cane" - item_state = "stick" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 5 - throwforce = 5 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=50) - attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") - -/obj/item/staff - name = "wizard staff" - desc = "Apparently a staff used by the wizard." - icon = 'icons/obj/wizard.dmi' - icon_state = "staff" - lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' - force = 3 - throwforce = 5 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - armour_penetration = 100 - attack_verb = list("bludgeoned", "whacked", "disciplined") - resistance_flags = FLAMMABLE - -/obj/item/staff/broom - name = "broom" - desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." - icon = 'icons/obj/wizard.dmi' - icon_state = "broom" - resistance_flags = FLAMMABLE - -/obj/item/staff/stick - name = "stick" - desc = "A great tool to drag someone else's drinks across the bar." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "stick" - item_state = "stick" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 3 - throwforce = 5 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - -/obj/item/ectoplasm - name = "ectoplasm" - desc = "spooky" - gender = PLURAL - icon = 'icons/obj/wizard.dmi' - icon_state = "ectoplasm" - -/obj/item/ectoplasm/suicide_act(mob/user) - user.visible_message("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane.") - return (OXYLOSS) - -/obj/item/mounted_chainsaw - name = "mounted chainsaw" - desc = "A chainsaw that has replaced your arm." - icon_state = "chainsaw_on" - item_state = "mounted_chainsaw" - lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' - flags_1 = NODROP_1 | ABSTRACT_1 | DROPDEL_1 - w_class = WEIGHT_CLASS_HUGE - force = 21 - throwforce = 0 - throw_range = 0 - throw_speed = 0 - sharpness = IS_SHARP - attack_verb = list("sawed", "torn", "cut", "chopped", "diced") - hitsound = 'sound/weapons/chainsawhit.ogg' - -/obj/item/mounted_chainsaw/Destroy() - var/obj/item/bodypart/part - new /obj/item/twohanded/required/chainsaw(get_turf(src)) - if(iscarbon(loc)) - var/mob/living/carbon/holder = loc - var/index = holder.get_held_index_of_item(src) - if(index) - part = holder.hand_bodyparts[index] - . = ..() - if(part) - part.drop_limb() - -/obj/item/statuebust - name = "bust" - desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it - icon = 'icons/obj/statue.dmi' - icon_state = "bust" - force = 15 - throwforce = 10 - throw_speed = 5 - throw_range = 2 - attack_verb = list("busted") - -/obj/item/tailclub - name = "tail club" - desc = "For the beating to death of lizards with their own tails." - icon_state = "tailclub" - force = 14 - throwforce = 1 // why are you throwing a club do you even weapon - throw_speed = 1 - throw_range = 1 - attack_verb = list("clubbed", "bludgeoned") - -/obj/item/melee/chainofcommand/tailwhip - name = "liz o' nine tails" - desc = "A whip fashioned from the severed tails of lizards." - icon_state = "tailwhip" - origin_tech = "engineering=3;combat=3;biotech=3" - needs_permit = 0 - -/obj/item/melee/chainofcommand/tailwhip/kitty - name = "cat o' nine tails" - desc = "A whip fashioned from the severed tails of cats." - icon_state = "catwhip" - -/obj/item/melee/skateboard - name = "skateboard" - desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon." - icon_state = "skateboard" - item_state = "skateboard" - force = 12 - throwforce = 4 - w_class = WEIGHT_CLASS_HUGE - attack_verb = list("smacked", "whacked", "slammed", "smashed") - -/obj/item/melee/skateboard/attack_self(mob/user) - new /obj/vehicle/scooter/skateboard(get_turf(user)) - qdel(src) - -/obj/item/melee/baseball_bat - name = "baseball bat" - desc = "There ain't a skull in the league that can withstand a swatter." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "baseball_bat" - item_state = "baseball_bat" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 10 - throwforce = 12 - attack_verb = list("beat", "smacked") - w_class = WEIGHT_CLASS_HUGE - var/homerun_ready = 0 - var/homerun_able = 0 - -/obj/item/melee/baseball_bat/homerun - name = "home run bat" - desc = "This thing looks dangerous... Dangerously good at baseball, that is." - homerun_able = 1 - -/obj/item/melee/baseball_bat/attack_self(mob/user) - if(!homerun_able) - ..() - return - if(homerun_ready) - to_chat(user, "You're already ready to do a home run!") - ..() - return - to_chat(user, "You begin gathering strength...") - playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1) - if(do_after(user, 90, target = src)) - to_chat(user, "You gather power! Time for a home run!") - homerun_ready = 1 - ..() - -/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user) - . = ..() - var/atom/throw_target = get_edge_target_turf(target, user.dir) - if(homerun_ready) - user.visible_message("It's a home run!") - target.throw_at(throw_target, rand(8,10), 14, user) - target.ex_act(EXPLODE_HEAVY) - playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) - homerun_ready = 0 - return - else if(!target.anchored) - target.throw_at(throw_target, rand(1,2), 7, user) - -/obj/item/melee/baseball_bat/ablative - name = "metal baseball bat" - desc = "This bat is made of highly reflective, highly armored material." - icon_state = "baseball_bat_metal" - item_state = "baseball_bat_metal" - force = 12 - throwforce = 15 - -/obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers - var/picksound = rand(1,2) - var/turf = get_turf(src) - if(picksound == 1) - playsound(turf, 'sound/weapons/effects/batreflect1.ogg', 50, 1) - if(picksound == 2) - playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) - return 1 - -/obj/item/melee/flyswatter - name = "flyswatter" - desc = "Useful for killing insects of all sizes." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "flyswatter" - item_state = "flyswatter" - lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' - force = 1 - throwforce = 1 - attack_verb = list("swatted", "smacked") - hitsound = 'sound/effects/snap.ogg' - w_class = WEIGHT_CLASS_SMALL - //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. - var/list/strong_against - -/obj/item/melee/flyswatter/Initialize() - . = ..() - strong_against = typecacheof(list( - /mob/living/simple_animal/hostile/poison/bees/, - /mob/living/simple_animal/butterfly, - /mob/living/simple_animal/cockroach, - /obj/item/queen_bee - )) - - -/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag) - if(proximity_flag) - if(is_type_in_typecache(target, strong_against)) - new /obj/effect/decal/cleanable/deadcockroach(get_turf(target)) - to_chat(user, "You easily splat the [target].") - if(istype(target, /mob/living/)) - var/mob/living/bug = target - bug.death(1) - else - qdel(target) - -/obj/item/circlegame - name = "circled hand" - desc = "If somebody looks at this while it's below your waist, you get to bop them." - icon_state = "madeyoulook" - force = 0 - throwforce = 0 - flags_1 = DROPDEL_1 | ABSTRACT_1 - attack_verb = list("bopped") - -/obj/item/proc/can_trigger_gun(mob/living/user) - if(!user.can_use_guns(src)) - return FALSE playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much /obj/item/sord From 9e0cb0fa7c6a9a484f6a2eb82292bcbfc3eb5c61 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 11 Sep 2017 13:53:18 -0500 Subject: [PATCH 052/102] Update datumvars.dm --- code/datums/datumvars.dm | 2282 +++++++++++++++++++------------------- 1 file changed, 1138 insertions(+), 1144 deletions(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index cb9be25f05..6df724c737 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -1,492 +1,490 @@ -/datum - var/var_edited = FALSE //Warrenty void if seal is broken - var/fingerprintslast = null - -/datum/proc/can_vv_get(var_name) - return TRUE - -/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited - switch(var_name) - if ("vars") - return FALSE - if ("var_edited") - return FALSE - var_edited = TRUE - vars[var_name] = var_value - -/datum/proc/vv_get_var(var_name) - switch(var_name) - if ("vars") - return debug_variable(var_name, list(), 0, src) - return debug_variable(var_name, vars[var_name], 0, src) - -//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down +/datum + var/var_edited = FALSE //Warrenty void if seal is broken + var/fingerprintslast = null + +/datum/proc/can_vv_get(var_name) + return TRUE + +/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited + switch(var_name) + if ("vars") + return FALSE + if ("var_edited") + return FALSE + var_edited = TRUE + vars[var_name] = var_value + +/datum/proc/vv_get_var(var_name) + switch(var_name) + if ("vars") + return debug_variable(var_name, list(), 0, src) + return debug_variable(var_name, vars[var_name], 0, src) + +//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down //add separaters by doing . += "---" -<<<<<<< HEAD -/datum/proc/vv_get_dropdown() - . = list() - . += "---" - .["Call Proc"] = "?_src_=vars;proc_call=\ref[src]" - .["Mark Object"] = "?_src_=vars;mark_object=\ref[src]" - .["Delete"] = "?_src_=vars;delete=\ref[src]" - - -/datum/proc/on_reagent_change() - return - - -/client/proc/debug_variables(datum/D in world) - set category = "Debug" - set name = "View Variables" - //set src in world - var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. - - if(!usr.client || !usr.client.holder) - to_chat(usr, "You need to be an administrator to access this.") - return - - if(!D) - return - - var/islist = islist(D) - if (!islist && !istype(D)) - return - - var/title = "" - var/refid = "\ref[D]" - var/icon/sprite - var/hash - - var/type = /list - if (!islist) - type = D.type - - - +/datum/proc/vv_get_dropdown() + . = list() + . += "---" + .["Call Proc"] = "?_src_=vars;proc_call=\ref[src]" + .["Mark Object"] = "?_src_=vars;mark_object=\ref[src]" + .["Delete"] = "?_src_=vars;delete=\ref[src]" + + +/datum/proc/on_reagent_change() + return + + +/client/proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + //set src in world + var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. + + if(!usr.client || !usr.client.holder) + to_chat(usr, "You need to be an administrator to access this.") + return + + if(!D) + return + + var/islist = islist(D) + if (!islist && !istype(D)) + return + + var/title = "" + var/refid = "\ref[D]" + var/icon/sprite + var/hash + + var/type = /list + if (!islist) + type = D.type + + + if(istype(D, /atom)) - var/atom/AT = D - if(AT.icon && AT.icon_state) - sprite = new /icon(AT.icon, AT.icon_state) - hash = md5(AT.icon) - hash = md5(hash + AT.icon_state) - usr << browse_rsc(sprite, "vv[hash].png") - - title = "[D] (\ref[D]) = [type]" - - var/sprite_text - if(sprite) - sprite_text = "" - var/list/atomsnowflake = list() - + var/atom/AT = D + if(AT.icon && AT.icon_state) + sprite = new /icon(AT.icon, AT.icon_state) + hash = md5(AT.icon) + hash = md5(hash + AT.icon_state) + usr << browse_rsc(sprite, "vv[hash].png") + + title = "[D] (\ref[D]) = [type]" + + var/sprite_text + if(sprite) + sprite_text = "" + var/list/atomsnowflake = list() + if(istype(D, /atom)) - var/atom/A = D - if(isliving(A)) - atomsnowflake += "[D]" - if(A.dir) - atomsnowflake += "
    << [dir2text(A.dir)] >>" - var/mob/living/M = A - atomsnowflake += {" -
    [M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"] -
    - BRUTE:[M.getBruteLoss()] - FIRE:[M.getFireLoss()] - TOXIN:[M.getToxLoss()] - OXY:[M.getOxyLoss()] - CLONE:[M.getCloneLoss()] - BRAIN:[M.getBrainLoss()] - STAMINA:[M.getStaminaLoss()] - - "} - else - atomsnowflake += "[D]" - if(A.dir) - atomsnowflake += "
    << [dir2text(A.dir)] >>" - else - atomsnowflake += "[D]" - - var/formatted_type = "[type]" - if(length(formatted_type) > 25) - var/middle_point = length(formatted_type) / 2 - var/splitpoint = findtext(formatted_type,"/",middle_point) - if(splitpoint) - formatted_type = "[copytext(formatted_type,1,splitpoint)]
    [copytext(formatted_type,splitpoint)]" - else - formatted_type = "Type too long" //No suitable splitpoint (/) found. - - var/marked - if(holder.marked_datum && holder.marked_datum == D) - marked = "
    Marked Object" - var/varedited_line = "" - if(!islist && D.var_edited) - varedited_line = "
    Var Edited" - - var/list/dropdownoptions = list() - if (islist) - dropdownoptions = list( - "---", - "Add Item" = "?_src_=vars;listadd=[refid]", - "Remove Nulls" = "?_src_=vars;listnulls=[refid]", - "Remove Dupes" = "?_src_=vars;listdupes=[refid]", - "Set len" = "?_src_=vars;listlen=[refid]", - "Shuffle" = "?_src_=vars;listshuffle=[refid]" - ) - else - dropdownoptions = D.vv_get_dropdown() - var/list/dropdownoptions_html = list() - - for (var/name in dropdownoptions) - var/link = dropdownoptions[name] - if (link) - dropdownoptions_html += "" - else - dropdownoptions_html += "" - - var/list/names = list() - if (!islist) - for (var/V in D.vars) - names += V - sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. - - var/list/variable_html = list() - if (islist) - var/list/L = D - for (var/i in 1 to L.len) - var/key = L[i] - var/value - if (IS_NORMAL_LIST(L) && !isnum(key)) - value = L[key] - variable_html += debug_variable(i, value, 0, D) - else - - names = sortList(names) - for (var/V in names) - if(D.can_vv_get(V)) - variable_html += D.vv_get_var(V) - - var/html = {" - - - [title] - - - - -