diff --git a/ByondPOST.dll b/ByondPOST.dll index 93dff79d7f6..f94ea657653 100644 Binary files a/ByondPOST.dll and b/ByondPOST.dll differ diff --git a/baystation12.dme b/baystation12.dme index 18adf991bb3..91a9b169831 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -53,6 +53,7 @@ #include "code\_helpers\matrices.dm" #include "code\_helpers\mobs.dm" #include "code\_helpers\names.dm" +#include "code\_helpers\overlay.dm" #include "code\_helpers\sanitize_values.dm" #include "code\_helpers\spawn_sync.dm" #include "code\_helpers\text.dm" @@ -172,6 +173,7 @@ #include "code\datums\mind.dm" #include "code\datums\mixed.dm" #include "code\datums\modules.dm" +#include "code\datums\scheduled_task.dm" #include "code\datums\server_greeting.dm" #include "code\datums\sun.dm" #include "code\datums\supplypacks.dm" @@ -336,6 +338,7 @@ #include "code\game\gamemodes\setupgame.dm" #include "code\game\gamemodes\calamity\calamity.dm" #include "code\game\gamemodes\changeling\changeling.dm" +#include "code\game\gamemodes\changeling\changeling_items.dm" #include "code\game\gamemodes\changeling\changeling_powers.dm" #include "code\game\gamemodes\changeling\modularchangling.dm" #include "code\game\gamemodes\cult\cult.dm" @@ -467,6 +470,8 @@ #include "code\game\machinery\wall_frames.dm" #include "code\game\machinery\washing_machine.dm" #include "code\game\machinery\wishgranter.dm" +#include "code\game\machinery\abstract\abstract.dm" +#include "code\game\machinery\abstract\intercom_listener.dm" #include "code\game\machinery\atmoalter\area_atmos_computer.dm" #include "code\game\machinery\atmoalter\canister.dm" #include "code\game\machinery\atmoalter\meter.dm" @@ -999,10 +1004,7 @@ #include "code\modules\alarm\fire_alarm.dm" #include "code\modules\alarm\motion_alarm.dm" #include "code\modules\alarm\power_alarm.dm" -#include "code\modules\antag_contest\contest_defines.dm" -#include "code\modules\antag_contest\contest_helpers.dm" -#include "code\modules\antag_contest\contest_objective.dm" -#include "code\modules\antag_contest\contest_verbs.dm" +#include "code\modules\antag_contest\sol_items.dm" #include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\helpers.dm" diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index a032b747d96..05488c719af 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -250,7 +250,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 1832ea8784e..c6ef3e201da 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -229,7 +229,7 @@ Thus, the two variables affect pump operation are set in New(): return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index ac7d88301af..b62a63da903 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -92,7 +92,7 @@ return 1 user << "You begin to unfasten \the [src]..." playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, 40)) + if(do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/portables_connector.dm b/code/ATMOSPHERICS/components/portables_connector.dm index 4f6473fccf3..72eedd3d7f1 100644 --- a/code/ATMOSPHERICS/components/portables_connector.dm +++ b/code/ATMOSPHERICS/components/portables_connector.dm @@ -146,7 +146,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index e78d777cabc..3506c3a2a75 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -139,7 +139,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index a163c122f01..48accdd6dbd 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -114,7 +114,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/tvalve.dm b/code/ATMOSPHERICS/components/tvalve.dm index f93970a93fd..c3592deb365 100644 --- a/code/ATMOSPHERICS/components/tvalve.dm +++ b/code/ATMOSPHERICS/components/tvalve.dm @@ -358,7 +358,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/unary/heat_exchanger.dm b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm index 79e43a8e1c3..b6014ff34f5 100644 --- a/code/ATMOSPHERICS/components/unary/heat_exchanger.dm +++ b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm @@ -80,7 +80,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 6e445bed48a..3cb91710571 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -275,7 +275,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ @@ -290,7 +290,7 @@ user << "\The [WT] must be turned on!" else if (WT.remove_fuel(0,user)) user << "Now welding \the [src]." - if(do_after(user, 20)) + if(do_after(user, 20, act_target = src)) if(!src || !WT.isOn()) return playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) if(!welded) diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm index 94d583c721c..121d58e186e 100644 --- a/code/ATMOSPHERICS/components/valve.dm +++ b/code/ATMOSPHERICS/components/valve.dm @@ -315,7 +315,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index d5656f75fc0..ee9d9ee0afb 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -93,7 +93,7 @@ return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "You begin to unfasten \the [src]..." - if (do_after(user, 40)) + if (do_after(user, 40, act_target = src)) user.visible_message( \ "\The [user] unfastens \the [src].", \ "You have unfastened \the [src].", \ diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm index 815f4dc2d82..6b057fce8ba 100644 --- a/code/__defines/lighting.dm +++ b/code/__defines/lighting.dm @@ -73,15 +73,20 @@ #define LIGHT_NARROW 45 // Night lighting controller times -// The time (in ticks based on worldtime2ticks()) that various actions trigger -#define MORNING_LIGHT_RESET 252000 // 7am or 07:00 - lighting restores to normal in morning -#define NIGHT_LIGHT_ACTIVE 648000 // 6pm or 18:00 - night lighting mode activates +// The time (in hours based on worldtime2hours()) that various actions trigger +#define MORNING_LIGHT_RESET 7 // 7am or 07:00 - lighting restores to normal in morning +#define NIGHT_LIGHT_ACTIVE 18 // 6pm or 18:00 - night lighting mode activates // Some brightness/range defines for objects. #define L_WALLMOUNT_POWER 0.4 #define L_WALLMOUNT_RANGE 2 -#define L_WALLMOUNT_HI_POWER 2 // For red/delta alert on fire alarms. +#define L_WALLMOUNT_HI_POWER 1 // For red/delta alert on fire alarms. #define L_WALLMOUNT_HI_RANGE 4 +// This controls by how much console sprites are dimmed before being overlayed. +#define HOLOSCREEN_ADDITION_FACTOR 1 +#define HOLOSCREEN_MULTIPLICATION_FACTOR 0.5 +#define HOLOSCREEN_ADDITION_OPACITY 0.8 +#define HOLOSCREEN_MULTIPLICATION_OPACITY 1 // Just so we can avoid unneeded proc calls when profiling is disabled. #define L_PROF(O,T) if (lighting_profiling) {lprof_write(O,T);} diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm index ab74ab7ddfe..9758cfdef84 100644 --- a/code/__defines/machinery.dm +++ b/code/__defines/machinery.dm @@ -105,3 +105,8 @@ var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret // If this is returned from a machine's process() proc, the machine will stop processing but // will continue to have power calculations done. #define M_NO_PROCESS 27 + +// This controls how much power the AME generates per unit of fuel. +// Assuming 100% efficency, use this equation to figure out power output. +// power_generated = (fuel**2) * AM_POWER_FACTOR +#define AM_POWER_FACTOR 50000 diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index d20cbfd7eb1..075bdd366fa 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -49,7 +49,8 @@ #define CHAT_NOICONS 0x8000 #define PARALLAX_SPACE 0x1 -#define PARALLAX_DUST 0x2 +#define PARALLAX_DUST 0x2 +#define PROGRESS_BARS 0x4 #define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC) @@ -286,6 +287,9 @@ #define get_turf(A) (get_step(A, 0)) #define QDELETED(TARGET) (!TARGET || TARGET.gcDestroyed) +#define QDEL_NULL(item) qdel(item); item = null +// Shim until addtimer is merged or I figure out if it is safe to use scheduler for this. +#define QDEL_IN(OBJ, TIME) spawn(TIME) qdel(OBJ) //Recipe type defines. Used to determine what machine makes them #define MICROWAVE 0x1 diff --git a/code/__defines/process_scheduler.dm b/code/__defines/process_scheduler.dm index 3db5980b7c1..d2dfe2505d6 100644 --- a/code/__defines/process_scheduler.dm +++ b/code/__defines/process_scheduler.dm @@ -30,3 +30,5 @@ last_slept = TimeOfHour; \ tick_start = world.tick_usage; \ } + +#define PSCHED_CHECK_TICK (world.tick_usage > 100 || (world.tick_usage - tick_start) > tick_allowance) diff --git a/code/_helpers/overlay.dm b/code/_helpers/overlay.dm new file mode 100644 index 00000000000..3ee93ccaf52 --- /dev/null +++ b/code/_helpers/overlay.dm @@ -0,0 +1,33 @@ +// Factor/Opacity values are defined in __defines\lighting.dm + +/proc/holographic_overlay(obj/target, icon, icon_state) + var/image/multiply = make_screen_overlay(icon, icon_state) + multiply.blend_mode = BLEND_MULTIPLY + multiply.color = list( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + HOLOSCREEN_MULTIPLICATION_FACTOR, HOLOSCREEN_MULTIPLICATION_FACTOR, HOLOSCREEN_MULTIPLICATION_FACTOR, HOLOSCREEN_MULTIPLICATION_OPACITY + ) + target.overlays += multiply + var/image/overlay = make_screen_overlay(icon, icon_state) + overlay.blend_mode = BLEND_ADD + overlay.color = list( + HOLOSCREEN_ADDITION_FACTOR, 0, 0, 0, + 0, HOLOSCREEN_ADDITION_FACTOR, 0, 0, + 0, 0, HOLOSCREEN_ADDITION_FACTOR, 0, + 0, 0, 0, HOLOSCREEN_ADDITION_OPACITY + ) + target.overlays += overlay + +/proc/make_screen_overlay(icon, icon_state, brightness_factor = null) + var/image/overlay = image(icon, icon_state) + overlay.layer = LIGHTING_LAYER + 0.1 + if (brightness_factor) + overlay.color = list( + brightness_factor, 0, 0, 0, + 0, brightness_factor, 0, 0, + 0, 0, brightness_factor, 0, + 0, 0, 0, 1 + ) + return overlay diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index 689e191fb57..ef732ebd0f4 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -10,10 +10,12 @@ proc/worldtime2text(time = world.time, timeshift = 1) if(!roundstart_hour) roundstart_hour = rand(0, 23) return timeshift ? time2text(time+(36000*roundstart_hour), "hh:mm") : time2text(time, "hh:mm") -proc/worldtime2ticks(time = world.time) - if(!roundstart_hour) +/proc/worldtime2hours() + if (!roundstart_hour) worldtime2text() - return ((roundstart_hour * 60 MINUTES) + time) % TICKS_IN_DAY + . = (world.timeofday / (60 MINUTES)) + roundstart_hour + if (. > 24) + . -= 24 proc/worlddate2text() return num2text(game_year) + "-" + time2text(world.timeofday, "MM-DD") diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm index 232f696a719..39c33cadfce 100644 --- a/code/_helpers/type2type.dm +++ b/code/_helpers/type2type.dm @@ -222,7 +222,7 @@ proc/tg_list2text(list/list, glue=",") // Converts an angle (degrees) into an ss13 direction /proc/angle2dir(var/degree) - degree = (degree + 22.5) % 365 // 22.5 = 45 / 2 + degree = (degree + 22.5) % 360 // 22.5 = 45 / 2 if (degree < 45) return NORTH if (degree < 90) return NORTHEAST if (degree < 135) return EAST diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index c91a9b0a031..294ad172268 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -646,45 +646,109 @@ proc/GaussRandRound(var/sigma,var/roundto) else return get_step(ref, base_dir) -/proc/do_mob(var/mob/user, var/mob/target, var/delay = 30, var/numticks = 5, var/needhand = 1) //This is quite an ugly solution but i refuse to use the old request system. - if(!user || !target) return 0 - if(numticks == 0) return 0 - - var/delayfraction = round(delay/numticks) - var/original_user_loc = user.loc - var/original_target_loc = target.loc +/proc/do_mob(mob/user , mob/target, delay = 30, numticks = 10, needhand = TRUE, display_progress = TRUE) //This is quite an ugly solution but i refuse to use the old request system. + if(!user || !target) + return 0 + var/user_loc = user.loc + var/target_loc = target.loc var/holding = user.get_active_hand() - - for(var/i = 0, i= config.nl_start) + activate() + else + deactivate() /datum/controller/process/night_lighting/doWork() if (manual_override) // don't automatically change lighting if it was manually changed in-game return - switch (worldtime2ticks()) - if (0 to config.nl_finish) - if (isactive) - command_announcement.Announce("Good morning. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now return the public hallway lighting levels to normal.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg') - deactivate() - - if (config.nl_start to TICKS_IN_DAY) - if (!isactive) - command_announcement.Announce("Good evening. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now dim lighting in the public hallways in order to accommodate the circadian rhythm of some species.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg') - activate() - - else - if (isactive) - deactivate() + var/time = worldtime2hours() + if (time <= config.nl_finish || time >= config.nl_start) + if (!isactive) + command_announcement.Announce("Good evening. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now dim lighting in the public hallways in order to accommodate the circadian rhythm of some species.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg') + activate() + else + if (isactive) + command_announcement.Announce("Good morning. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now return the public hallway lighting levels to normal.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg') + deactivate() // 'whitelisted' areas are areas that have nightmode explicitly enabled diff --git a/code/controllers/Processes/scheduler.dm b/code/controllers/Processes/scheduler.dm index f2729d5d3aa..35146686fcc 100644 --- a/code/controllers/Processes/scheduler.dm +++ b/code/controllers/Processes/scheduler.dm @@ -4,54 +4,141 @@ * Scheduler * ************/ /datum/controller/process/scheduler - var/list/scheduled_tasks - var/tick_completed = TRUE - var/list/queued_tasks + var/list/datum/scheduled_task/tasks = list() + var/datum/scheduled_task/head /datum/controller/process/scheduler/setup() name = "scheduler" - schedule_interval = 2 SECONDS - scheduled_tasks = list() + schedule_interval = 2 scheduler = src /datum/controller/process/scheduler/doWork() - if (tick_completed) - queued_tasks = scheduled_tasks.Copy() - tick_completed = FALSE + while (head && !PSCHED_CHECK_TICK) + if (head.destroyed) + head.kill() + head = head.next + tasks -= head + continue + if (head.trigger_time >= world.time) + return // Nothing after this will be ready to fire. - while (queued_tasks.len) - var/datum/scheduled_task/task = queued_tasks[queued_tasks.len] - queued_tasks.len-- + // This one's ready to fire, process it. + var/datum/scheduled_task/task = head + head = task.next + task.pre_process() + task.process() + task.post_process() + if (task.destroyed) // post_process probably destroyed it. + tasks -= task + task.kill() +/datum/controller/process/scheduler/proc/queue(datum/scheduled_task/task) + if (!task || !task.trigger_time) + warning("scheduler: Invalid task queued! Ignoring.") + return + // Reset this in-case we're doing a rebuild. + task.next = null + if (!head && !tasks.len) + head = task + tasks += task + return + + if (!head) // Head's missing but we still have tasks, rebuild. + tasks += task + rebuild_queue() + return + + var/datum/scheduled_task/curr = head + while (curr.next && curr.trigger_time < task.trigger_time) + curr = curr.next + + if (!curr.next) + // We're at the end of the queue, just append. + curr.next = task + tasks += task + return + + // Inserting midway into the list. + var/old_next = curr.next + curr.next = task + task.next = old_next + tasks += task + +// Rebuilds the queue linked-list, removing invalid or destroyed entries. +/datum/controller/process/scheduler/proc/rebuild_queue() + log_debug("scheduler: Rebuilding queue.") + var/list/old_tasks = tasks + tasks = list() + if (!old_tasks.len) + log_debug("scheduler: rebuild was called on empty queue! Aborting.") + return + + // Find the head. + for (var/thing in old_tasks) + var/datum/scheduled_task/task = thing if (QDELETED(task)) - scheduled_tasks -= task + old_tasks -= task continue - if (world.time > task.trigger_time) - unschedule(task) - task.pre_process() - task.process() - task.post_process() - F_SCHECK + if (task.destroyed) + old_tasks -= task + task.kill() + continue - tick_completed = TRUE + if (!head || task.trigger_time < head.trigger_time) + head = task + + if (!head) + log_debug("scheduler: unable to find head! Purging task queue.") + for (var/thing in old_tasks) + var/datum/scheduled_task/task = thing + if (QDELETED(task)) + continue + + task.kill() + + head = null + return + + // Don't queue the head. + tasks += head + old_tasks -= head + + // Now rebuild the queue. + for (var/thing in old_tasks) + var/datum/scheduled_task/task = thing + + queue(task) + + log_debug("scheduler: Queue diff is [old_tasks.len - tasks.len].") /datum/controller/process/scheduler/statProcess() ..() - stat(null, "[scheduled_tasks.len] tasks, [queued_tasks.len] queued") + stat(null, "[tasks.len] task\s") /datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st) - scheduled_tasks += st - destroyed_event.register(st, src, /datum/controller/process/scheduler/proc/unschedule) + queue(st) /datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st) - if(st in scheduled_tasks) - scheduled_tasks -= st - destroyed_event.unregister(st, src) + st.destroyed = TRUE /********** * Helpers * **********/ +/proc/schedule(source, the_proc, time, ...) + if (time < 0) + return + time += world.time + var/list/the_args + if (length(args) > 3) + the_args = args.Copy(4) + else + the_args = list() + if (source) + return schedule_task_with_source(time, the_proc, the_args) + else + return schedule_task(time, the_proc, the_args) + /proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list()) return schedule_task(world.time + in_time, procedure, arguments) @@ -77,68 +164,3 @@ var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval)) scheduler.schedule(st) return st - -/************* -* Task Datum * -*************/ -/datum/scheduled_task - var/trigger_time - var/procedure - var/list/arguments - var/task_after_process - var/list/task_after_process_args - -/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) - ..() - src.trigger_time = trigger_time - src.procedure = procedure - src.arguments = arguments ? arguments : list() - src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task - src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list() - task_after_process_args += src - -/datum/scheduled_task/Destroy() - procedure = null - arguments.Cut() - task_after_process = null - task_after_process_args.Cut() - return ..() - -/datum/scheduled_task/proc/pre_process() - task_triggered_event.raise_event(list(src)) - -/datum/scheduled_task/proc/process() - if(procedure) - call(procedure)(arglist(arguments)) - -/datum/scheduled_task/proc/post_process() - call(task_after_process)(arglist(task_after_process_args)) - -// Resets the trigger time, has no effect if the task has already triggered -/datum/scheduled_task/proc/trigger_task_in(var/trigger_in) - src.trigger_time = world.time + trigger_in - -/datum/scheduled_task/source - var/datum/source - -/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) - src.source = source - destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed) - ..(trigger_time, procedure, arguments, task_after_process, task_after_process_args) - -/datum/scheduled_task/source/Destroy() - source = null - return ..() - -/datum/scheduled_task/source/process() - call(source, procedure)(arglist(arguments)) - -/datum/scheduled_task/source/proc/source_destroyed() - qdel(src) - -/proc/destroy_scheduled_task(var/datum/scheduled_task/st) - qdel(st) - -/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st) - st.trigger_time = world.time + trigger_delay - scheduler.schedule(st) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 2e22c1d9b12..8cfb79a34ab 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -177,8 +177,8 @@ var/list/gamemode_cache = list() var/ghost_interaction = 0 var/night_lighting = 0 - var/nl_start = 19 * TICKS_IN_HOUR - var/nl_finish = 8 * TICKS_IN_HOUR + var/nl_start = 19 + var/nl_finish = 8 var/comms_password = "" @@ -187,6 +187,7 @@ var/list/gamemode_cache = list() var/use_discord_bot = 0 var/discord_bot_host = "localhost" var/discord_bot_port = 0 + var/use_discord_pins = 0 var/python_path = "python" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge. var/use_overmap = 0 @@ -629,10 +630,10 @@ var/list/gamemode_cache = list() config.night_lighting = 1 if("nl_start_hour") - config.nl_start = text2num(value) * TICKS_IN_HOUR + config.nl_start = text2num(value) if("nl_finish_hour") - config.nl_finish = text2num(value) * TICKS_IN_HOUR + config.nl_finish = text2num(value) if("disable_player_mice") config.disable_player_mice = 1 @@ -652,6 +653,9 @@ var/list/gamemode_cache = list() if("discord_bot_port") config.discord_bot_port = value + if("use_discord_pins") + config.use_discord_pins = 1 + if("python_path") if(value) config.python_path = value @@ -878,6 +882,8 @@ var/list/gamemode_cache = list() discord_bot.active = 1 if ("robust_debug") discord_bot.robust_debug = 1 + if ("subscriber") + discord_bot.subscriber_role = value else log_misc("Unknown setting in discord configuration: '[name]'") diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index 694f64e0f21..2b8c10ac6e1 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -194,8 +194,16 @@ datum/controller/vote proc/submit_vote(var/ckey, var/vote) if(mode) - if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder) - return 0 + if (mode == "crew_transfer") + if(config.vote_no_dead && usr && !usr.client.holder) + if (isnewplayer(usr)) + usr << "You must be playing or have been playing to start a vote." + return 0 + else if (isobserver(usr)) + var/mob/dead/observer/O = usr + if (O.started_as_observer) + usr << "You must be playing or have been playing to start a vote." + return 0 if(vote && vote >= 1 && vote <= choices.len) if(current_votes[ckey]) choices[choices[current_votes[ckey]]]-- @@ -211,6 +219,16 @@ datum/controller/vote // Transfer votes are their own little special snowflake var/next_allowed_time = 0 if (vote_type == "crew_transfer") + if (config.vote_no_dead && !usr.client.holder) + if (isnewplayer(usr)) + usr << "You must be playing or have been playing to start a vote." + return 0 + else if (isobserver(usr)) + var/mob/dead/observer/O = usr + if (O.started_as_observer) + usr << "You must be playing or have been playing to start a vote." + return 0 + if (last_transfer_vote) next_allowed_time = (last_transfer_vote + config.vote_delay) else @@ -275,16 +293,16 @@ datum/controller/vote log_vote(text) world << "[text]\nType vote or click here to place your votes.\nYou have [config.vote_period/10] seconds to vote." - for(var/client/C in clients) + for(var/cc in clients) + var/client/C = cc if(C.prefs.asfx_togs & ASFX_VOTE) //Personal mute - C << sound('sound/effects/vote.ogg') - switch(vote_type) - if("crew_transfer") - world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) - if("gamemode") - world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) - if("custom") - world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + switch(vote_type) + if("crew_transfer") + C << sound('sound/effects/vote.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + if("gamemode") + C << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + if("custom") + C << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) if(mode == "gamemode" && round_progressing) round_progressing = 0 world << "Round start has been delayed." diff --git a/code/datums/discord_bot.dm b/code/datums/discord_bot.dm index 1238e3e93e4..1f74fee83b6 100644 --- a/code/datums/discord_bot.dm +++ b/code/datums/discord_bot.dm @@ -1,6 +1,13 @@ #define CHAN_ADMIN "channel_admin" #define CHAN_CCIAA "channel_cciaa" #define CHAN_ANNOUNCE "channel_announce" +#define CHAN_INVITE "channel_invite" + +#define SEND_OK 0 +#define SEND_TIMEOUT 1 +#define ERROR_PROC 2 +#define ERROR_CURL 3 +#define ERROR_HTTP 4 var/datum/discord_bot/discord_bot = null @@ -15,21 +22,34 @@ var/datum/discord_bot/discord_bot = null discord_bot.update_channels() + if (config.use_discord_pins && server_greeting) + server_greeting.update_pins() + return 1 /datum/discord_bot - var/list/channels = list() + var/list/channels_to_group = list() // Group flag -> list of channel datums map. + var/list/channels = list() // Channel ID -> channel datum map. Will ensure that only one datum per channel ID exists. + + var/datum/discord_channel/invite = null // The channel datum where the ingame Join Channel button will link to. var/active = 0 var/auth_token = "" + var/subscriber_role = "" var/robust_debug = 0 // Lazy man's rate limiting vars - var/rate_limited_since = 0 - var/queue_being_pushed = 0 + var/datum/scheduled_task/push_task var/list/queue = list() +/* + * Proc update_channels + * Used to load channels from the database and construct them with the discord API. + * Wipes all current channels and channel maps. + * + * @return num - Error code. 0 upon success. + */ /datum/discord_bot/proc/update_channels() if (!active) return 1 @@ -38,27 +58,56 @@ var/datum/discord_bot/discord_bot = null log_debug("BOREALIS: Failed to update channels due to missing database.") return 2 - channels = list() + // Reset the channel lists. + channels_to_group.Cut() + channels.Cut() - var/DBQuery/channel_query = dbcon.NewQuery("SELECT channel_group, channel_id FROM discord_channels") + var/DBQuery/channel_query = dbcon.NewQuery("SELECT channel_group, channel_id, pin_flag, server_id FROM discord_channels") channel_query.Execute() - var/list/A while (channel_query.NextRow()) - if (isnull(channels[channel_query.item[1]])) - channels[channel_query.item[1]] = list() + // Create the channel map. + if (isnull(channels_to_group[channel_query.item[1]])) + channels_to_group[channel_query.item[1]] = list() - A = channels[channel_query.item[1]] - A += channel_query.item[2] + var/datum/discord_channel/B = channels[channel_query.item[2]] + + // We don't have this channel datum yet. + if (isnull(B)) + B = new(channel_query.item[2], channel_query.item[4], text2num(channel_query.item[3])) + + if (!B) + log_debug("BOREALIS: Bad channel data during update channels. [jointext(channel_query.item, ", ")].") + continue + + channels[channel_query.item[2]] = B + + if (text2num(channel_query.item[3])) + B.pin_flag |= text2num(channel_query.item[3]) + + // Add the channel to the required lists. + channels_to_group[channel_query.item[1]] += B + + if (!isnull(channels_to_group[CHAN_INVITE])) + invite = channels_to_group[CHAN_INVITE][1] + else if (robust_debug) + log_debug("BOREALIS: No invite channel designated.") log_debug("BOREALIS: Channels updated successfully.") return 0 +/* + * Proc send_message + * Used to send a message to a specific channel group. + * + * @param text channel_group - The name of the channel group which to target. + * @param text message - The message to send. + */ /datum/discord_bot/proc/send_message(var/channel_group, var/message) if (!active || !auth_token) return - if (!channel_group || !channels.len || isnull(channels[channel_group])) + if (!channel_group || !channels.len || isnull(channels_to_group[channel_group])) return if (!message) @@ -70,18 +119,18 @@ var/datum/discord_bot/discord_bot = null // Let's run it through the proper JSON encoder, just in case of special characters. message = json_encode(list("content" = message)) - var/list/A = channels[channel_group] + var/list/A = channels_to_group[channel_group] var/list/sent = list() - for (var/channel in A) - if (send_post_request("https://discordapp.com/api/channels/[channel]/messages", message, "Authorization: Bot [auth_token]", "Content-Type: application/json") == 429) + for (var/B in A) + var/datum/discord_channel/channel = B + if (channel.send_message_to(auth_token, message) == SEND_TIMEOUT) // Whoopsies, rate limited. // Set up the queue. - rate_limited_since = world.time - queue.Add(list(message, A - sent)) + queue.Add(list(list(message, A - sent))) // Schedule a push. - spawn (100) - push_queue() + if (!push_task) + push_task = schedule_task_with_source_in(10 SECONDS, src, /datum/discord_bot/proc/push_queue) // And exit. return @@ -89,43 +138,87 @@ var/datum/discord_bot/discord_bot = null sent += channel if (robust_debug) - log_debug("BOEALIS: Message sent to [channel_group]. JSON body: '[message]'") + log_debug("BOREALIS: Message sent to [channel_group]. JSON body: '[message]'") +/* + * Proc retreive_pins + * Used to fetch a list of all pins from the designated channels. + * + * @return list - A multilayered list of flags associated with pins. Structure looks like this: + * list("pin_flag" = list(list("author" = author name, "content" = content), + * list("author" = author name, "content" = content))) + */ +/datum/discord_bot/proc/retreive_pins() + if (!active || !auth_token) + return list() + + if (!channels.len || isnull(channels_to_group["channel_pins"])) + testing("No group.") + return list() + + var/list/output = list() + + for (var/A in channels_to_group["channel_pins"]) + var/datum/discord_channel/channel = A + if (isnull(output["[channel.pin_flag]"])) + output["[channel.pin_flag]"] = list() + + output["[channel.pin_flag]"] += channel.get_pins(auth_token) + + return output + +/* + * Proc retreive_invite + * Used to retreive the invite to the invite channel. + * One will be created if none exist. + * + * @return text - The invite URL to the designated invite channel. + */ +/datum/discord_bot/proc/retreive_invite() + if (!active || !auth_token) + return "" + + if (!invite) + return "" + + var/res = invite.get_invite(auth_token) + return isnum(res) ? "" : res + +/* + * Proc send_to_admin + * Forwards a message to the admin channels. + */ /datum/discord_bot/proc/send_to_admins(message) send_message(CHAN_ADMIN, message) +/* + * Proc send_to_cciaa + * Forwards a message to the CCIAA channels. + */ /datum/discord_bot/proc/send_to_cciaa(message) send_message(CHAN_CCIAA, message) -/datum/discord_bot/proc/send_to_announce(message) +/* + * Proc send_to_announce + * Forwards a message to the announcements channels. + */ +/datum/discord_bot/proc/send_to_announce(message, prepend_role = 0) + if (prepend_role && subscriber_role) + message = "<@&[subscriber_role]> " + message send_message(CHAN_ANNOUNCE, message) +/* + * Proc push_queue + * Handles the queue pushing for the bot. If there is no need to reschedule (all messages get successfully + * pushed), then it deletes push_task and sets it back to null. Otherwise, it simply reschedules it. + */ /datum/discord_bot/proc/push_queue() // What facking queue. - if (!queue.len) + if (!queue || !queue.len) if (robust_debug) log_debug("BOREALIS: Attempted to push a null length queue.") - if (queue_being_pushed) - queue_being_pushed = 0 return - if (queue_being_pushed) - if (robust_debug) - log_debug("BOREALIS: Attempted to initialize a second queue driver.") - return - - if ((world.time - rate_limited_since) < 100) - // Something broke the limit again. Ideally, this wouldn't happen. But sure. - // Use a longer timeout, just in case. - spawn (200) - push_queue() - - queue_being_pushed = 0 - return - - // Async process lock var. No touchy. - queue_being_pushed = 1 - // A[1] - message body. // A[2] - list of channels to send to. var/message @@ -134,22 +227,216 @@ var/datum/discord_bot/discord_bot = null message = A[1] destinations = A[2] - for (var/channel in destinations) - if (send_post_request("https://discordapp.com/api/channels/[channel]/messages", message, "Authorization: Bot [auth_token]", "Content-Type: application/json") == 429) - // Limited again. Reschedule. - rate_limited_since = world.time - spawn (100) - push_queue() + for (var/B in destinations) + var/datum/discord_channel/channel = B + if (channel.send_message_to(auth_token, message) == SEND_TIMEOUT) + // Tasks nuke themselves after use. So just make a new one! What could possibly go wrong! + push_task = schedule_task_with_source_in(10 SECONDS, src, /datum/discord_bot/proc/push_queue) - queue_being_pushed = 0 return else destinations.Remove(channel) queue.Remove(A) - queue_being_pushed = 0 +// A holder class for channels. +/datum/discord_channel + var/id = "" + var/server_id = "" + var/pin_flag = 0 + var/invite_url = "" + +/* + * Constructor + * + * @param text _id - the discord API id of the channel, as a string. + * @param text _sid - the discord API server id for the channel, as a string. + * @param num _pin - the bitflags of admin permissions which have access to the pins from this channel. + */ +/datum/discord_channel/New(var/_id, var/_sid, var/_pin) + id = _id + server_id = _sid + + if (_pin) + pin_flag = _pin + +/* + * Proc send_message_to + * Sends a message to the channel. + * + * @param text token - the authorization token to be used for the requests. + * @param text message - the sanitized message content to be sent. + * @return num - a specific return code for the discord_bot to handle. + */ +/datum/discord_channel/proc/send_message_to(var/token, var/message) + if (!token || !message) + return ERROR_PROC + + var/res = send_post_request("https://discordapp.com/api/channels/[id]/messages", message, "Authorization: Bot [token]", "Content-Type: application/json") + + switch (res) + if (-1) + return ERROR_PROC + + if (200) + return SEND_OK + + if (429) + return SEND_TIMEOUT + + if (0 to 90) + log_debug("BOREALIS: cURL error while forwarding message to Discord API: [res]. Message body: [message].") + return ERROR_CURL + + else + log_debug("BOREALIS: HTTP error while forwarding message to Discord API: [res]. Channel: [id]. Message body: [message].") + return ERROR_HTTP + +/* + * Proc get_pins + * Retreives a list of pinned messages from the channel. + * + * @param text token - the authorization token to be used for the requests. + * @return mixed - 2d array of content upon success, in format: list(list("author" = text, "content" = text)). + * Num upon failure. + */ +/datum/discord_channel/proc/get_pins(var/token) + var/res = send_get_request("https://discordapp.com/api/channels/[id]/pins", "Authorization: Bot [token]") + + // Is a number, so an error code. + if (isnum(res)) + switch (res) + if (-1) + return ERROR_PROC + + if (0 to 90) + log_debug("BOREALIS: cURL error while fetching pins from the Discord API: [res].") + return ERROR_CURL + + if (100 to 600) + log_debug("BOREALIS: HTTP error while fetching pins from the Discord API: [res].") + return ERROR_HTTP + + else + log_debug("BOREALIS: Unknown response code while fetching pins from the Discord API: [res].") + return ERROR_PROC + else + var/list/A = res + var/list/pinned_messages = list() + + // Begin processing the list structure delivered back to us from send_get_request. + for (var/list/B in A) + var/content = B["content"] + + // We have mentions to take care of. + if (!isnull(B["mentions"])) + var/list/mentions = B["mentions"] + + for (var/list/C in mentions) + content = replacetextEx(content, "<@[C["id"]]>", C["username"]) + + // Role mentions are up next. + if (!isnull(B["mention_roles"])) + var/list/mentions = B["mention_roles"] + + for (var/C in mentions) + content = replacetextEx(content, "<@&[C]>", "@SomeRole") + + pinned_messages += list(list("author" = B["author"]["username"], "content" = content)) + + return pinned_messages + +/* + * Proc get_invite + * Retreives (or creates if none found) an invite URL to the specific channel. + * + * @param text token - the authorization token to be used for the requests. + * @return mixed - text upon success, the link to the invite; num upon failure. + */ +/datum/discord_channel/proc/get_invite(var/token) + if (invite_url) + return invite_url + + var/res = send_get_request("https://discordapp.com/api/channels/[id]/invites", "Authorization: Bot [token]") + + // Is a number, so an error code. + if (isnum(res)) + switch (res) + if (-1) + return ERROR_PROC + + if (0 to 90) + log_debug("BOREALIS: cURL error while fetching pins from the Discord API: [res].") + return ERROR_CURL + + if (100 to 600) + log_debug("BOREALIS: HTTP error while fetching pins from the Discord API: [res].") + return ERROR_HTTP + + else + log_debug("BOREALIS: Unknown response code while fetching pins from the Discord API: [res].") + return ERROR_PROC + else + var/list/A = res + + // No length to return data, but a valid 200 return header. + // So we simply have no invites active. Make one! + if (!A || !A.len) + return create_invite(token) + + var/best_age = A[1]["max_age"] + var/code = A[1]["code"] + + // Find the best invite. + // Why? Because round time expires are lame, I guess. + if (best_age != 0) + for (var/i = 2, i < A.len, i++) + if (A[i]["max_age"] == 0) + code = A[i]["code"] + break + + if (best_age < A[i]["max_age"]) + best_age = A[i]["max_age"] + code = A[i]["code"] + + // Sanity check for debug I guess. + if (!code) + log_debug("BOREALIS: Retreived an empty invite. This should not happen. Response object: [json_encode(A)]") + + // Save the URL for later retreival. + invite_url = "https://discord.gg/[code]" + return invite_url + +/* + * Proc create_invite + * Creates a permanent invite to a channel and returns it, under the assumption that + * there are no other invites for this channel. + * + * @param text token - the authorization token to be used for the requests. + * @return mixed - String upon success - the URL of the newly generated invite. + * Num upon failure. + */ +/datum/discord_channel/proc/create_invite(var/token) + var/data = list("max_age" = 0, "max_uses" = 0) + var/res = send_post_request("https://discordapp.com/api/channels/[id]/invites", json_encode(data), "Authorization: Bot [token]", "Content-Type: application/json") + + if (res == 200) + var/list/get_req = send_get_request("https://discordapp.com/api/channels/[id]/invites", "Authorization: Bot [token]") + + if (!istype(get_req) || !get_req.len) + return ERROR_PROC + + // The first index should now exist. So we just use that! + invite_url = "https://discord.gg/[get_req[1]["code"]]" + return invite_url #undef CHAN_ADMIN #undef CHAN_CCIAA #undef CHAN_ANNOUNCE +#undef CHAN_INVITE + +#undef SEND_OK +#undef SEND_TIMEOUT +#undef ERROR_PROC +#undef ERROR_CURL +#undef ERROR_HTTP diff --git a/code/datums/scheduled_task.dm b/code/datums/scheduled_task.dm new file mode 100644 index 00000000000..f7ffb042325 --- /dev/null +++ b/code/datums/scheduled_task.dm @@ -0,0 +1,79 @@ +/************* +* Task Datum * +*************/ +/datum/scheduled_task + var/trigger_time + var/procedure + var/list/arguments + var/task_after_process + var/list/task_after_process_args + var/datum/scheduled_task/next + var/destroyed = FALSE + +/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) + ..() + src.trigger_time = trigger_time + src.procedure = procedure + src.arguments = arguments ? arguments : list() + src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task + src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list() + task_after_process_args += src + +/datum/scheduled_task/Destroy() + if (!destroyed) + kill(no_del = TRUE) + procedure = null + arguments.Cut() + task_after_process = null + task_after_process_args.Cut() + return ..() + +/datum/scheduled_task/proc/pre_process() + return + +/datum/scheduled_task/proc/process() + if(procedure) + call(procedure)(arglist(arguments)) + +/datum/scheduled_task/proc/post_process() + call(task_after_process)(arglist(task_after_process_args)) + +// Resets the trigger time, has no effect if the task has already triggered +/datum/scheduled_task/proc/trigger_task_in(var/trigger_in) + src.trigger_time = world.time + trigger_in + +/datum/scheduled_task/proc/kill(no_del = FALSE) + if (!destroyed) + warning("scheduler: Non-destroyed task was killed!") + destroyed = TRUE + + if (src in scheduler.tasks) + warning("scheduler: Task was not cleaned up correctly, rebuilding scheduler queue!") + scheduler.rebuild_queue() + + if (!no_del) + qdel(src) + +/datum/scheduled_task/source + var/datum/source + +/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) + src.source = source + ..(trigger_time, procedure, arguments, task_after_process, task_after_process_args) + +/datum/scheduled_task/source/Destroy() + source = null + return ..() + +/datum/scheduled_task/source/process() + call(source, procedure)(arglist(arguments)) + +/datum/scheduled_task/source/proc/source_destroyed() + destroyed = TRUE + +/proc/destroy_scheduled_task(var/datum/scheduled_task/st) + st.destroyed = TRUE + +/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st) + st.trigger_time = world.time + trigger_delay + scheduler.schedule(st) diff --git a/code/datums/server_greeting.dm b/code/datums/server_greeting.dm index be8bfcee59f..5b7868b07b6 100644 --- a/code/datums/server_greeting.dm +++ b/code/datums/server_greeting.dm @@ -46,8 +46,9 @@ if (F["motd"]) F["motd"] >> motd - if (F["memo"]) - F["memo"] >> memo_list + if (!config.use_discord_pins) + if (F["memo"]) + F["memo"] >> memo_list update_data() @@ -63,18 +64,32 @@ motd = initial(motd) motd_hash = "" - if (memo_list.len) - memo = "" - for (var/ckey in memo_list) - var/data = {"

[ckey] wrote on [memo_list[ckey]["date"]]:
- [memo_list[ckey]["content"]]

"} + if (!config.use_discord_pins) + // The initialization of memos in case use_discord_pins == 1 is done in discord_bot.dm + // Primary reason is to avoid null references when the bot isn't created yet. + if (memo_list.len) + memo = "" + for (var/ckey in memo_list) + var/data = {"

[ckey] wrote on [memo_list[ckey]["date"]]:
+ [memo_list[ckey]["content"]]

"} - memo += data + memo += data - memo_hash = md5(memo) - else - memo = initial(memo) - memo_hash = "" + memo_hash = md5(memo) + else + memo = initial(memo) + memo_hash = "" + +/datum/server_greeting/proc/update_pins() + var/list/temp_list = discord_bot.retreive_pins() + + // A is a number in a string form + // temp_list[A] is a list of lists. + for (var/A in temp_list) + var/list/memos = temp_list[A] + var/flag = text2num(A) + + memo_list += new /datum/memo_datum(memos, flag) /* * Helper to update the MoTD or memo contents. @@ -94,9 +109,15 @@ motd = new_value if ("memo_write") + if (config.use_discord_pins) + return 0 + memo_list[new_value[1]] = list("date" = time2text(world.realtime, "DD-MMM-YYYY"), "content" = new_value[2]) if ("memo_delete") + if (config.use_discord_pins) + return 0 + if (memo_list[new_value]) memo_list -= new_value else @@ -132,7 +153,7 @@ if (motd_hash && user.prefs.motd_hash != motd_hash) outdated_info |= OUTDATED_MOTD - if (user.holder && memo_hash && user.prefs.memo_hash != memo_hash) + if (user.holder && user.prefs.memo_hash != get_memo_hash(user)) outdated_info |= OUTDATED_MEMO if (user.prefs.notifications.len) @@ -185,13 +206,13 @@ else if (outdated_info & OUTDATED_MEMO) data["update"] = 1 - data["changeHash"] = memo_hash + data["changeHash"] = get_memo_hash(user) else data["update"] = 0 data["changeHash"] = null data["div"] = "#memo" - data["content"] = memo + data["content"] = get_memo_content(user) user << output(JS_SANITIZE(data), "greeting.browser:AddContent") if (outdated_info & OUTDATED_MOTD) @@ -216,6 +237,81 @@ if ("request_data") send_to_javascript(C) +/* + * Gets the appropriate memo hash for the memo system in use. + * Args: + * - var/C client + * Returns: + * - string + */ +/datum/server_greeting/proc/get_memo_hash(var/client/C) + if (!C || !C.holder) + return "" + + if (!config.use_discord_pins) + return memo_hash + + var/joint_checksum = "" + for (var/A in memo_list) + var/datum/memo_datum/memo = A + if (C.holder.rights & memo.flag) + joint_checksum += memo.hash + + return md5(joint_checksum) + +/* + * Gets the appropriate memo content for the memo system in use. + * Args: + * - var/C client + * Returns: + * - string if old memo system is used (config.use_discord_pins = 0) + * - list of strings if new memo system is used + */ +/datum/server_greeting/proc/get_memo_content(var/client/C) + if (!C || !C.holder) + return "" + + if (!config.use_discord_pins) + return memo + + var/list/content = list() + for (var/A in memo_list) + var/datum/memo_datum/memo = A + if (C.holder.rights & memo.flag) + content += memo.contents + + return content + +/datum/memo_datum + var/contents + var/hash + var/flag + +/datum/memo_datum/New(var/list/input = list(), var/_flag) + flag = _flag + + // Yes. This is an unfortunately acceptable way of doing it. + // Why? Because you cannot use numbers as indexes in an assoc list without fucking DM. + var/static/list/flags_to_divs = list("[R_ADMIN]" = "danger", + "[R_MOD]" = "warning", + "[(R_MOD|R_ADMIN)]" = "warning", + "[R_CCIAA]" = "info", + "[R_DEV]" = "info") + + if (input.len) + contents = "
" + for (var/i = 1, i <= input.len, i++) + contents += "[input[i]["author"]] wrote:
[nl2br(input[i]["content"])]" + + if (i < input.len) + contents += "
" + + contents += "
" + else + contents = "" + + hash = md5(contents) + #undef OUTDATED_NOTE #undef OUTDATED_MEMO #undef OUTDATED_MOTD diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index c2caf09c07e..5b17e18198f 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -1733,3 +1733,44 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee containertype = /obj/structure/closet/crate containername = "IPC/Shell tag implanters" group = "Security" + +/datum/supply_packs/ame_ctrl + name = "Antimatter Reactor Control Unit" + contains = list( + /obj/machinery/power/am_control_unit + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure/large + containername = "antimatter reactor control unit kit" + group = "Engineering" + access = access_ce + +/datum/supply_packs/ame_section + name = "Antimatter Reactor Shielding Kit" + contains = list( + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container + ) + cost = 20 + containertype = /obj/structure/closet/crate/secure/phoron + containername = "antimatter reactor shielding (9x) crate" + group = "Engineering" + access = access_ce + +/datum/supply_packs/ame_fuel + name = "Antimatter Reactor Fuel" + contains = list( + /obj/item/weapon/am_containment + ) + cost = 20 + containertype = /obj/structure/closet/crate/secure/bin + containername = "antimatter fuel container" + group = "Engineering" + access = access_engine diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm index 6eb6a230083..9f9c828b59a 100644 --- a/code/game/antagonist/antagonist_add.dm +++ b/code/game/antagonist/antagonist_add.dm @@ -45,7 +45,7 @@ update_icons_added(player) return 1 -/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) +/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message = TRUE, var/implanted) if(!istype(player)) return 0 @@ -53,14 +53,15 @@ player.current.verbs -= faction_verb if(player in current_antagonists) - player.current << "You are no longer a [role_text]!" + if (show_message) + player.current << "You are no longer a [role_text]!" current_antagonists -= player faction_members -= player player.special_role = null update_icons_removed(player) BITSET(player.current.hud_updateflag, SPECIALROLE_HUD) - if (!is_special_character(player)) + if (!is_special_character(player) && !player.current.client.holder) player.current.client.verbs -= /client/proc/aooc return 1 diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm index 1ff619546e0..df159aeb16d 100644 --- a/code/game/antagonist/station/cultist.dm +++ b/code/game/antagonist/station/cultist.dm @@ -6,6 +6,12 @@ var/datum/antagonist/cultist/cult if(player.mind in cult.current_antagonists) return 1 +/proc/iscult(var/mob/test) + if (test.faction == "cult") + return 1 + + else return iscultist(test) + /datum/antagonist/cultist id = MODE_CULTIST role_text = "Cultist" @@ -113,7 +119,7 @@ var/datum/antagonist/cultist/cult player << "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back." if(player.current && !istype(player.current, /mob/living/simple_animal/construct)) player.current.add_language(LANGUAGE_CULT) - + /datum/antagonist/cultist/can_become_antag(var/datum/mind/player, ignore_role = 1) if(!..()) return 0 diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index cb0665ea768..1a4e3a52734 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -611,6 +611,13 @@ area/space/atmosalert() flags = RAD_SHIELDED sound_env = TUNNEL_ENCLOSED turf_initializer = new /datum/turf_initializer/maintenance() + ambience = list( + 'sound/ambience/ambimaint1.ogg', + 'sound/ambience/ambimaint2.ogg', + 'sound/ambience/ambimaint3.ogg', + 'sound/ambience/ambimaint4.ogg', + 'sound/ambience/ambimaint5.ogg' + ) station_area = 1 /area/maintenance/civ @@ -1130,14 +1137,20 @@ area/space/atmosalert() /area/engineering name = "\improper Engineering" icon_state = "engineering" - ambience = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg') + ambience = list( + 'sound/ambience/ambisin1.ogg', + 'sound/ambience/ambisin2.ogg', + 'sound/ambience/ambisin3.ogg', + 'sound/ambience/ambisin4.ogg' + ) station_area = 1 /area/engineering/atmos - name = "\improper Atmospherics" - icon_state = "atmos" - sound_env = LARGE_ENCLOSED - no_light_control = 1 + name = "\improper Atmospherics" + icon_state = "atmos" + sound_env = LARGE_ENCLOSED + no_light_control = 1 + ambience = list('sound/ambience/ambiatm1.ogg') /area/engineering/atmos/monitoring name = "\improper Atmospherics Monitoring Room" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 1c2d6d0382f..214caef4a92 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -9,7 +9,7 @@ blend_mode = BLEND_MULTIPLY /area/New() - icon_state = "" + icon_state = "white" layer = 10 uid = ++global_uid all_areas += src @@ -154,21 +154,40 @@ D.open() return +#define DO_PARTY(COLOR) animate(color = COLOR, time = 0.5 SECONDS, easing = QUAD_EASING) + /area/proc/updateicon() if ((fire || eject || party) && (!requires_power||power_environ) && !istype(src, /area/space))//If it doesn't require power, can still activate this proc. - if(fire && !eject && !party) - icon_state = "blue" - /*else if(atmosalm && !fire && !eject && !party) - icon_state = "bluenew"*/ - else if(!fire && eject && !party) - icon_state = "red" - else if(party && !fire && !eject) - icon_state = "party" + if(fire && !eject && !party) // FIRE + color = "#ff9292" + animate(src) // stop any current animations. + animate(src, color = "#ffa5b2", time = 1 SECOND, loop = -1, easing = SINE_EASING) + animate(color = "#ff9292", time = 1 SECOND, easing = SINE_EASING) + else if(!fire && eject && !party) // EJECT + color = "#ff9292" + animate(src) + animate(src, color = "#bc8a81", time = 1 SECOND, loop = -1, easing = EASE_IN|CUBIC_EASING) + animate(color = "#ff9292", time = 0.5 SECOND, easing = EASE_OUT|CUBIC_EASING) + else if(party && !fire && !eject) // PARTY + color = "#ff728e" + animate(src) + animate(src, color = "#7272ff", time = 0.5 SECONDS, loop = -1, easing = QUAD_EASING) + DO_PARTY("#72aaff") + DO_PARTY("#ffc68e") + DO_PARTY("#72c6ff") + DO_PARTY("#ff72e2") + DO_PARTY("#72ff8e") + DO_PARTY("#ffff8e") + DO_PARTY("#ff728e") else - icon_state = "blue-red" + color = "#ffb2b2" + animate(src) + animate(src, color = "#B3DFFF", time = 0.5 SECOND, loop = -1, easing = SINE_EASING) + animate(color = "#ffb2b2", time = 0.5 SECOND, loop = -1, easing = SINE_EASING) else - // new lighting behaviour with obj lights - icon_state = null + animate(src, color = "#FFFFFF", time = 0.5 SECONDS, easing = QUAD_EASING) // Stop the animation. + +#undef DO_PARTY /* diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 0fa8af01ad0..132587422cb 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -223,15 +223,6 @@ its easier to just keep the beam vertical. /atom/proc/set_dir(new_dir) . = new_dir != dir dir = new_dir - /*for(var/datum/light_source/L in light_sources) - if (L.source_atom.offset_light) - L.force_update = 1 - if (world.tick_usage < 80) - L.instant_update()//Instant update skips the normal controller process and updates the light now. - //This makes things more responsive, but probably has a performance cost for people spinning rapidly - //Ergo, it checks tick usage first - else - L.source_atom.update_light()*/ /atom/proc/ex_act() return @@ -510,4 +501,4 @@ its easier to just keep the beam vertical. change_area_name(oldarea.name, newarea.name) /atom/proc/change_area_name(var/oldname, var/newname) - name = replacetext(name,oldname,newname) \ No newline at end of file + name = replacetext(name,oldname,newname) diff --git a/code/game/gamemodes/changeling/changeling_items.dm b/code/game/gamemodes/changeling/changeling_items.dm new file mode 100644 index 00000000000..cf27d5301ba --- /dev/null +++ b/code/game/gamemodes/changeling/changeling_items.dm @@ -0,0 +1,91 @@ +/obj/item/weapon/melee/arm_blade + name = "arm blade" + desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter." + icon = 'icons/obj/changeling.dmi' + icon_state = "arm_blade" + item_state = "arm_blade" + contained_sprite = 1 + w_class = 4 + force = 30 + sharp = 1 + edge = 1 + anchored = 1 + throwforce = 0 //Just to be on the safe side + throw_range = 0 + throw_speed = 0 + can_embed = 0 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + var/mob/living/creator + +/obj/item/weapon/melee/arm_blade/New() + processing_objects |= src + +/obj/item/weapon/melee/arm_blade/Destroy() + processing_objects -= src + ..() + +/obj/item/weapon/melee/arm_blade/dropped() + visible_message("With a sickening crunch, [user] reforms their arm blade into an arm!", + "We assimilate the weapon back into our body.", + "You hear organic matter ripping and tearing!") + playsound(loc, 'sound/effects/blobattack.ogg', 30, 1) + spawn(1) if(src) qdel(src) + +/obj/item/weapon/melee/arm_blade/process() + if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src)) + // Tidy up a bit. + if(istype(loc,/mob/living)) + var/mob/living/carbon/human/host = loc + if(istype(host)) + for(var/obj/item/organ/external/organ in host.organs) + for(var/obj/item/O in organ.implants) + if(O == src) + organ.implants -= src + host.pinned -= src + host.embedded -= src + host.drop_from_inventory(src) + spawn(1) if(src) qdel(src) + +/obj/item/weapon/shield/riot/changeling + name = "shield-like mass" + desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield." + icon = 'icons/obj/changeling.dmi' + icon_state = "ling_shield" + item_state = "ling_shield" + contained_sprite = 1 + slot_flags = null + anchored = 1 + throwforce = 0 //Just to be on the safe side + throw_range = 0 + throw_speed = 0 + can_embed = 0 + var/mob/living/creator + +/obj/item/weapon/shield/riot/changeling/New() + processing_objects |= src + +/obj/item/weapon/shield/riot/changeling/Destroy() + processing_objects -= src + ..() + +/obj/item/weapon/shield/riot/changeling/dropped() + visible_message("With a sickening crunch, [user] reforms their arm blade into an arm!", + "We assimilate the weapon back into our body.", + "You hear organic matter ripping and tearing!") + playsound(loc, 'sound/effects/blobattack.ogg', 30, 1) + spawn(1) if(src) qdel(src) + +/obj/item/weapon/shield/riot/changeling/process() + if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src)) + // Tidy up a bit. + if(istype(loc,/mob/living)) + var/mob/living/carbon/human/host = loc + if(istype(host)) + for(var/obj/item/organ/external/organ in host.organs) + for(var/obj/item/O in organ.implants) + if(O == src) + organ.implants -= src + host.pinned -= src + host.embedded -= src + host.drop_from_inventory(src) + spawn(1) if(src) qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index eb3a092a03c..f57322c47a1 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -1,8 +1,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega") /datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) - var/list/absorbed_dna = list() - var/list/absorbed_species = list() + var/list/datum/absorbed_dna/absorbed_dna = list() var/list/absorbed_languages = list() var/absorbedcount = 0 var/chem_charges = 20 @@ -31,12 +30,24 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E geneticdamage = max(0, geneticdamage-1) /datum/changeling/proc/GetDNA(var/dna_owner) - var/datum/dna/chosen_dna - for(var/datum/dna/DNA in absorbed_dna) - if(dna_owner == DNA.real_name) - chosen_dna = DNA - break - return chosen_dna + for(var/datum/absorbed_dna/DNA in absorbed_dna) + if(dna_owner == DNA.name) + return DNA + +/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA) + var/datum/changeling/changeling = null + if(src.mind && src.mind.changeling) + changeling = src.mind.changeling + if(!changeling) + return + + for(var/language in newDNA.languages) + changeling.absorbed_languages |= language + + changeling_update_languages(changeling.absorbed_languages) + + if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite + changeling.absorbed_dna += newDNA //Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human /mob/proc/make_changeling() @@ -65,14 +76,13 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E if(!(P in src.verbs)) src.verbs += P.verbpath - mind.changeling.absorbed_dna |= dna + for(var/language in languages) + mind.changeling.absorbed_languages |= language var/mob/living/carbon/human/H = src if(istype(H)) - mind.changeling.absorbed_species += H.species.name - - for(var/language in languages) - mind.changeling.absorbed_languages |= language + var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages) + absorbDNA(newDNA) return 1 @@ -83,13 +93,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E if(P.isVerb) verbs -= P.verbpath -//removes changeling powers but keeps those with allowduringlesserform -/mob/proc/remove_changeling_powers_monkey() - if(!mind || !mind.changeling) return - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) - if(P.isVerb && (P.allowduringlesserform == 0)) - verbs -= P.verbpath - //Helper proc. Does all the checks and stuff for us to avoid copypasta /mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0) @@ -133,46 +136,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E return -//Used to switch species based on the changeling datum. -/mob/proc/changeling_change_species() - - set category = "Changeling" - set name = "Change Species (5)" - - var/mob/living/carbon/human/H = src - if(!istype(H)) - src << "We may only use this power while in humanoid form." - return - - var/datum/changeling/changeling = changeling_power(5,1,0) - if(!changeling) return - - if(changeling.absorbed_species.len < 2) - src << "We do not know of any other species genomes to use." - return - - var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species - if(!S) return - - domutcheck(src, null) - - changeling.chem_charges -= 5 - changeling.geneticdamage = 30 - - src.visible_message("[src] transforms!") - - src.verbs -= /mob/proc/changeling_change_species - H.set_species(S,1) //Until someone moves body colour into DNA, they're going to have to use the default. - - spawn(10) - src.verbs += /mob/proc/changeling_change_species - src.regenerate_icons() - - changeling_update_languages(changeling.absorbed_languages) - feedback_add_details("changeling_powers","TR") - - return 1 - //Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. //Doesn't cost anything as it's the most basic ability. /mob/proc/changeling_absorb_dna() @@ -196,6 +159,10 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E src << "We do not know how to parse this creature's DNA!" return + if(islesserform(T)) + src << "This creature DNA is not compatible with our form!" + return + if(HUSK in T.mutations) src << "This creature's DNA is ruined beyond useability!" return @@ -213,6 +180,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E switch(stage) if(1) src << "This creature is compatible. We must hold still..." + src.visible_message("[src]'s skin begins to shift and squirm!") if(2) src << "We extend a proboscis." src.visible_message("[src] extends a proboscis!") @@ -234,9 +202,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E src.visible_message("[src] sucks the fluids from [T]!") T << "You have been absorbed by the changeling!" - T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set. - changeling.absorbed_dna |= T.dna - if(src.nutrition < max_nutrition) src.nutrition = min((nutrition + T.nutrition), max_nutrition) changeling.chem_charges += 10 changeling.geneticpoints += 2 @@ -247,16 +212,15 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E changeling_update_languages(changeling.absorbed_languages) - //Steal their species! - if(T.species && !(T.species.name in changeling.absorbed_species)) - changeling.absorbed_species += T.species.name + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) + absorbDNA(newDNA) if(T.mind && T.mind.changeling) if(T.mind.changeling.absorbed_dna) - for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot - if(dna_data in changeling.absorbed_dna) + for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot + if(changeling.GetDNA(dna_data.name)) continue - changeling.absorbed_dna += dna_data + absorbDNA(dna_data) changeling.absorbedcount++ T.mind.changeling.absorbed_dna.len = 1 @@ -295,31 +259,44 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E if(!changeling) return var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) + names += "[DNA.name]" var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names if(!S) return - var/datum/dna/chosen_dna = changeling.GetDNA(S) + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) if(!chosen_dna) return changeling.chem_charges -= 5 - src.visible_message("[src] transforms!") changeling.geneticdamage = 30 - src.dna = chosen_dna.Clone() - src.real_name = chosen_dna.real_name - src.flavor_text = "" - src.UpdateAppearance() - domutcheck(src, null) + + handle_changeling_transform(chosen_dna) src.verbs -= /mob/proc/changeling_transform - spawn(10) src.verbs += /mob/proc/changeling_transform + spawn(10) + src.verbs += /mob/proc/changeling_transform + + changeling_update_languages(changeling.absorbed_languages) feedback_add_details("changeling_powers","TR") return 1 +/mob/proc/handle_changeling_transform(var/datum/absorbed_dna/chosen_dna) + src.visible_message("[src] transforms!") + + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/newSpecies = chosen_dna.speciesName + H.set_species(newSpecies,1) + + src.dna = chosen_dna.dna + src.real_name = chosen_dna.name + src.flavor_text = "" + domutcheck(src, null) + src.UpdateAppearance() + //Transform into a monkey. /mob/proc/changeling_lesser_form() @@ -340,15 +317,10 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E return changeling.chem_charges-- - H.remove_changeling_powers_monkey() //we weren't making us of allowduringlesserform before for some reason? -Ryan784 H.visible_message("[H] transforms!") changeling.geneticdamage = 30 H << "Our genes cry out!" - var/list/implants = list() //Try to preserve implants. - for(var/obj/item/weapon/implant/W in H) - implants += W - H.monkeyize() - verbs += /mob/proc/changeling_lesser_transform //allow us to actually transform BACK into a human - Ryan784 + H = H.monkeyize() feedback_add_details("changeling_powers","LF") return 1 @@ -457,25 +429,29 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E // charge the changeling chemical cost for stasis changeling.chem_charges -= 20 - // restore us to health - C.revive() - - // remove our fake death flag - C.status_flags &= ~(FAKEDEATH) - - // let us move again - C.update_canmove() - - // re-add out changeling powers - C.make_changeling() - - // sending display messages - C << "We have regenerated." - + C << "We are ready to rise. Use the Revive verb when you are ready." + C.verbs += /mob/proc/changeling_revive feedback_add_details("changeling_powers","FD") return 1 +/mob/proc/changeling_revive() + set category = "Changeling" + set name = "Revive" + + var/mob/living/carbon/C = src + // restore us to health + C.revive() + // remove our fake death flag + C.status_flags &= ~(FAKEDEATH) + // let us move again + C.update_canmove() + // re-add out changeling powers + C.make_changeling() + // sending display messages + C << "We have regenerated." + C.verbs -= /mob/proc/changeling_revive + //Boosts the range of your next sting attack by 1 /mob/proc/changeling_boost_range() @@ -581,7 +557,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E // HIVE MIND UPLOAD/DOWNLOAD DNA -var/list/datum/dna/hivemind_bank = list() +var/list/datum/absorbed_dna/hivemind_bank = list() /mob/proc/changeling_hiveupload() set category = "Changeling" @@ -592,9 +568,14 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling) return var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - if(!(DNA in hivemind_bank)) - names += DNA.real_name + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) + var/valid = 1 + for(var/datum/absorbed_dna/DNB in hivemind_bank) + if(DNA.name == DNB.name) + valid = 0 + break + if(valid) + names += DNA.name if(names.len <= 0) src << "The airwaves already have all of our DNA." @@ -603,7 +584,7 @@ var/list/datum/dna/hivemind_bank = list() var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names if(!S) return - var/datum/dna/chosen_dna = changeling.GetDNA(S) + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) if(!chosen_dna) return @@ -622,9 +603,9 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling) return var/list/names = list() - for(var/datum/dna/DNA in hivemind_bank) - if(!(DNA in changeling.absorbed_dna)) - names[DNA.real_name] = DNA + for(var/datum/absorbed_dna/DNA in hivemind_bank) + if(!(changeling.GetDNA(DNA.name))) + names[DNA.name] = DNA if(names.len <= 0) src << "There's no new DNA to absorb from the air." @@ -637,7 +618,7 @@ var/list/datum/dna/hivemind_bank = list() return changeling.chem_charges -= 20 - changeling.absorbed_dna += chosen_dna + absorbDNA(chosen_dna) src << "We absorb the DNA of [S] from the air." feedback_add_details("changeling_powers","HD") return 1 @@ -692,7 +673,7 @@ var/list/datum/dna/hivemind_bank = list() return 1 //Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities) -/mob/proc/changeling_sting(var/required_chems=0, var/verb_path) +/mob/proc/changeling_sting(var/required_chems=0, var/verb_path, var/stealthy = 0) var/datum/changeling/changeling = changeling_power(required_chems) if(!changeling) return @@ -711,9 +692,20 @@ var/list/datum/dna/hivemind_bank = list() src.verbs -= verb_path spawn(10) src.verbs += verb_path - src << "We stealthily sting [T]." + if(stealthy == 1) + src << "We stealthily sting [T]." + T << "You feel a tiny prick." + else + src.visible_message(pick("[src]'s eyes balloon and burst out in a welter of blood, burrowing into [T]!", + "[src]'s arm rapidly shifts into a giant scorpion-stinger and stabs into [T]!", + "[src]'s throat lengthens and twists before vomitting a chunky red spew all over [T]!", + "[src]'s tongue stretches an impossible length and stabs into [T]!", + "[src] sneezes a cloud of shrieking spiders at [T]!", + "[src] erupts a grotesque tail and impales [T]!", + "[src]'s chin skin bulges and tears, launching a bone-dart at [T]!")) + if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting - T << "You feel a tiny prick." + return @@ -722,7 +714,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Hallucination Sting (15)" set desc = "Causes terror in the target." - var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting) + var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting,stealthy = 1) if(!T) return 0 spawn(rand(300,600)) if(T) T.hallucination += 400 @@ -734,7 +726,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Silence sting (10)" set desc="Sting target" - var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting) + var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting,stealthy = 1) if(!T) return 0 T.silent += 30 feedback_add_details("changeling_powers","SS") @@ -745,7 +737,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Blind sting (20)" set desc="Sting target" - var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting) + var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting,stealthy = 0) if(!T) return 0 T << "Your eyes burn horrificly!" T.disabilities |= NEARSIGHTED @@ -760,7 +752,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Deaf sting (5)" set desc="Sting target:" - var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting) + var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting,stealthy = 0) if(!T) return 0 T << "Your ears pop and begin ringing loudly!" T.sdisabilities |= DEAF @@ -773,7 +765,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Paralysis sting (30)" set desc="Sting target" - var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting) + var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting,stealthy = 0) if(!T) return 0 T << "Your muscles begin to painfully tighten." T.Weaken(20) @@ -788,29 +780,25 @@ var/list/datum/dna/hivemind_bank = list() var/datum/changeling/changeling = changeling_power(40) if(!changeling) return 0 - - var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) + names += "[DNA.name]" var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names if(!S) return - var/datum/dna/chosen_dna = changeling.GetDNA(S) + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) if(!chosen_dna) return - var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting) + var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting,stealthy = 1) if(!T) return 0 if((HUSK in T.mutations) || (!ishuman(T) && !issmall(T))) src << "Our sting appears ineffective against its DNA." return 0 - T.visible_message("[T] transforms!") - T.dna = chosen_dna.Clone() - T.real_name = chosen_dna.real_name - T.UpdateAppearance() - domutcheck(T, null) + + T.handle_changeling_transform(chosen_dna) + feedback_add_details("changeling_powers","TS") return 1 @@ -819,10 +807,9 @@ var/list/datum/dna/hivemind_bank = list() set name = "Unfat sting (5)" set desc = "Sting target" - var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting) + var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting,stealthy = 1) if(!T) return 0 T << "you feel a small prick as stomach churns violently and you become to feel skinnier." - T.overeatduration = 0 T.nutrition -= 100 feedback_add_details("changeling_powers","US") return 1 @@ -832,13 +819,13 @@ var/list/datum/dna/hivemind_bank = list() set name = "Death Sting (40)" set desc = "Causes spasms onto death." - var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting) + var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting,stealthy = 0) if(!T) return 0 T << "You feel a small prick and your chest becomes tight." T.silent = 10 T.Paralyse(10) T.make_jittery(1000) - if(T.reagents) T.reagents.add_reagent("lexorin", 40) + if(T.reagents) T.reagents.add_reagent("cyanide", 5) feedback_add_details("changeling_powers","DTHS") return 1 @@ -853,13 +840,66 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling) return 0 - var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting) + var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting,stealthy = 1) if(!T) return 0 - T.dna.real_name = T.real_name - changeling.absorbed_dna |= T.dna - if(T.species && !(T.species.name in changeling.absorbed_species)) - changeling.absorbed_species += T.species.name + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) + absorbDNA(newDNA) feedback_add_details("changeling_powers","ED") return 1 + +/mob/proc/armblades() + set category = "Changeling" + set name = "Form Blades" + set desc="Rupture the flesh and mend the bone of your hand into a deadly blade." + + var/mob/living/M = src + + if(M.l_hand && M.r_hand) + M << "Your hands are full." + return + + var/obj/item/weapon/melee/arm_blade/blade = new(M) + blade.creator = M + M.put_in_hands(blade) + playsound(loc, 'sound/effects/blobattack.ogg', 30, 1) + src.visible_message("A grotesque blade forms around [M]\'s arm!", + "Our arm twists and mutates, transforming it into a deadly blade.", + "You hear organic matter ripping and tearing!") + gibs(src.loc) + +/mob/proc/changeling_shield() + set category = "Changeling" + set name = "Form Shield" + set desc="Bend the flesh and bone of your hand into a grotesque shield." + + var/mob/living/M = src + + if(M.l_hand && M.r_hand) + M << "Your hands are full." + return + + var/obj/item/weapon/shield/riot/changeling/shield = new(M) + shield.creator = M + M.put_in_hands(shield) + playsound(loc, 'sound/effects/blobattack.ogg', 30, 1) + src.visible_message("The end of [M]\'s hand inflates rapidly, forming a huge shield-like mass!", + "We inflate our hand into a robust shield.", + "You hear organic matter ripping and tearing!") + gibs(src.loc) + +//dna related datum + +/datum/absorbed_dna + var/name + var/datum/dna/dna + var/speciesName + var/list/languages + +/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages) + ..() + name = newName + dna = newDNA + speciesName = newSpecies + languages = newLanguages diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm index 7ba0052b816..303016281a2 100644 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ b/code/game/gamemodes/changeling/modularchangling.dm @@ -26,12 +26,6 @@ var/list/datum/power/changeling/powerinstances = list() genomecost = 0 verbpath = /mob/proc/changeling_transform -/datum/power/changeling/change_species - name = "Change Species" - desc = "We take on the apperance of a species that we have absorbed." - genomecost = 0 - verbpath = /mob/proc/changeling_change_species - /datum/power/changeling/fakedeath name = "Regenerative Stasis" desc = "We become weakened to a death-like state, where we will rise again from death." @@ -64,14 +58,14 @@ var/list/datum/power/changeling/powerinstances = list() /datum/power/changeling/deaf_sting name = "Deaf Sting" - desc = "We silently sting a human, completely deafening them for a short time." + desc = "We sting a human, completely deafening them for a short time." genomecost = 1 allowduringlesserform = 1 verbpath = /mob/proc/changeling_deaf_sting /datum/power/changeling/blind_sting name = "Blind Sting" - desc = "We silently sting a human, completely blinding them for a short time." + desc = "We sting a human, completely blinding them for a short time." genomecost = 2 allowduringlesserform = 1 verbpath = /mob/proc/changeling_blind_sting @@ -108,7 +102,7 @@ var/list/datum/power/changeling/powerinstances = list() /datum/power/changeling/paralysis_sting name = "Paralysis Sting" - desc = "We silently sting a human, paralyzing them for a short time." + desc = "We sting a human, paralyzing them for a short time." genomecost = 8 verbpath = /mob/proc/changeling_paralysis_sting @@ -121,7 +115,7 @@ var/list/datum/power/changeling/powerinstances = list() /datum/power/changeling/DeathSting name = "Death Sting" - desc = "We silently sting a human, filling them with potent chemicals. Their rapid death is all but assured." + desc = "We sting a human, filling them with potent chemicals. Their rapid death is all but assured." genomecost = 10 verbpath = /mob/proc/changeling_DEATHsting @@ -184,7 +178,19 @@ var/list/datum/power/changeling/powerinstances = list() genomecost = 7 verbpath = /mob/proc/changeling_rapidregen +//weapon and armor like powers +/datum/power/changeling/armblades + name = "Mutate Armblades" + desc = "Permits us to reshape our arms into a deadly blade." + genomecost = 2 + verbpath = /mob/proc/armblades + +/datum/power/changeling/shield + name = "Mutate Shield" + desc = "Permits us to bloat our hands into a robust shield." + genomecost = 3 + verbpath = /mob/proc/changeling_shield // Modularchangling, totally stolen from the new player panel. YAYY /datum/changeling/proc/EvolutionMenu()//The new one diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 59cf8f8856b..80f4d996dcb 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -17,59 +17,565 @@ desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie" icon_state = "forge" + + + + + + + + + + + + + +/* + Cult pylons can be used as arcane defensive turrets. + + First of all they must be empowered with a sacrifice. Any small organic creature that can be picked up is valid + Hit the pylon with the creature - while still alive - to present it as a sacrifice, and then end its life to complete the process. + + Once empowered, pylons will fire rapid, weak magical beams at non cult mobs. + + As crystals, pylons are immune to energy weaponry. More than immune, they will absorb lasers and become + supercharged for some time, boosting their damage. Pylons can only be harmed by ballistics and physical weapons + Building reinforced windows around them is highly recommended. + + Pylons are fairly fragile and will quickly break under direct hits. + A damaged pylon will self repair, if it contains a soul. + + + Pylons are largely intended as a stalling, early warning, fire support and area denial system. They are unlikely to actually + kill anyone alone but they can keep pesky civilians away for long enough to learn runes and prepare rituals. + + If you can get ahold of a laser rifle to supercharge them, they can even give security some pause + + Recommended tools for combatting pylons: + Heavy melee (fireaxe, baseball bat, etc) + Sniper rifles + Exosuits + Explosives + Ablative armour +*/ /obj/structure/cult/pylon name = "Pylon" desc = "A floating crystal that hums with an unearthly energy" - icon_state = "pylon" + description_antag = "A pylon can be upgraded into a magical defensive turret that shoots anyone opposing the cult\ +
Upgrading a pylon requires a sacrifice. Bring it a small organic creature, like a monkey or mouse. Use the creature on the pylon, or drag and drop to present it.\ +
Once the sacrifice is accepted, kill it to complete the process. This will gib its body and make a very visible mess. After this point the pylon is fixed to the floor and cant be moved\ +
The pylon will fire weak beams that are harmless to the cult. In addition it can be upgraded even more by shooting it with a laser, which will give it a limited number of extra-power shots." + + icon_state = "pylonbase" var/isbroken = 0 light_range = 5 light_color = "#3e0000" - var/obj/item/wepon = null + var/pylonmode = 0 + //Pylon has three states: + //0 = Idle, the pylon is an inert crystal + //1 = Awaiting sacrifice. The pylon is actively tracking a creature to be sacrificed to it + //2 = Turret. The pylon has been empowered by a sacrifice and is now a turret permanantly + + var/damagetaken = 0 + var/empowered = 0 //Number of empowered, higher-damage shots remaining + var/processing = 0 + var/mob/living/sacrifice //Holds a reference to a mob that is a pending sacrifice + var/mob/living/sacrificer //A reference to the last mob that attempted to sacrifice something. So we can message them + //Sacrifier is also used in target handling. the pylon will not bite the hand that feeds it. Noncultist colleagues are fair game though + + var/next_shot = 0 //Absolute world time when we're allowed to fire again + var/shot_delay = 5 //Minimum delay between shots, in deciseconds + var/mob/living/target + + var/notarget //Number of times handle_firing has been called without finding anything to shoot at + //This is used for switching to lower-intensity processing + + var/datum/language/cultcommon/lang + //An instance of the cult language datum. Used to scramble speech when speaking to noncultists + + var/turf/last_target_loc + + var/process_interval = 1 + var/ticks + anchored = 0 + + +//Just a subtype that starts off in turret mode. For adminbus and debugging. Maybe a future wizard spell +//Spawn them next to ERPers +/obj/structure/cult/pylon/turret + pylonmode = 2 + +/obj/structure/cult/pylon/turret/New() + ..() + start_process() + + +//Another subtype which starts with infinite empower shots. For empowered adminbus +/obj/structure/cult/pylon/turret/empowered + empowered = 99999999 + + +/obj/structure/cult/pylon/New() + ..() + lang = new /datum/language/cultcommon() + update_icon() + +/obj/structure/cult/pylon/examine(var/mob/user) + ..() + if (damagetaken) + switch (damagetaken) + if (1 to 8) + user << "It has very faint hairline fractures." + if (8 to 20) + user << "It has several cracks across its surface." + if (20 to 30) + user << "It is chipped and deeply cracked, it may shatter with much more pressure." + if (30 to INFINITY) + user << "It is almost cleaved in two, the pylon looks like it will fall to shards under its own weight." + + +/obj/structure/cult/pylon/Move() + ..() + last_target_loc = null + +/obj/structure/cult/pylon/proc/start_process() + process_interval = 1 + if (!processing) + processing_objects += src + processing = 1 + + +//If the pylon goes a long time without shooting anything, it will consider slowing down processing +/obj/structure/cult/pylon/proc/reconsider_interval() + var/mindist = INFINITY + for (var/m in player_list) + var/mob/living/L = m + if (L.z != z) + continue + + if (L.stat == DEAD) + continue + + if (iscult(L)) + continue + + if (L == sacrificer) + continue + + var/d = get_dist(src, L) + if (d < mindist) + mindist = d + + mindist = min(150, mindist) + process_interval = Ceiling(mindist*0.1) + process_interval = max(1, process_interval) + + +//Run each process loop, this function checks if we can stop processing yet. +//Returns 0 if its time to stop. Returns 1 if we should keep going. +/obj/structure/cult/pylon/proc/check_process() + if (isbroken) + return 0 + + if (pylonmode == 2) + return 1 + + if (pylonmode == 1) + if (sacrifice) + return 1 + + if (empowered > 0) + return 1 + + return 0 + +/obj/structure/cult/pylon/process() + ticks++ + if(!check_process()) + processing_objects.Remove(src) + processing = 0 + return + + switch (pylonmode) + if (1) + handle_sacrifice() + if (2) + if ((ticks % process_interval) == 0) + handle_firing() + if (damagetaken && prob(50)) + damagetaken = max(0, damagetaken-1) //An empowered pylon slowly self repairs + if (prob(10)) + visible_message("Cracks in the [src] gradually seal as new crystalline matter grows to fill them.") + + if (empowered && prob(2)) + empowered = max(0, empowered - 1) //Overcharging gradually wears off over time + if (empowered <= 0) + update_icon() + + +//If user is a cultist, speaks message to them with a prefix +//If user is not cultist, then speaks cult-y gibberish +/obj/structure/cult/pylon/proc/speak_to(var/mob/user, var/message) + if (iscult(user) || (/datum/language/cultcommon in user.languages)) + user << "A voice speaks into your mind, [span("cult","\"[message]\"")]" + else + user << "A voice speaks into your mind, [span("cult","\"[lang.scramble(message)]\"")]" + + +//Todo: Replace the messages here with better ones. Should display a proper message to cultists +//And nonsensical arcane gibberish to non cultists +/obj/structure/cult/pylon/proc/present_sacrifice(var/mob/living/user, var/mob/living/victim) + if (!user || !victim) + return 0 + + if (isbroken) + user << "The pylon lies silent." + return 0 + + if (pylonmode != 0) + return 0 + + if (!(victim.mob_size) || victim.mob_size > 6) + //toolarge sacrifice, display a message and return + speak_to(user, "This creature is too large, we only require a lesser sacrifice. A small morsel of life...") + return + + if (victim.stat == DEAD) + speak_to(user, "You are too late, the spark of life is already gone from this one. It is naught but an empty husk...") + return + + var/types = victim.find_type() + if ((!(types & TYPE_ORGANIC)) || ((types & TYPE_WIERD))) + //Invalid sacrifice. Display a message and return + speak_to(user, "This soulless automaton cannot satisfy our hunger. We yearn for life essence, it must have a soul.") + return + + sacrifice = victim + sacrificer = user + //Sacrifice accepted, display message here + speak_to(user, "Your sacrifice has been deemed worthy, and accepted. End its life now, and liberate its soul, to seal our contract...") + sacrifice << span("danger", "You feel an invisible force grip your soul, as you're drawn inexorably towards the pylon. Every part of you screams to flee from here!") + + if (istype(sacrifice.loc,/obj/item/weapon/holder)) + var/obj/item/weapon/holder/H = sacrifice.loc + H.release_to_floor() + else + sacrifice.forceMove(get_turf(sacrifice)) + pylonmode = 1 + update_icon() + start_process() + + + +//Runs every proc while there's a pending sacrifice. This checks whether the sacrifice was killed or escaped +/obj/structure/cult/pylon/proc/handle_sacrifice() + .=0 //Return value has 3 states. + //0 = waiting, the sacrifice is still alive + //1 = Finished, the sacrifice was killed, finalize the process and become a turret + //-1 = Escape: The sacrifice left the vicinity of the pylon, return to inert mode. + + if (!sacrifice) + //If the sacrifice was deleted somehow, we cant know exactly what happened. We'll assume it escaped + .=-1 + + else if(get_dist(src, sacrifice) > 5) + //If the sacrifice gets more than 5 tiles away, it has escaped + .=-1 + else if (sacrifice.stat == DEAD) + .=1 + + switch(.) + if (1) + finalize_sacrifice() + if (-1) + speak_to(sacrificer, "Fool! Your offering has escaped. Bring it back, or find us another...") + sacrifice = null + pylonmode = 0 + update_icon() + if (sacrifice) + walk_to(sacrifice,0) + else + walk_towards(sacrifice,src, 10) + +/obj/structure/cult/pylon/proc/finalize_sacrifice() + sacrifice.visible_message(span("danger","\The [sacrifice]'s physical form unwinds as its soul is extracted from the remains, and drawn into the pylon!")) + if (istype(sacrifice.loc,/obj/item/weapon/holder)) + var/obj/item/weapon/holder/H = sacrifice.loc + H.release_to_floor() + else + sacrifice.forceMove(get_turf(sacrifice)) //Make sure its on the floor before we gib it + pylonmode = 2 + sacrifice.gib() + + update_icon() + + +//Called every process in turret mode, and also by chaining spawns +/obj/structure/cult/pylon/proc/handle_firing() + + if ((world.time < next_shot) || isbroken) + return + //Not ready to fire yet + + + var/list/stuffcache + //Stuffcache holds a list of things found by a dview call, so we only need to do it once per proc. + + + if (target && (target.stat != DEAD)) + if (target.loc == last_target_loc) + //To minimise expensive DVIEW calls, if the target hasnt moved since the last shot we'll assume they're still in sight + //This could cause problems in some edge cases (like lowering firelocks or shutters without moving) + //But it has a major performance gain that makes it worth it + fire_at(target) + return + else + stuffcache = mobs_in_view(10, src) + //for (var/turf/T in stuffcache) + //new /obj/effect/testtrans(T) + if ((target in stuffcache) && isInSight(src, target)) + for (var/mob/m in stuffcache) + fire_at(target) + return + else + target = null + + //We may have already populated stuffcache this run, dont repeat work + if (!stuffcache) + stuffcache = mobs_in_view(10, src) + + target = null //Either we lost a target or lack one + //for (var/turf/T in stuffcache) + //new /obj/effect/testtrans(T) + + for (var/mob/living/L in stuffcache) + if (L == sacrificer) + continue + //A pylon won't shoot the person who created it, regardless of cult status. + //This is mainly for xenoarch antags + + if (L.stat == DEAD) + continue + //No point shooting at corpses + + if (iscult(L)) + continue + //Pylon wont shoot at cultists or constructs + + if (!isInSight(src, L)) + continue + + target = L + + + break + + if (target) + fire_at(target) + else + notarget++ + if (notarget > 60 || process_interval > 1) + notarget = 0 + reconsider_interval() + + +/obj/structure/cult/pylon/proc/fire_at(var/atom/target) + //Only store loc if target is on a turf. Otherwise this bugs out with people in exosuits + if (istype(target.loc, /turf)) + last_target_loc = target.loc + + process_interval = 1 //Instantly wake up if we found a target + var/obj/item/projectile/beam/cult/A + if (empowered > 0) + A = new /obj/item/projectile/beam/cult/heavy(loc) + empowered = max(0, empowered-1) + playsound(loc, 'sound/weapons/laserdeep.ogg', 100, 1) + if (empowered <= 0) + update_icon() + else + A = new /obj/item/projectile/beam/cult(loc) + playsound(loc, 'sound/weapons/laserdeep.ogg', 65, 1) + A.ignore = sacrificer + A.launch(target) + next_shot = world.time + shot_delay + spawn(shot_delay+1) + handle_firing() + + /obj/structure/cult/pylon/attack_hand(mob/M as mob) - attackpylon(M, 5) + if (M.a_intent == "help") + M << "The pylon feels warm to the touch...." + else + attackpylon(M, 4, M) /obj/structure/cult/pylon/attack_generic(var/mob/user, var/damage) - attackpylon(user, damage) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + //Artificiers maintain pylons + if(istype(user, /mob/living/simple_animal/construct)) + var/mob/living/simple_animal/construct/C = user + if (C.can_repair) + repair(user) + return + attackpylon(user, damage, user) /obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob) - attackpylon(user, W.force) + if (istype(W, /obj/item/weapon/holder)) + var/obj/item/weapon/holder/H = W + if (H.contained) + present_sacrifice(user, H.contained) + return -/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!isbroken) - if(prob(1+ damage * 5)) - user.visible_message( - "[user] smashed the pylon!", - "You hit the pylon, and its crystal breaks apart!", - "You hear a tinkle of crystal shards" + attackpylon(user, W.force, W) + + +//Mousedrop so that constructs can drag mice out of maintenance to make turrets +/obj/structure/cult/pylon/MouseDrop_T(var/atom/movable/C, mob/user) + if (istype(C, /mob/living)) + present_sacrifice(user, C) + return + return ..() + +/obj/structure/cult/pylon/bullet_act(var/obj/item/projectile/Proj) + attackpylon(user, Proj.damage, Proj) + +//Explosions will usually cause instant shattering, or heavy damage +//Class 3 or lower blast is sometimes survivable. 2 or higher will always shatter +/obj/structure/cult/pylon/ex_act(var/severity) + if (severity > 0) + attackpylon(null, (rand(200,400)/severity), null) + +/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage, var/source) + var/ranged = 0 + if (user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if (istype(source, /obj/item)) + var/obj/item/I = source + if (I.damtype != BRUTE) + user << "You swing at the pylon to no effect." + return + + if (istype(source, /obj/item/projectile)) + if (istype(source, /obj/item/projectile/beam/cult)) + return //No feedback loops + var/obj/item/projectile/proj = source + if (proj.damage_type == BURN) + if (empowered <= 0) + visible_message( + "The beam refracts inside the pylon, splitting into an indistinct violet glow. The crystal takes on a new, more ominous aura!" ) + empowered += damage*0.3 + //When shot with a laser, the pylon absorbs the beam, becoming empowered for a while, glowing brighter + // and firing more powerful blasts which have some armor penetration + // Using lasers to empower a defensive pylon yields more total damage than directly shooting your enemies + + start_process() + update_icon() + return + else if (proj.damage_type != BRUTE) + return + ranged = 1 + + if (!damage) + return + + damagetaken += damage + + if(!isbroken) + if (user) user.do_attack_animation(src) - playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1) - isbroken = 1 - density = 0 - icon_state = "pylon-broken" - set_light(0) + if(prob(damagetaken*0.5)) + shatter() else - user << "You hit the pylon!" + if (user && !ranged) + user << "You hit the pylon!" playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) else - if(prob(damage * 2)) - user << "You pulverize what was left of the pylon!" + if(prob(damagetaken)) + if (user) + user << "You pulverize what was left of the pylon!" qdel(src) - else + else if (user && !ranged) user << "You hit the pylon!" playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) + start_process() + +/obj/structure/cult/pylon/proc/shatter() + visible_message( + "The pylon shatters into shards of crystal!", + "You hear a tinkle of crystal shards" + ) + playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1) + isbroken = 1 + if (pylonmode == 2) + //If the pylon had a soul in it then it plays a creepy evil sound as the soul is released + var/possibles = list('sound/hallucinations/far_noise.ogg', + 'sound/hallucinations/growl3.ogg', + 'sound/hallucinations/veryfar_noise.ogg', + 'sound/hallucinations/wail.ogg', + 'sound/voice/hiss5.ogg') + playsound(get_turf(src), pick(possibles), 50, 1) + + pylonmode = 0 //A broken pylon loses its soul. Even if repaired it will need a new sacrifice to re-empower it + + //Make sure we stop it from firing + target = null + sacrificer = null + notarget = 0 + last_target_loc = null + process_interval = 1 + //It will stop processing after the next check, start of the next process + + empowered = 0 + density = 0 + update_icon() + + /obj/structure/cult/pylon/proc/repair(mob/user as mob) if(isbroken) - user << "You repair the pylon." + if(user) + user << span("notice","You weave forgotten magic, summoning the shards of the crystal and knitting them anew, until it hovers flawless once more.") isbroken = 0 density = 1 - icon_state = "pylon" - set_light(5) + else if (damagetaken > 0) + user << span("notice","You meld the crystal lattice back into integrity, sealing over the cracks until they never were.") + else + user << span("notice","The crystal lights up at your touch.") + + process_interval = 1 //Wake up the crystal + notarget = 0 + damagetaken = 0 + update_icon() + + +/obj/structure/cult/pylon/update_icon() + overlays.Cut() + if (pylonmode == 2) + anchored = 1 + if (empowered > 0) + overlays += "crystal_overcharge" + set_light(7, 3, l_color = "#a160bf") + else + set_light(6, 3, l_color = "#3e0000") + overlays += "crystal_turret" + else if (!isbroken) + set_light(5, 2, l_color = "#3e0000") + overlays += "crystal_idle" + if (pylonmode == 1) + anchored = 1 + else + anchored = 0 + else + anchored = 0 + set_light(0) + + + +//============================================ /obj/structure/cult/tome name = "Desk" desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl" @@ -144,7 +650,7 @@ if(M.has_brain_worms()) return //Borer stuff - RR - if(iscultist(M)) return + if(iscult(M)) return if(!ishuman(M) && !isrobot(M)) return M.transforming = 1 @@ -174,3 +680,12 @@ new_mob.key = M.key new_mob << "Your form morphs into that of a corgi." //Because we don't have cluwnes + +/obj/effect/testtrans + icon = 'icons/obj/cult.dmi' + icon_state = "tt" + +/obj/effect/testtrans/New() + ..() + spawn(10) + qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 71de8a75d2e..c093642416d 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -283,7 +283,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/declare_completion() var/is_antag_mode = (antag_templates && antag_templates.len) - var/discord_text = "@subscribers A round of **[name]** has ended! \[Game ID: [game_id]\]\n\n" + var/discord_text = "A round of **[name]** has ended! \[Game ID: [game_id]\]\n\n" check_victory() if(is_antag_mode) sleep(10) @@ -298,7 +298,7 @@ var/global/list/additional_antag_types = list() sleep(10) print_ownerless_uplinks() - discord_bot.send_to_announce(discord_text) + discord_bot.send_to_announce(discord_text, 1) discord_text = "" var/clients = 0 diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm index 3bf6ab01108..046da249b1d 100644 --- a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm @@ -111,6 +111,13 @@ return log_ability_use(user, "elite encryption hack (SUCCESS - title: [title])") command_announcement.Announce(text, title) + for (var/obj/machinery/computer/communications/C in machines) + if(! (C.stat & (BROKEN|NOPOWER) ) ) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc ) + P.name = "[command_name()] Update" + P.info = replacetext(text, "\n", "
") + P.update_space(P.info) + P.update_icon() /datum/game_mode/malfunction/verb/elite_encryption_hack() set category = "Software" diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index e483bb0c30a..341d2ba8e1d 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -850,6 +850,10 @@ if (alert(src, choice_text, "Choices", "Yes", "No") == "No") src << "[denial_response]" return + + vampire_thrall.remove_antagonist(T.mind, 0, 0) + qdel(draining_vamp) + draining_vamp = null else src << "You feel corruption running in [T.name]'s blood. Much like yourself, \he[T] is already a spawn of the Veil, and cannot be Embraced." return diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 82858a19d42..02e8eba06a5 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -29,13 +29,12 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_cap(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) if(5) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/duffel/cap(H), slot_back) - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/captain(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/captain(H), slot_w_uniform) if(H.age>49) - // Since we can have something other than the default uniform at this + // Since we can have something other than the default uniform at this // point, check if we can actually attach the medal var/obj/item/clothing/uniform = H.w_uniform var/obj/item/clothing/accessory/medal/gold/captain/medal = new() - if(uniform && uniform.can_attach_accessory(medal)) uniform.attach_accessory(null, medal) else diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index a1be098d394..36634a74d08 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -80,7 +80,12 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_service(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/hydroponics(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/clothing/gloves/botanic_leather(H), slot_gloves) + if(istajara(H)) + H.equip_to_slot_or_del(new /obj/item/clothing/gloves/botanic_leather/tajara(H), slot_gloves) + if(isunathi(H)) + H.equip_to_slot_or_del(new /obj/item/clothing/gloves/botanic_leather/unathi(H), slot_gloves) + else + H.equip_to_slot_or_del(new /obj/item/clothing/gloves/botanic_leather(H), slot_gloves) H.equip_to_slot_or_del(new /obj/item/clothing/suit/apron(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/device/analyzer/plant_analyzer(H), slot_s_store) H.equip_to_slot_or_del(new /obj/item/device/pda/botanist(H), slot_belt) @@ -285,6 +290,8 @@ if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) if(5) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/duffel(H), slot_back) + + H.implant_loyalty(H) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/internalaffairs(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/internalaffairs(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/brown(H), slot_shoes) @@ -292,7 +299,5 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/lawyer(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase(H), slot_l_hand) - H.implant_loyalty(H) - return 1 diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index abb3a6c68f0..77c6dc7ec8d 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -33,15 +33,13 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/head_of_security(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/device/pda/heads/hos(H), slot_belt) - if(H.species.name == "Tajara") + if(istajara(H)) H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/tajara(H), slot_gloves) - if(H.species.name == "Unathi") + if(isunathi(H)) H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/unathi(H), slot_gloves) else H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves) -// H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(H), slot_wear_mask) //Grab one from the armory you donk H.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud(H), slot_glasses) - H.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(H), slot_s_store) if(H.backbag == 1) H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_l_store) else @@ -77,9 +75,9 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/warden(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/device/pda/warden(H), slot_belt) - if(H.species.name == "Tajara") + if(istajara(H)) H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/tajara(H), slot_gloves) - if(H.species.name == "Unathi") + if(isunathi(H)) H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/unathi(H), slot_gloves) else H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves) @@ -120,9 +118,9 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/det(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/device/pda/detective(H), slot_belt) - if(H.species.name == "Tajara") + if(istajara(H)) H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/tajara(H), slot_gloves) - if(H.species.name == "Unathi") + if(isunathi(H)) H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/unathi(H), slot_gloves) else H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves) diff --git a/code/game/machinery/abstract/abstract.dm b/code/game/machinery/abstract/abstract.dm new file mode 100644 index 00000000000..675113713d3 --- /dev/null +++ b/code/game/machinery/abstract/abstract.dm @@ -0,0 +1,47 @@ +/* + - Abstract machinery - + + Pretty much designed for whenever you want something that is not a machine to interact with the power grid. + Better to use one of these to be notified of power changes than poll with process(). + +*/ + +/obj/machinery/abstract + name = "impossible device" + desc = "No matter how hard you look at it, you have no idea what it is. (please inform coders if you see this)" + simulated = FALSE + anchored = 1 + var/should_process = FALSE + mouse_opacity = 0 + +/obj/machinery/abstract/attack_ai(mob/user as mob) + return + +/obj/machinery/abstract/attack_hand(mob/user as mob) + return + +/obj/machinery/abstract/emp_act(severity) + return // No EMPing these. + +/obj/machinery/abstract/ex_act(severity) + return + +/obj/machinery/abstract/tesla_act() + return + +/obj/machinery/abstract/singularity_act() + return + +/obj/machinery/abstract/singularity_pull() + return + +/obj/machinery/abstract/singuloCanEat() + return FALSE + +/obj/machinery/abstract/operable(additional_flags = 0) + return TRUE + +/obj/machinery/abstract/get_process_type() + . = ..() + if (!should_process) + . &= ~M_PROCESSES diff --git a/code/game/machinery/abstract/intercom_listener.dm b/code/game/machinery/abstract/intercom_listener.dm new file mode 100644 index 00000000000..a344eeeb9ae --- /dev/null +++ b/code/game/machinery/abstract/intercom_listener.dm @@ -0,0 +1,25 @@ +/obj/machinery/abstract/intercom_listener + name = "intercom power interface" + desc = "You shouldn't see this." + power_channel = EQUIP + + var/obj/item/device/radio/intercom/master + +/obj/machinery/abstract/intercom_listener/New(atom/loc, obj/item/device/radio/intercom/owner) + if (QDELETED(owner)) + warning("intercom_listener created with QDELETED intercom!") + qdel(src) + else + master = owner + +/obj/machinery/abstract/intercom_listener/Destroy() + master = null + return ..() + +/obj/machinery/abstract/intercom_listener/power_change() + if (master) + var/state = powered(power_channel) + master.power_change(state) + else + warning("intercom_listener got power_change but has no master!") + qdel(src) diff --git a/code/game/machinery/computer/RCON_Console.dm b/code/game/machinery/computer/RCON_Console.dm index ec0d0f3c7d5..3d45813923d 100644 --- a/code/game/machinery/computer/RCON_Console.dm +++ b/code/game/machinery/computer/RCON_Console.dm @@ -40,4 +40,4 @@ /obj/machinery/computer/rcon/update_icon() ..() if(is_operable()) - overlays += image('icons/obj/computer.dmi', "ai-fixer-empty", overlay_layer) + holographic_overlay(src, src.icon, "ai-fixer-empty") diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index cc3fb188f9b..30684a17c4b 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -215,6 +215,7 @@ network = list(NETWORK_THUNDER) density = 0 circuit = null + is_holographic = FALSE /obj/machinery/computer/security/telescreen/entertainment name = "entertainment monitor" @@ -260,6 +261,7 @@ icon_screen = "syndicam" network = list(NETWORK_MERCENARY) circuit = null + is_holographic = FALSE // I mean, it is, but the holo effect looks terrible with the current merc shuttle floor. /obj/machinery/computer/security/nuclear/New() ..() diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 66ed07fb01f..775b3aa937f 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -14,6 +14,7 @@ var/light_range_on = 2 var/light_power_on = 1 var/overlay_layer + var/is_holographic = TRUE /obj/machinery/computer/New() overlay_layer = layer @@ -64,8 +65,10 @@ if(stat & BROKEN) overlays += image(icon,"[icon_state]_broken", overlay_layer) + else if (is_holographic) + holographic_overlay(src, src.icon, icon_screen) else - overlays += image(icon,icon_screen, overlay_layer) + overlays += image(icon, icon_screen, overlay_layer) /obj/machinery/computer/power_change() ..() diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index f9c7be55df0..c63134fe0c2 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -47,6 +47,7 @@ light_color = LIGHT_COLOR_BLUE icon_screen = "pass" + is_holographic = FALSE density = 0 var/obj/item/weapon/card/id/giver diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 57c19f9a318..af4983258ee 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -16,7 +16,6 @@ var/datum/data/record/active2 = null var/a_id = null var/temp = null - //var/printing = null /obj/machinery/computer/med_data/AltClick(var/mob/user) eject_id() @@ -562,3 +561,4 @@ icon_state = "medlaptop0" icon_screen = "medlaptop" + is_holographic = FALSE diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index c8ddad2a140..b8f1638c4bd 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -33,6 +33,12 @@ ..() spark_system = bind_spark(src, 5) +/obj/machinery/computer/message_monitor/Destroy() + QDEL_NULL(spark_system) + linkedServer = null + customrecepient = null + return ..() + /obj/machinery/computer/message_monitor/attackby(obj/item/weapon/O as obj, mob/living/user as mob) if(stat & (NOPOWER|BROKEN)) ..() diff --git a/code/game/machinery/computer/shuttle.dm b/code/game/machinery/computer/shuttle.dm index 735f61947a2..7f6152bdd6d 100644 --- a/code/game/machinery/computer/shuttle.dm +++ b/code/game/machinery/computer/shuttle.dm @@ -2,6 +2,7 @@ name = "Shuttle" desc = "For shuttle control." + is_holographic = FALSE icon_screen = "shuttle" light_color = "#00ffff" var/auth_need = 3.0 diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index 4e20655ec88..f60ab34fcb0 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -16,7 +16,7 @@ var/datum/data/record/active1 = null var/a_id = null var/temp = null - //var/printing = null + is_holographic = FALSE var/can_change_id = 0 var/list/Perp var/tempname = null diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 36dd5e90b43..275ebce38d2 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -261,6 +261,6 @@ for reference: else if (src.emagged == 1) src.emagged = 2 user << "You short out the anchoring mechanism on \the [src]." - spark(src, 2, 1) + spark(src, 2, alldirs) visible_message("BZZzZZzZZzZT") return 1 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 391d885fccb..b4118abd48a 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -30,8 +30,7 @@ var/obj/item/stack/material/steel/repairing var/block_air_zones = 1 //If set, air zones cannot merge across the door even when it is opened. var/open_duration = 150//How long it stays open - var/datum/scheduled_task/close_task - var/datum/scheduled_task/hatch_task + var/hashatch = 0//If 1, this door has hatches, and certain small creatures can move through them without opening the door var/hatchstate = 0//0: closed, 1: open @@ -229,7 +228,7 @@ switch (Proj.damage_type) if(BRUTE) new /obj/item/stack/material/steel(src.loc, 2) - getFromPool(/obj/item/stack/rods, list(src.loc, 3)) + getFromPool(/obj/item/stack/rods, src.loc, 3) if(BURN) new /obj/effect/decal/cleanable/ash(src.loc) // Turn it to ashes! qdel(src) diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm index db1e0ff71f5..abb2cc6f8be 100644 --- a/code/game/machinery/floodlight.dm +++ b/code/game/machinery/floodlight.dm @@ -33,10 +33,10 @@ // If the cell is almost empty rarely "flicker" the light. Aesthetic only. if((cell.percent() < 10) && prob(5)) - set_light(brightness_on/2, brightness_on/4) + set_light(brightness_on/2, 0.5) spawn(20) if(on) - set_light(brightness_on, brightness_on/2) + set_light(brightness_on, 1) cell.use(use*CELLRATE) @@ -49,7 +49,7 @@ return 0 on = 1 - set_light(brightness_on, brightness_on / 2) + set_light(brightness_on, 1) update_icon() if(loud) visible_message("\The [src] turns on.") @@ -57,7 +57,7 @@ /obj/machinery/floodlight/proc/turn_off(var/loud = 0) on = 0 - set_light(0, 0) + set_light(0) update_icon() if(loud) visible_message("\The [src] shuts down.") diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index c4169470fde..4c4c40ec7c7 100755 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -126,7 +126,7 @@ flick("migniter-spark", src) - spark(src, 2, 1) + spark(src, 2, alldirs) src.last_spark = world.time use_power(1000) var/turf/location = src.loc diff --git a/code/game/machinery/kitchen/cooking_machines/_appliance.dm b/code/game/machinery/kitchen/cooking_machines/_appliance.dm index fab66c20872..29d727f1d19 100644 --- a/code/game/machinery/kitchen/cooking_machines/_appliance.dm +++ b/code/game/machinery/kitchen/cooking_machines/_appliance.dm @@ -389,14 +389,15 @@ CI.result_type = 4//Recipe type, a specific recipe will transform the ingredients into a new food var/list/results = recipe.make_food(C) - var/atom/temp = new /atom //To prevent infinite loops, all results will be moved into a temporary location so they're not considered as inputs for other recipes + var/obj/temp = new /obj(src) //To prevent infinite loops, all results will be moved into a temporary location so they're not considered as inputs for other recipes for (var/atom/movable/AM in results) AM.loc = temp //making multiple copies of a recipe from one container. For example, tons of fries while (select_recipe(available_recipes,C) == recipe) - var/list/TR = recipe.make_food(C) + var/list/TR = list() + TR.Add(recipe.make_food(C)) for (var/atom/movable/AM in TR) //Move results to buffer AM.loc = temp results.Add(TR) @@ -636,7 +637,7 @@ //var/obj/object var/max_cookwork var/cookwork - var/overcook_mult = 2 + var/overcook_mult = 3 var/result_type = 0 var/obj/item/weapon/reagent_containers/cooking_container/container = null var/combine_target = null diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker.dm b/code/game/machinery/kitchen/cooking_machines/_cooker.dm index d8bfd43dabe..18089e06572 100644 --- a/code/game/machinery/kitchen/cooking_machines/_cooker.dm +++ b/code/game/machinery/kitchen/cooking_machines/_cooker.dm @@ -16,7 +16,7 @@ if (.)//no need to duplicate adjacency check if (!stat) if (temperature < min_temp) - user << span("warning", "It is heating up.") + user << span("warning", "The [src] is still heating up and is too cold to cook anything yet.") else user << span("notice", "It is running at [round(get_efficiency(), 0.1)]% efficiency!") user << "Temperature: [round(temperature - T0C, 0.1)]C / [round(optimal_temp - T0C, 0.1)]C" @@ -121,9 +121,10 @@ //Cookers do differently, they use containers /obj/machinery/appliance/cooker/has_space(var/obj/item/I) - if (istype(I, /obj/item/weapon/reagent_containers/cooking_container) && cooking_objs.len < max_contents) + if (istype(I, /obj/item/weapon/reagent_containers/cooking_container)) //Containers can go into an empty slot - return 1 + if (cooking_objs.len < max_contents) + return 1 else @@ -137,6 +138,6 @@ /obj/machinery/appliance/cooker/add_content(var/obj/item/I, var/mob/user) var/datum/cooking_item/CI = ..() - if (CI.combine_target) + if (CI && CI.combine_target) user << "The [I] will be used to make a [selected_option]. Output selection is returned to default for future items." selected_option = null \ No newline at end of file diff --git a/code/game/machinery/kitchen/cooking_machines/container.dm b/code/game/machinery/kitchen/cooking_machines/container.dm index f9be08952ae..f1decf8c811 100644 --- a/code/game/machinery/kitchen/cooking_machines/container.dm +++ b/code/game/machinery/kitchen/cooking_machines/container.dm @@ -8,6 +8,10 @@ var/max_space = 20//Maximum sum of w-classes of foods in this container at once var/max_reagents = 80//Maximum units of reagents + var/list/insertable = list(/obj/item/weapon/reagent_containers/food/snacks, + /obj/item/weapon/holder, + /obj/item/weapon/paper) + /obj/item/weapon/reagent_containers/cooking_container/New() ..() create_reagents(max_reagents) @@ -26,15 +30,17 @@ /obj/item/weapon/reagent_containers/cooking_container/attackby(var/obj/item/I as obj, var/mob/user as mob) - if (istype(I, /obj/item/weapon/reagent_containers/food/snacks)) - if (!can_fit(I)) - user << span("warning","There's no more space in the [src] for that!") - return 0 + for (var/possible_type in insertable) + if (istype(I, possible_type)) + if (!can_fit(I)) + user << span("warning","There's no more space in the [src] for that!") + return 0 - if(!user.unEquip(I)) + if(!user.unEquip(I)) + return + I.forceMove(src) + user << span("notice", "You put the [I] into the [src]") return - I.forceMove(src) - user << span("notice", "You put the [I] into the [src]") /obj/item/weapon/reagent_containers/cooking_container/verb/empty() set src in view() diff --git a/code/game/machinery/kitchen/cooking_machines/oven.dm b/code/game/machinery/kitchen/cooking_machines/oven.dm index 48e3364c7ee..c741535df3b 100644 --- a/code/game/machinery/kitchen/cooking_machines/oven.dm +++ b/code/game/machinery/kitchen/cooking_machines/oven.dm @@ -67,7 +67,7 @@ loss = (active_power_usage / resistance)*0.5 else open = 1 - loss = (active_power_usage / resistance)*10 + loss = (active_power_usage / resistance)*6 //When the oven door is opened, heat is lost MUCH faster playsound(src, 'sound/machines/hatch_open.ogg', 20, 1) diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm index 05a1f0f3bba..c9763016618 100644 --- a/code/game/machinery/kitchen/microwave.dm +++ b/code/game/machinery/kitchen/microwave.dm @@ -16,7 +16,7 @@ var/global/list/datum/recipe/available_recipes // List of the recipes you can use var/global/list/acceptable_items // List of the items you can put in var/global/list/acceptable_reagents // List of the reagents you can put in - var/global/max_n_of_items = 0 + var/global/max_n_of_items = 20 var/appliancetype = MICROWAVE // see code/modules/food/recipes_microwave.dm for recipes @@ -44,8 +44,6 @@ acceptable_items |= item for (var/reagent in recipe.reagents) acceptable_reagents |= reagent - if (recipe.items) - max_n_of_items = max(max_n_of_items,recipe.items.len) // This will do until I can think of a fun recipe to use dionaea in - // will also allow anything using the holder item to be microwaved into // impure carbon. ~Z @@ -295,13 +293,28 @@ var/result = recipe.result var/valid = 1 var/list/cooked_items = list() + var/obj/temp = new /obj(src) //To prevent infinite loops, all results will be moved into a temporary location so they're not considered as inputs for other recipes while(valid) - cooked_items += recipe.make_food(src) + var/list/things = list() + things.Add(recipe.make_food(src)) + cooked_items += things + //Move cooked things to the buffer so they're not considered as ingredients + for (var/atom/movable/AM in things) + AM.loc = temp + valid = 0 recipe = select_recipe(available_recipes,src) if (recipe && recipe.result == result) + sleep(2) valid = 1 + for (var/r in cooked_items) + var/atom/movable/R = r + R.loc = src //Move everything from the buffer back to the container + + qdel(temp)//Delete buffer object + temp = null + //Any leftover reagents are divided amongst the foods var/total = reagents.total_volume for (var/obj/item/weapon/reagent_containers/food/snacks/S in cooked_items) @@ -312,6 +325,7 @@ dispose(0) //clear out anything left stop() + return /obj/machinery/microwave/proc/wzhzhzh(var/seconds as num) // Whoever named this proc is fucking literally Satan. ~ Z diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 640e5cfa2f8..e83fba6d060 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -179,6 +179,11 @@ underlays += image('icons/obj/stationobjs.dmi', icon_state = "tele-wires") spark_system = bind_spark(src, 5, alldirs) +/obj/machinery/teleport/hub/Destroy() + QDEL_NULL(spark_system) + com = null + return ..() + /obj/machinery/teleport/hub/Bumped(M as mob|obj) spawn() if (src.icon_state == "tele1") diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index bc658b7faf8..ee25385e2a8 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -237,7 +237,7 @@ anchored = !anchored return - else + else if (!is_borg_item(W)) for(var/datum/data/vending_product/R in product_records) if(istype(W, R.product_path)) @@ -245,6 +245,8 @@ qdel(W) return ..() + else + ..() /** * Receive payment with cashmoney. @@ -722,7 +724,7 @@ vend_power_usage = 85000 //85 kJ to heat a 250 mL cup of coffee products = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 25,/obj/item/weapon/reagent_containers/food/drinks/tea = 25,/obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 25) contraband = list(/obj/item/weapon/reagent_containers/food/drinks/ice = 10) - prices = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 30, /obj/item/weapon/reagent_containers/food/drinks/tea = 30, /obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 32) + prices = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 20, /obj/item/weapon/reagent_containers/food/drinks/tea = 20, /obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 22) @@ -738,10 +740,10 @@ /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 6, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 6, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 3, /obj/item/weapon/reagent_containers/food/snacks/meatsnack = 2, /obj/item/weapon/reagent_containers/food/snacks/maps = 2, /obj/item/weapon/reagent_containers/food/snacks/nathisnack = 2) contraband = list(/obj/item/weapon/reagent_containers/food/snacks/syndicake = 6) - prices = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 25,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 30,/obj/item/weapon/reagent_containers/food/snacks/chips = 27, - /obj/item/weapon/reagent_containers/food/snacks/sosjerky = 30,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 22,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 25, - /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 25, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 28, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 50, - /obj/item/weapon/reagent_containers/food/snacks/meatsnack = 32, /obj/item/weapon/reagent_containers/food/snacks/maps = 33, /obj/item/weapon/reagent_containers/food/snacks/nathisnack = 34) + prices = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 15,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 20,/obj/item/weapon/reagent_containers/food/snacks/chips = 17, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky = 20,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 12,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 15, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 15, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 18, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 40, + /obj/item/weapon/reagent_containers/food/snacks/meatsnack = 22, /obj/item/weapon/reagent_containers/food/snacks/maps = 23, /obj/item/weapon/reagent_containers/food/snacks/nathisnack = 24) /obj/machinery/vending/cola @@ -755,10 +757,10 @@ /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 10, /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 10, /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 10) contraband = list(/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko = 5, /obj/item/weapon/reagent_containers/food/snacks/liquidfood = 6) - prices = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 25,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 21, - /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 26,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 25, - /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 22,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 25, - /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 23,/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 26) + prices = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 15,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 11, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 16,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 15, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 12,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 15, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 13,/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 16) idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. //This one's from bay12 @@ -783,7 +785,7 @@ products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/flame/lighter/random = 4) contraband = list(/obj/item/weapon/flame/lighter/zippo = 4) premium = list(/obj/item/weapon/storage/fancy/cigar = 5,/obj/item/weapon/storage/fancy/cigarettes/killthroat = 5 ) - prices = list(/obj/item/weapon/storage/fancy/cigarettes = 520,/obj/item/weapon/storage/box/matches = 22,/obj/item/weapon/flame/lighter/random = 22) + prices = list(/obj/item/weapon/storage/fancy/cigarettes = 510,/obj/item/weapon/storage/box/matches = 12,/obj/item/weapon/flame/lighter/random = 12) /obj/machinery/vending/medical diff --git a/code/game/mecha/equipment/tracking_beacon.dm b/code/game/mecha/equipment/tracking_beacon.dm index 92787c3873d..d45b7d7aab5 100644 --- a/code/game/mecha/equipment/tracking_beacon.dm +++ b/code/game/mecha/equipment/tracking_beacon.dm @@ -12,6 +12,10 @@ if (in_mecha()) exo_beacons.Add(src)//For the sake of exosuits which spawn with a preinstalled tracking beacon +/obj/item/mecha_parts/mecha_tracking/Destroy() + exo_beacons.Remove(src) + return ..() + /obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info() if(!in_mecha()) return 0 diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm index 1e06328564c..d95d9966b29 100644 --- a/code/game/objects/effects/chem/chemsmoke.dm +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -250,7 +250,7 @@ if(passed_smoke) smoke = passed_smoke else - smoke = getFromPool(/obj/effect/effect/smoke/chem, list(location, smoke_duration + rand(smoke_duration*-0.25, smoke_duration*0.25), T, I)) + smoke = getFromPool(/obj/effect/effect/smoke/chem, location, smoke_duration + rand(smoke_duration*-0.25, smoke_duration*0.25), T, I) if(chemholder.reagents.reagent_list.len) chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm index 73ea7cf3c67..b7d2acc5411 100644 --- a/code/game/objects/effects/chem/foam.dm +++ b/code/game/objects/effects/chem/foam.dm @@ -108,7 +108,7 @@ F.amount += amount return - F = getFromPool(/obj/effect/effect/foam, list(location, metal)) + F = getFromPool(/obj/effect/effect/foam, location, metal) F.amount = amount if(!metal) // don't carry other chemicals if a metal foam @@ -180,4 +180,4 @@ /obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) if(air_group) return 0 - return !density \ No newline at end of file + return !density diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index 5265e05531a..02d66ed114d 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -101,7 +101,7 @@ O = loc for(var/i=0, i 30) || ((world.timeofday - last_tick) < 0)) - last_tick = world.timeofday +/obj/item/device/radio/intercom/proc/power_change(has_power) + if (!src.loc) + on = 0 + else + on = has_power - if(!src.loc) - on = 0 - else - var/area/A = get_area(src) - if(!A) - on = 0 - else - on = A.powered(EQUIP) // set "on" to the power status + update_icon() - if(!on) - icon_state = "intercom-p" - else - icon_state = "intercom" +/obj/item/device/radio/intercom/forceMove(atom/dest) + power_interface.forceMove(dest) + ..(dest) + +/obj/item/device/radio/intercom/update_icon() + if (on) + icon_state = "intercom" + else + icon_state = "intercom-p" /obj/item/device/radio/intercom/broadcasting broadcasting = 1 diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index bd40f42b4c4..60663c8596c 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -121,6 +121,10 @@ var/const/NO_EMAG_ACT = -50 var/rank = null //actual job var/dorm = 0 // determines if this ID has claimed a dorm already +/obj/item/weapon/card/id/Destroy() + mob = null + return ..() + /obj/item/weapon/card/id/examine(mob/user) set src in oview(1) if(in_range(usr, src)) diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 76b7043f01e..48998682eab 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -266,7 +266,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM ignitermes = "USER fiddles with FLAME, and manages to light their NAME with the power of science." /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba - name = "\improper Cohiba Robusto cigar" + name = "\improper Cohiba robusto cigar" desc = "There's little more you could want from a cigar." icon_state = "cigar2off" icon_on = "cigar2on" diff --git a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm index db11c4de502..e36b147d113 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm @@ -5,7 +5,7 @@ /obj/item/weapon/circuitboard/holodeckcontrol name = T_BOARD("holodeck control console") build_path = /obj/machinery/computer/HolodeckControl - origin_tech = "programming=2;bluespace=2" + origin_tech = list(TECH_DATA = 2, TECH_BLUESPACE = 2) var/last_to_emag var/linkedholodeck_area var/list/supported_programs diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index a7c8f69e32d..54a774b176c 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -367,6 +367,17 @@ the implant may become unstable and either pre-maturely inject the subject or si processing_objects.Add(src) return 1 +/obj/item/weapon/implant/loyalty/ipc + name = "loyalty chip" + desc = "A device that sets directives programmed for loyalty to NanoTrasen on the synthetic subject. Will not work on organics." + +/obj/item/weapon/implant/loyalty/ipc/implanted(mob/M) + + if (!isipc(M)) + return + + ..() + /obj/item/weapon/implant/adrenalin name = "adrenalin" desc = "Removes all stuns and knockdowns." diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm index f78b563917f..f5bc195ead9 100644 --- a/code/game/objects/items/weapons/material/knives.dm +++ b/code/game/objects/items/weapons/material/knives.dm @@ -58,7 +58,7 @@ edge = 1 force_divisor = 0.15 // 9 when wielded with hardness 60 (steel) matter = list(DEFAULT_WALL_MATERIAL = 12000) - origin_tech = "materials=1" + origin_tech = list(TECH_MATERIAL = 1) attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") unbreakable = 1 diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index 8cae5642073..ae28d217466 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -18,7 +18,7 @@ w_class = 2 sharp = 1 edge = 1 - origin_tech = "materials=2;combat=1" + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 1) attack_verb = list("chopped", "torn", "cut") applies_material_colour = 0 @@ -61,5 +61,5 @@ throw_range = 3 w_class = 4 slot_flags = SLOT_BACK - origin_tech = "materials=2;combat=2" + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 2) attack_verb = list("chopped", "sliced", "cut", "reaped") diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm index c0c5ceb1b4a..7f24f9919a8 100644 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -107,6 +107,7 @@ var/obj/item/weapon/material/twohanded/offhand/O = user.get_inactive_hand() if(O && istype(O)) + user.u_equip(O) O.unwield() else //Trying to wield it @@ -149,9 +150,17 @@ default_material = "placeholder" /obj/item/weapon/material/twohanded/offhand/unwield() + if (ismob(loc)) + var/mob/living/our_mob = loc + our_mob.remove_from_mob(src) + qdel(src) /obj/item/weapon/material/twohanded/offhand/wield() + if (ismob(loc)) + var/mob/living/our_mob = loc + our_mob.remove_from_mob(src) + qdel(src) /obj/item/weapon/material/twohanded/offhand/update_icon() diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 4b7db053bd8..45d9aef2c6c 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -5,15 +5,23 @@ var/active_w_class sharp = 0 edge = 0 - armor_penetration = 50 + armor_penetration = 10 flags = NOBLOODY can_embed = 0//No embedding pls + var/base_reflectchance = 40 + var/base_block_chance = 25 + var/shield_power = 100 + var/can_block_bullets = 0 var/datum/effect_system/sparks/spark_system /obj/item/weapon/melee/energy/New() spark_system = bind_spark(src, 5) ..() +/obj/item/weapon/melee/energy/Destroy() + QDEL_NULL(spark_system) + return ..() + /obj/item/weapon/melee/energy/proc/activate(mob/living/user) anchored = 1 if(active) @@ -56,6 +64,66 @@ add_fingerprint(user) return +/obj/item/weapon/melee/energy/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(active && default_parry_check(user, attacker, damage_source) && prob(50)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + + spark_system.queue() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + return 1 + else + + if(!active) + return 0 //turn it on first! + + if(user.incapacitated()) + return 0 + + //block as long as they are not directly behind us + var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block + if(check_shield_arc(user, bad_arc, damage_source, attacker)) + + if(prob(base_block_chance)) + spark_system.queue() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + shield_power -= round(damage/4) + + if(shield_power <= 0) + visible_message("\The [user]'s [src.name] overloads!") + deactivate() + shield_power = initial(shield_power) + return 0 + + if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam)) + var/obj/item/projectile/P = damage_source + + var/reflectchance = base_reflectchance - round(damage/3) + if(!(def_zone in list("chest", "groin","head"))) + reflectchance /= 2 + if(P.starting && prob(reflectchance)) + visible_message("\The [user]'s [src.name] reflects [attack_text]!") + + // Find a turf near or on the original location to bounce to + var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + var/turf/curloc = get_turf(user) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, user) + + return PROJECTILE_CONTINUE // complete projectile permutation + else + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + return 1 + + else if(istype(damage_source, /obj/item/projectile/bullet) && can_block_bullets) + var/reflectchance = (base_reflectchance) - round(damage/3) + if(!(def_zone in list("chest", "groin","head"))) + reflectchance /= 2 + if(prob(reflectchance)) + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + return 1 + /obj/item/weapon/melee/energy/glaive name = "energy glaive" desc = "An energized glaive." @@ -74,6 +142,11 @@ sharp = 1 edge = 1 slot_flags = SLOT_BACK + base_reflectchance = 0 + base_block_chance = 0 //cannot be used to block guns + shield_power = 0 + can_block_bullets = 0 + armor_penetration = 20 /obj/item/weapon/melee/energy/glaive/activate(mob/living/user) ..() @@ -108,6 +181,11 @@ attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") sharp = 1 edge = 1 + base_reflectchance = 0 + base_block_chance = 0 //cannot be used to block guns + shield_power = 0 + can_block_bullets = 0 + armor_penetration = 35 /obj/item/weapon/melee/energy/axe/activate(mob/living/user) ..() @@ -140,6 +218,7 @@ sharp = 1 edge = 1 var/blade_color + shield_power = 75 /obj/item/weapon/melee/energy/sword/dropped(var/mob/user) ..() @@ -175,19 +254,12 @@ attack_verb = list() icon_state = initial(icon_state) -/obj/item/weapon/melee/energy/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - if(active && default_parry_check(user, attacker, damage_source) && prob(50)) - user.visible_message("\The [user] parries [attack_text] with \the [src]!") - - spark_system.queue() - playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) - return 1 - return 0 - /obj/item/weapon/melee/energy/sword/pirate name = "energy cutlass" desc = "Arrrr matey." icon_state = "cutlass0" + base_reflectchance = 60 + base_block_chance = 60 /obj/item/weapon/melee/energy/sword/pirate/activate(mob/living/user) ..() @@ -196,13 +268,12 @@ /* *Energy Blade */ - -//Can't be activated or deactivated, so no reason to be a subtype of energy /obj/item/weapon/melee/energy/blade name = "energy blade" desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal." icon_state = "blade" - force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe + force = 40 + active_force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe armor_penetration = 100 sharp = 1 edge = 1 @@ -214,6 +285,12 @@ flags = NOBLOODY attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") var/mob/living/creator + base_reflectchance = 140 + base_block_chance = 75 + shield_power = 150 + can_block_bullets = 1 + active = 1 + armor_penetration = 20 /obj/item/weapon/melee/energy/blade/New() processing_objects |= src @@ -223,10 +300,14 @@ processing_objects -= src ..() -/obj/item/weapon/melee/energy/blade/attack_self(mob/user as mob) +/obj/item/weapon/melee/energy/blade/deactivate(mob/living/user) + if(!active) + return + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) user.drop_from_inventory(src) spawn(1) if(src) qdel(src) + /obj/item/weapon/melee/energy/blade/dropped() spawn(1) if(src) qdel(src) diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index e50ce867967..e60df528ed1 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -12,9 +12,14 @@ var/mopping = 0 var/mopcount = 0 - /obj/item/weapon/mop/New() + ..() create_reagents(30) + janitorial_supplies |= src + +/obj/item/weapon/mop/Destroy() + janitorial_supplies -= src + return ..() /obj/item/weapon/mop/afterattack(atom/A, mob/user, proximity) if(!proximity) return diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index d57d312ab15..45483b8c8f0 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -103,17 +103,62 @@ w_class = 2 origin_tech = list(TECH_MATERIAL = 4, TECH_MAGNET = 3, TECH_ILLEGAL = 4) attack_verb = list("shoved", "bashed") + var/shield_power = 150 var/active = 0 -/obj/item/weapon/shield/energy/handle_shield(mob/user) +/obj/item/weapon/shield/energy/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(!active) return 0 //turn it on first! - . = ..() + if(user.incapacitated()) + return 0 + if(.) spark(user.loc, 5) playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + //block as long as they are not directly behind us + var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block + if(check_shield_arc(user, bad_arc, damage_source, attacker)) + + if(prob(get_block_chance(user, damage, damage_source, attacker))) + spark(user.loc, 5) + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + shield_power -= round(damage/4) + + if(shield_power <= 0) + visible_message("\The [user]'s [src.name] overloads!") + active = 0 + force = 3 + update_icon() + w_class = 1 + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + shield_power = initial(shield_power) + return 0 + + if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam)) + var/obj/item/projectile/P = damage_source + + var/reflectchance = 80 - round(damage/3) + if(P.starting && prob(reflectchance)) + visible_message("\The [user]'s [src.name] reflects [attack_text]!") + + // Find a turf near or on the original location to bounce to + var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + var/turf/curloc = get_turf(user) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, user) + + return PROJECTILE_CONTINUE // complete projectile permutation + else + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + return 1 + else + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + return 1 + /obj/item/weapon/shield/energy/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) if(istype(damage_source, /obj/item/projectile)) var/obj/item/projectile/P = damage_source diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 3ca7ce50aa0..633f8285947 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -329,11 +329,19 @@ name = "duffel bag" desc = "A spacious duffel bag." icon_state = "duffel-norm" + item_state_slots = list( + slot_l_hand_str = "duffle", + slot_r_hand_str = "duffle" + ) /obj/item/weapon/storage/backpack/duffel/cap name = "captain's duffel bag" desc = "A rare and special duffel bag for only the most air-headed of Nanotrasen personnel." icon_state = "duffel-captain" + item_state_slots = list( + slot_l_hand_str = "duffle_captain", + slot_r_hand_str = "duffle_captain" + ) /obj/item/weapon/storage/backpack/duffel/hyd name = "botanist's duffel bag" @@ -344,16 +352,28 @@ name = "virology duffel bag" desc = "A sterilized duffel bag suited to those about to unleash pathogenic havoc upon the world." icon_state = "duffel-virology" + item_state_slots = list( + slot_l_hand_str = "duffle_med", + slot_r_hand_str = "duffle_med" + ) /obj/item/weapon/storage/backpack/duffel/med name = "medical duffel bag" desc = "A sterilized duffel bag for the young, upcoming lesbayan." icon_state = "duffel-medical" + item_state_slots = list( + slot_l_hand_str = "duffle_med", + slot_r_hand_str = "duffle_med" + ) /obj/item/weapon/storage/backpack/duffel/eng name = "industrial duffel bag" desc = "A rough and tumble duffel bag for the hard working wrench-monkey of tomorrow." icon_state = "duffel-engineering" + item_state_slots = list( + slot_l_hand_str = "duffle_eng", + slot_r_hand_str = "duffle_eng" + ) /obj/item/weapon/storage/backpack/duffel/tox name = "scientist's duffel bag" @@ -374,11 +394,19 @@ name = "chemistry duffel bag" desc = "Spice up the love life a little." icon_state = "duffel-chemistry" + item_state_slots = list( + slot_l_hand_str = "duffle_med", + slot_r_hand_str = "duffle_med" + ) /obj/item/weapon/storage/backpack/duffel/syndie name = "syndicate duffel bag" desc = "A snazzy black and red duffel bag, perfect for smuggling C4 and Parapens." icon_state = "duffel-syndie" + item_state_slots = list( + slot_l_hand_str = "duffle_syndie", + slot_r_hand_str = "duffle_syndie" + ) /obj/item/weapon/storage/backpack/duffel/wizard name = "wizardly duffel bag" diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index 9865e60e2cc..649cd666a0f 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -71,7 +71,7 @@ item_state = "candlebox5" throwforce = 2 slot_flags = SLOT_BELT - + max_storage_space = 5 /obj/item/weapon/storage/fancy/candle_box/New() ..() diff --git a/code/game/objects/items/weapons/storage/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm index e5409eef9c2..f215deb0cf6 100644 --- a/code/game/objects/items/weapons/storage/lockbox.dm +++ b/code/game/objects/items/weapons/storage/lockbox.dm @@ -114,21 +114,15 @@ /obj/item/weapon/storage/lockbox/medal/New() ..() - new /obj/item/clothing/accessory/medal - new /obj/item/clothing/accessory/medal - new /obj/item/clothing/accessory/medal/conduct - new /obj/item/clothing/accessory/medal/conduct - new /obj/item/clothing/accessory/medal/conduct - new /obj/item/clothing/accessory/medal/conduct - new /obj/item/clothing/accessory/medal/bronze_heart - new /obj/item/clothing/accessory/medal/bronze_heart - new /obj/item/clothing/accessory/medal/nobel_science - new /obj/item/clothing/accessory/medal/nobel_science - new /obj/item/clothing/accessory/medal/silver - new /obj/item/clothing/accessory/medal/iron/merit - new /obj/item/clothing/accessory/medal/silver/valor - new /obj/item/clothing/accessory/medal/silver/security - new /obj/item/clothing/accessory/medal/silver/security - new /obj/item/clothing/accessory/medal/gold - - + new /obj/item/clothing/accessory/medal/conduct(src) + new /obj/item/clothing/accessory/medal/conduct(src) + new /obj/item/clothing/accessory/medal/conduct(src) + new /obj/item/clothing/accessory/medal/bronze_heart(src) + new /obj/item/clothing/accessory/medal/bronze_heart(src) + new /obj/item/clothing/accessory/medal/nobel_science(src) + new /obj/item/clothing/accessory/medal/nobel_science(src) + new /obj/item/clothing/accessory/medal/iron/merit(src) + new /obj/item/clothing/accessory/medal/iron/merit(src) + new /obj/item/clothing/accessory/medal/silver/valor(src) + new /obj/item/clothing/accessory/medal/silver/security(src) + new /obj/item/clothing/accessory/medal/silver/security(src) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index e1c2f9796d4..c09aef55f4f 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -413,7 +413,16 @@ update_icon() return 1 + //This proc is called when you want to place an item into the storage item. +//Its a safe proc for adding things to the storage that does the necessary checks. Object will not be moved if it fails +/obj/item/weapon/storage/proc/insert_into_storage(obj/item/W as obj, var/prevent_messages = 1) + if(!can_be_inserted(W, prevent_messages)) + return + + return handle_item_insertion(W, prevent_messages) + + /obj/item/weapon/storage/attackby(obj/item/W as obj, mob/user as mob) ..() diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index 724b6c31ac1..faf8a11c76c 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -4,11 +4,13 @@ storage_slots = 10 icon_state = "wallet" w_class = 2 + max_w_class = 2 can_hold = list( /obj/item/weapon/spacecash, /obj/item/weapon/card, - /obj/item/clothing/mask/smokable/cigarette/, + /obj/item/clothing/mask/smokable, /obj/item/clothing/accessory/badge, + /obj/item/clothing/accessory/locket, /obj/item/device/flashlight/pen, /obj/item/seeds, /obj/item/stack/medical, @@ -19,11 +21,16 @@ /obj/item/weapon/flame/lighter, /obj/item/weapon/flame/match, /obj/item/weapon/paper, + /obj/item/weapon/paper_bundle, /obj/item/weapon/pen, /obj/item/weapon/photo, /obj/item/weapon/reagent_containers/dropper, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/reagent_containers/pill, + /obj/item/weapon/reagent_containers/hypospray/autoinjector, /obj/item/weapon/screwdriver, - /obj/item/weapon/stamp) + /obj/item/weapon/stamp, + /obj/item/device/paicard) slot_flags = SLOT_ID var/obj/item/weapon/card/id/front_id = null diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 51c60982e46..64a44c1af54 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -208,7 +208,7 @@ item_state = "stunrod" force = 20 baton_color = "#75ACFF" - origin_tech = "combat=4,illegal=2" + origin_tech = list(TECH_COMBAT = 4, TECH_ILLEGAL = 2) contained_sprite = 1 /obj/item/weapon/melee/baton/stunrod/New() diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 77de8acdb59..8c5ddf22f50 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -166,8 +166,8 @@ desc = "A welding tool with an extended-capacity built-in fuel tank, standard issue for engineers." max_fuel = 40 matter = list(DEFAULT_WALL_MATERIAL = 100, "glass" = 60) - origin_tech = "engineering=2" base_iconstate = "ind_welder_off" + origin_tech = list(TECH_ENGINEERING = 2) /obj/item/weapon/weldingtool/hugetank @@ -176,8 +176,8 @@ max_fuel = 80 w_class = 2.0 matter = list(DEFAULT_WALL_MATERIAL = 200, "glass" = 120) - origin_tech = "engineering=3" base_iconstate = "adv_welder_off" + origin_tech = list(TECH_ENGINEERING = 3) //The Experimental Welding Tool! @@ -187,8 +187,8 @@ max_fuel = 40 w_class = 2.0 matter = list(DEFAULT_WALL_MATERIAL = 100, "glass" = 120) - origin_tech = "engineering=4;biotech=4" base_iconstate = "exp_welder_off" + origin_tech = list(TECH_ENGINEERING = 4, TECH_BIO = 4) base_itemstate = "exp_welder" var/last_gen = 0 diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm index 31bcd4a6e72..b2e58cdad5b 100644 --- a/code/game/objects/items/weapons/traps.dm +++ b/code/game/objects/items/weapons/traps.dm @@ -8,7 +8,7 @@ desc = "A mechanically activated leg trap. Low-tech, but reliable. Looks like it could really hurt if you set it off." throwforce = 0 w_class = 3 - origin_tech = "materials=1" + origin_tech = list(TECH_MATERIAL = 1) matter = list(DEFAULT_WALL_MATERIAL = 18750) var/deployed = 0 diff --git a/code/game/objects/items/weapons/vaurca_items.dm b/code/game/objects/items/weapons/vaurca_items.dm index 7a13b765692..0bcdb2eedaf 100644 --- a/code/game/objects/items/weapons/vaurca_items.dm +++ b/code/game/objects/items/weapons/vaurca_items.dm @@ -157,7 +157,7 @@ desc = "A lightweight Zo'rane designed Vaurcae softsuit, for extremely extended EVA operations." slowdown = 0 - species_restricted = list("Vaurca Worker", "Vaurca Warrior") + species_restricted = list("Vaurca") boots = /obj/item/clothing/shoes/magboots/vox/vaurca helmet = /obj/item/clothing/head/helmet/space/void/vaurca @@ -170,7 +170,7 @@ icon_state = "helm_void" item_state = "helm_void" - species_restricted = list("Vaurca Worker", "Vaurca Warrior") + species_restricted = list("Vaurca") light_overlay = "helmet_light" @@ -183,7 +183,7 @@ contained_sprite = 1 icon = 'icons/obj/vaurca_items.dmi' - species_restricted = list("Vaurca Worker", "Vaurca Warrior") + species_restricted = list("Vaurca") action_button_name = "Toggle the magclaws" diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index bd9a9876bae..46cda524cb7 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -96,7 +96,7 @@ if(iswirecutter(W)) if(!shock(user, 100)) playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) - getFromPool(/obj/item/stack/rods, list(get_turf(src), destroyed ? 1 : 2)) + getFromPool(/obj/item/stack/rods, get_turf(src), destroyed ? 1 : 2) qdel(src) else if((isscrewdriver(W)) && (istype(loc, /turf/simulated) || anchored)) if(!shock(user, 90)) diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index b35e3ac59e6..f8052a2b022 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -22,8 +22,21 @@ var/has_items = 0//This is set true whenever the cart has anything loaded/mounted on it var/dismantled = 0//This is set true after the object has been dismantled to avoid an infintie loop -///obj/structure/janitorialcart/New() +/obj/structure/janitorialcart/New() + ..() + janitorial_supplies |= src +/obj/structure/janitorialcart/Destroy() + janitorial_supplies -= src + QDEL_NULL(mybag) + QDEL_NULL(mymop) + QDEL_NULL(myspray) + QDEL_NULL(myreplacer) + QDEL_NULL(mybucket) + return ..() + +/obj/structure/janitorialcart/proc/get_short_status() + return "Contents: [english_list(contents)]" /obj/structure/janitorialcart/examine(mob/user) if(..(user, 1)) diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm index 6e3807c30cf..00bb35a041a 100644 --- a/code/game/objects/structures/mop_bucket.dm +++ b/code/game/objects/structures/mop_bucket.dm @@ -10,12 +10,17 @@ /obj/structure/mopbucket/New() - create_reagents(100) ..() + create_reagents(100) + janitorial_supplies |= src + +/obj/structure/mobbucket/Destroy() + janitorial_supplies -= src + return ..() /obj/structure/mopbucket/examine(mob/user) if(..(user, 1)) - user << "[src] \icon[src] contains [reagents.total_volume] unit\s of water!" + user << "Contains [reagents.total_volume] unit\s of water." /obj/structure/mopbucket/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/weapon/mop)) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 1742cd09b0f..c7bc593fcad 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -18,6 +18,7 @@ /obj/structure/toilet/attack_hand(mob/living/user as mob) if(swirlie) + usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) usr.visible_message("[user] slams the toilet seat onto [swirlie.name]'s head!", "You slam the toilet seat onto [swirlie.name]'s head!", "You hear reverberating porcelain.") swirlie.adjustBruteLoss(8) return @@ -53,6 +54,7 @@ return if(istype(I, /obj/item/weapon/grab)) + usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/obj/item/weapon/grab/G = I if(isliving(G.affecting)) @@ -117,7 +119,7 @@ /obj/machinery/shower name = "shower" - desc = "The HS-451. Installed in the 2550s by the Hygiene Division." + desc = "The HS-451. Installed in the 2450s by the Hygiene Division." icon = 'icons/obj/watercloset.dmi' icon_state = "shower" density = 0 @@ -453,9 +455,7 @@ R.cell.charge -= 20 else B.deductcharge(B.hitcost) - user.visible_message( \ - "[user] was stunned by \his wet [O]!", \ - "[user] was stunned by \his wet [O]!") + user.visible_message("[user] was stunned by \the [O]!") return 1 // Short of a rewrite, this is necessary to stop monkeycubes being washed. else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/monkeycube)) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index dbf92c1b11c..0b278903a74 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -17,6 +17,7 @@ obj/structure/windoor_assembly density = 0 dir = NORTH w_class = 3 + flags = ON_BORDER var/obj/item/weapon/airlock_electronics/electronics = null @@ -79,7 +80,7 @@ obj/structure/windoor_assembly/Destroy() user << "You dissasembled the windoor assembly!" new /obj/item/stack/material/glass/reinforced(get_turf(src), 5) if(secure) - getFromPool(/obj/item/stack/rods, list(get_turf(src), 4)) + getFromPool(/obj/item/stack/rods, get_turf(src), 4) qdel(src) else user << "You need more welding fuel to dissassemble the windoor assembly." @@ -261,18 +262,60 @@ obj/structure/windoor_assembly/Destroy() //Rotates the windoor assembly clockwise -/obj/structure/windoor_assembly/verb/revrotate() - set name = "Rotate Windoor Assembly" +//These directions are fucked up, apparently dm rotates anticlockwise by default +/obj/structure/windoor_assembly/verb/rotate() + set name = "Rotate Windoor Clockwise" set category = "Object" set src in oview(1) + var/targetdir = turn(src.dir, 270) + + for(var/obj/obstacle in get_turf(src)) + if (obstacle == src) + continue + + if((obstacle.flags & ON_BORDER) && obstacle.dir == targetdir) + usr << span("danger", "You can't turn the windoor assembly that way, there's already something there!") + return + if (src.anchored) usr << "It is fastened to the floor; therefore, you can't rotate it!" return 0 if(src.state != "01") update_nearby_tiles(need_rebuild=1) //Compel updates before - src.set_dir(turn(src.dir, 270)) + src.set_dir(targetdir) + + if(src.state != "01") + update_nearby_tiles(need_rebuild=1) + + update_icon() + return + + +//Rotates the windoor assembly anticlockwise +/obj/structure/windoor_assembly/verb/revrotate() + set name = "Rotate Windoor Anticlockwise" + set category = "Object" + set src in oview(1) + + var/targetdir = turn(src.dir, 90) + + for(var/obj/obstacle in get_turf(src)) + if (obstacle == src) + continue + + if((obstacle.flags & ON_BORDER) && obstacle.dir == targetdir) + usr << span("danger", "You can't turn the windoor assembly that way, there's already something there!") + return + + if (src.anchored) + usr << "It is fastened to the floor; therefore, you can't rotate it!" + return 0 + if(src.state != "01") + update_nearby_tiles(need_rebuild=1) //Compel updates before + + src.set_dir(targetdir) if(src.state != "01") update_nearby_tiles(need_rebuild=1) diff --git a/code/game/objects/structures/window_spawner.dm b/code/game/objects/structures/window_spawner.dm index a1cec9eb55c..966d6e8e0e1 100644 --- a/code/game/objects/structures/window_spawner.dm +++ b/code/game/objects/structures/window_spawner.dm @@ -35,7 +35,7 @@ /obj/effect/wingrille_spawn/proc/activate() if(activated) return if (!locate(/obj/structure/grille) in get_turf(src)) - var/obj/structure/grille/G = getFromPool(/obj/structure/grille, src.loc) + var/obj/structure/grille/G = new /obj/structure/grille(src.loc) handle_grille_spawn(G) var/list/neighbours = list() for (var/dir in cardinal) @@ -49,7 +49,7 @@ found_connection = 1 qdel(W) if(!found_connection) - var/obj/structure/window/new_win = getFromPool(win_path, src.loc) + var/obj/structure/window/new_win = new win_path(src.loc) new_win.set_dir(dir) handle_window_spawn(new_win) else diff --git a/code/game/turfs/initialization/maintenance.dm b/code/game/turfs/initialization/maintenance.dm index 833c0cd68dc..558f6385882 100644 --- a/code/game/turfs/initialization/maintenance.dm +++ b/code/game/turfs/initialization/maintenance.dm @@ -15,9 +15,10 @@ T.update_dirt() if(prob(2)) - getFromPool(junk(), T) + var/type = junk() + new type(T) if(prob(2)) - getFromPool(/obj/effect/decal/cleanable/blood/oil, T) + new /obj/effect/decal/cleanable/blood/oil(T) if(prob(25)) // Keep in mind that only "corners" get any sort of web attempt_web(T, cardinal_turfs) @@ -54,7 +55,7 @@ var/global/list/random_junk var/turf/neighbour = get_step(T, dir) if(neighbour && neighbour.density) if(dir == WEST) - getFromPool(/obj/effect/decal/cleanable/cobweb, T) + new /obj/effect/decal/cleanable/cobweb(T) if(dir == EAST) - getFromPool(/obj/effect/decal/cleanable/cobweb2, T) + new /obj/effect/decal/cleanable/cobweb2(T) return diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 11022e2f469..977d25059b5 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -14,8 +14,6 @@ var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to var/dirt = 0 - var/datum/scheduled_task/unwet_task - // This is not great. /turf/simulated/proc/wet_floor(var/wet_val = 1) if(wet_val < wet) @@ -26,22 +24,17 @@ wet_overlay = image('icons/effects/water.dmi',src,"wet_floor") overlays += wet_overlay - if(unwet_task) - unwet_task.trigger_task_in(180 SECONDS) - else - unwet_task = schedule_task_in(180 SECONDS) - task_triggered_event.register(unwet_task, src, /turf/simulated/proc/task_unwet_floor) - -/turf/simulated/proc/task_unwet_floor(var/triggered_task) - if(triggered_task == unwet_task) - unwet_task = null - unwet_floor() + schedule_task_with_source_in(180 SECONDS, src, .proc/unwet_floor) /turf/simulated/proc/unwet_floor() - wet = 0 - if(wet_overlay) - overlays -= wet_overlay - wet_overlay = null + --wet + if (wet < 1) + wet = 0 + if(wet_overlay) + overlays -= wet_overlay + wet_overlay = null + else + schedule_task_with_source_in(180 SECONDS, src, .proc/unwet_floor) /turf/simulated/clean_blood() for(var/obj/effect/decal/cleanable/blood/B in contents) @@ -54,11 +47,6 @@ holy = 1 levelupdate() -/turf/simulated/Destroy() - qdel(unwet_task) - unwet_task = null - return ..() - /turf/simulated/proc/initialize() return diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index 1db04cfef6c..104fc1802e9 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -24,15 +24,19 @@ can_open = WALL_CAN_OPEN update_icon() -/turf/simulated/wall/proc/fail_smash(var/mob/user) +/turf/simulated/wall/proc/fail_smash(var/mob/user, var/multiplier = 1) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN*2.5) user << "You smash against the wall!" - take_damage(rand(25,75)) + user.do_attack_animation(src) + take_damage(rand(60,135)*multiplier) + return 1 /turf/simulated/wall/proc/success_smash(var/mob/user) user << "You smash through the wall!" user.do_attack_animation(src) spawn(1) dismantle_wall(1) + return 1 /turf/simulated/wall/proc/try_touch(var/mob/user, var/rotting) @@ -64,7 +68,7 @@ if (rotting || !prob(material.hardness)) success_smash(user) else - fail_smash(user) + fail_smash(user, 2) return 1 try_touch(user, rotting) @@ -72,21 +76,21 @@ /turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker) radiate() - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/rotting = (locate(/obj/effect/overlay/wallrot) in src) if(!damage || !wallbreaker) try_touch(user, rotting) return + if(rotting) return success_smash(user) if(reinf_material) - if((wallbreaker == 2) || (damage >= max(material.hardness,reinf_material.hardness))) + if((wallbreaker == 2) && (damage >= max(material.hardness,reinf_material.hardness))) return success_smash(user) else if(damage >= material.hardness) return success_smash(user) - return fail_smash(user) + return fail_smash(user, wallbreaker) /turf/simulated/wall/attackby(obj/item/weapon/W as obj, mob/user as mob) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 67d55d583dc..2775ca50cbd 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -143,7 +143,7 @@ var/const/enterloopsanity = 100 M.make_floating(0) ..() var/objects = 0 - if(A && (A.flags & PROXMOVE)) + if(A && (A.flags & PROXMOVE) && A.simulated) for(var/atom/movable/thing in range(1)) if(objects > enterloopsanity) break objects++ diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index 8797e040811..331d10b3e5e 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -69,6 +69,7 @@ W.post_change() . = W + recalc_atom_opacity() lighting_overlay = old_lighting_overlay affecting_lights = old_affecting_lights corners = old_corners diff --git a/code/global.dm b/code/global.dm index d4adf226408..700bdc2717b 100644 --- a/code/global.dm +++ b/code/global.dm @@ -15,6 +15,7 @@ var/global/list/active_diseases = list() var/global/list/med_hud_users = list() // List of all entities using a medical HUD. var/global/list/sec_hud_users = list() // List of all entities using a security HUD. var/global/list/hud_icon_reference = list() +var/global/list/janitorial_supplies = list() // List of all the janitorial supplies on the map that the PDA cart may be tracking. var/global/list/global_mutations = list() // List of hidden mutation things. diff --git a/code/modules/admin/verbs/bluespacetech.dm b/code/modules/admin/verbs/bluespacetech.dm index 2e35869ee97..f25a668b327 100644 --- a/code/modules/admin/verbs/bluespacetech.dm +++ b/code/modules/admin/verbs/bluespacetech.dm @@ -349,7 +349,7 @@ //Headset /obj/item/device/radio/headset/ert/bst - name = "\improper Bluespace Technician's headset" + name = "bluespace technician's headset" desc = "A Bluespace Technician's headset. The letters 'BST' are stamped on the side." translate_binary = 1 translate_hive = 1 @@ -375,7 +375,7 @@ //Clothes /obj/item/clothing/under/rank/centcom_officer/bst - name = "\improper Bluespace Technician's Uniform" + name = "bluespace technician's uniform" desc = "A Bluespace Technician's Uniform. There is a logo on the sleeve that reads 'BST'." has_sensor = 0 sensor_mode = 0 @@ -395,7 +395,7 @@ //Gloves /obj/item/clothing/gloves/swat/bst - name = "\improper Bluespace Technician's gloves" + name = "bluespace technician's gloves" desc = "A pair of modified gloves. The letters 'BST' are stamped on the side." siemens_coefficient = 0 permeability_coefficient = 0 @@ -412,7 +412,7 @@ //Sunglasses /obj/item/clothing/glasses/sunglasses/bst - name = "\improper Bluespace Technician's Glasses" + name = "bluespace technician's glasses" desc = "A pair of modified sunglasses. The word 'BST' is stamped on the side." // var/list/obj/item/clothing/glasses/hud/health/hud = null vision_flags = (SEE_TURFS|SEE_OBJS|SEE_MOBS) @@ -435,7 +435,7 @@ //Shoes /obj/item/clothing/shoes/black/bst - name = "\improper Bluespace Technician's shoes" + name = "bluespace technician's shoes" desc = "A pair of black shoes with extra grip. The letters 'BST' are stamped on the side." icon_state = "black" flags = NOSLIP diff --git a/code/modules/antag_contest/contest_helpers.dm b/code/modules/antag_contest/contest_helpers.dm index 53235d77b50..3bef7a99c5d 100644 --- a/code/modules/antag_contest/contest_helpers.dm +++ b/code/modules/antag_contest/contest_helpers.dm @@ -42,3 +42,14 @@ antag_contest_side = ANTI_SYNTH else antag_contest_side = 0 + + +/mob/living/carbon/human/proc/implant_loyalty_sol(mob/living/carbon/human/M, override = FALSE) // Won't override by default. + + var/obj/item/weapon/implant/loyalty/sol/L = new/obj/item/weapon/implant/loyalty/sol(M) + L.imp_in = M + L.implanted = 1 + var/obj/item/organ/external/affected = M.organs_by_name["head"] + affected.implants += L + L.part = affected + L.implanted(src) \ No newline at end of file diff --git a/code/modules/antag_contest/sol_items.dm b/code/modules/antag_contest/sol_items.dm new file mode 100644 index 00000000000..e5b164d3fb7 --- /dev/null +++ b/code/modules/antag_contest/sol_items.dm @@ -0,0 +1,299 @@ +/* + * Sol Alliance military related items + */ + + +/obj/item/weapon/implant/loyalty/sol + name = "loyalty implant" + desc = "Makes you loyal to the Sol Alliance, or to a certain individual." + +/obj/item/weapon/implant/loyalty/sol/implanted(mob/M) + if(!istype(M, /mob/living/carbon/human)) return 0 + var/mob/living/carbon/human/H = M + var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) + if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE)) + H.visible_message("[H] seems to resist the implant!", "You feel the tendrils of the Sol Alliance try to invade your mind!") + return 0 + else + clear_antag_roles(H.mind, 1) + H << "You feel a surge of loyalty towards Admiral Michael Frost." + return 1 + + +//sol uniforms + +/obj/item/clothing/under/rank/fatigues //regular sol navy combat fatigues + name = "sol navy fatigues" + desc = "Military looking uniform issued to Sol Alliance navy, to be used while in the field." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "sol_uniform" + item_state = "sol_uniform" + contained_sprite = 1 + armor = list(melee = 10, bullet = 10, laser = 10,energy = 0, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/under/rank/fatigues/marine //regular sol navy marine fatigues + name = "sol marine fatigues" + desc = "Military looking uniform issued to Sol Alliance marines, to be used while in the field." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "marine_fatigue" + item_state = "marine_fatigue" + contained_sprite = 1 + +/obj/item/clothing/under/rank/service //navy personnel service unniform + name = "sol navy service uniform" + desc = "Military looking service uniform issued to Sol Alliance navy members." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "whiteservice" + item_state = "whiteservice" + contained_sprite = 1 + +/obj/item/clothing/under/rank/service/marine //sol marine service unniform + name = "sol marine service uniform" + desc = "Military looking service uniform issued to Sol Alliance marines." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "tanutility" + item_state = "tanutility" + contained_sprite = 1 + +/obj/item/clothing/under/rank/dress //navy personnel dress unniform + name = "sol navy dress uniform" + desc = "A fancy military looking dress uniform issued to Sol Alliance navy members." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "sailor" + item_state = "sailor" + contained_sprite = 1 + +/obj/item/clothing/under/rank/dress/marine //sol marine dress unniform + name = "sol marine dress uniform" + desc = "A fancy military looking dress uniform issued to Sol Alliance marine." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "mahreendress" + item_state = "mahreendress" + contained_sprite = 1 + +/obj/item/clothing/under/rank/dress/officer //sol marine officer dress unniform + name = "sol navy commander dress uniform" + desc = "A fancy military looking dress uniform issued to high ranking Sol Alliance navy officers. This one wears the rank of Commander" + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "dress" + item_state = "dress" + contained_sprite = 1 + +/obj/item/clothing/under/rank/dress/subofficer //sol marine officer dress unniform + name = "sol navy lieutenant dress uniform" + desc = "A fancy military looking dress uniform issued to lower ranking Sol Alliance navy officers. This one wears the rank of Lieutenant" + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "subdress" + item_state = "subdress" + contained_sprite = 1 + +/obj/item/clothing/under/rank/dress/admiral //admiral uniform + name = "sol navy admiral uniform" + desc = "A fancy military dress uniform issued to a higher member of the Sol Alliance navy." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "admiral_uniform" + item_state = "admiral_uniform" + contained_sprite = 1 + +//hats + +/obj/item/clothing/head/navy + name = "sol navy utility cover" + desc = "An eight pointed cover issued to Sol Alliance navy members as part of their field uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "greyutility" + item_state = "greyutility" + contained_sprite = 1 + armor = list(melee = 10, bullet = 10, laser = 10,energy = 0, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/head/navy/marine + name = "sol marine utility cover" + desc = "An eight pointed cover issued to Sol Alliance marines as part of their field uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "greenutility" + item_state = "greenutility" + contained_sprite = 1 + +/obj/item/clothing/head/navy/garrison + name = "sol marine garrison cap" + desc = "A green garrison cap issued to Sol Alliance marines." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "greengarrisoncap" + item_state = "greengarrisoncap" + contained_sprite = 1 + +/obj/item/clothing/head/dress + name = "sol navy dress cap" + desc = "A white cap issued as part of the Sol Alliance navy dress uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "whitepeakcap" + item_state = "whitepeakcap" + contained_sprite = 1 + +/obj/item/clothing/head/dress/marine + name = "sol marine dress cap" + desc = "A green cap issued as part of the Sol Alliance marine dress uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "whitepeakcap" + item_state = "whitepeakcap" + contained_sprite = 1 + +/obj/item/clothing/head/dress/officer + name = "sol navy officer dress cap" + desc = "A white cap issued as part of the Sol Alliance navy officers dress uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "whitewheelcap" + item_state = "whitewheelcap" + contained_sprite = 1 + +/obj/item/clothing/head/dress/admiral + name = "sol navy admiral dress cap" + desc = "A fancy looking cap issued to a higher member of the Sol Alliance navy." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "admiral_cap" + item_state = "admiral_cap" + contained_sprite = 1 + +//ceremonial swords + +/obj/item/weapon/melee/ceremonial_sword + name = "sol officer ceremonial sword" + desc = "A ceremonial sword issued to Sol navy officers as part of their dress uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "officersword" + item_state = "officersword" + contained_sprite = 1 + flags = CONDUCT + slot_flags = SLOT_BELT + force = 15 + throwforce = 5 + w_class = 4 + sharp = 1 + edge = 1 + can_embed = 0 + origin_tech = list(TECH_COMBAT = 4) + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + +/obj/item/weapon/melee/ceremonial_sword/marine + name = "sol marine ceremonial sword" + desc = "A ceremonial sword issued to Sol marine officers as part of their dress uniform." + icon = 'icons/obj/sol_uniform.dmi' + icon_state = "marineofficersword" + item_state = "marineofficersword" + contained_sprite = 1 + +//closet uniform + +/obj/structure/closet/sol + name = "sol navy uniform closet" + desc = "It's a storage unit for Sol Alliance navy uniforms." + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + +/obj/structure/closet/sol/navy/New() + ..() + new /obj/item/clothing/under/rank/fatigues(src) + new /obj/item/clothing/under/rank/fatigues(src) + new /obj/item/clothing/under/rank/fatigues(src) + new /obj/item/clothing/under/rank/service(src) + new /obj/item/clothing/under/rank/service(src) + new /obj/item/clothing/under/rank/service(src) + new /obj/item/clothing/head/navy(src) + new /obj/item/clothing/head/navy(src) + new /obj/item/clothing/head/navy(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/shoes/jackboots(src) + +/obj/structure/closet/sol/marine + name = "sol marines uniform closet" + desc = "It's a storage unit for Sol Alliance marine uniforms." + +/obj/structure/closet/sol/marine/New() + ..() + new /obj/item/clothing/under/rank/fatigues/marine(src) + new /obj/item/clothing/under/rank/fatigues/marine(src) + new /obj/item/clothing/under/rank/fatigues/marine(src) + new /obj/item/clothing/under/rank/service/marine(src) + new /obj/item/clothing/under/rank/service/marine(src) + new /obj/item/clothing/under/rank/service/marine(src) + new /obj/item/clothing/head/navy/marine(src) + new /obj/item/clothing/head/navy/marine(src) + new /obj/item/clothing/head/navy/garrison(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/shoes/jackboots(src) + +/obj/structure/closet/sol/navy_dress + name = "sol navy dress uniform closet" + desc = "It's a storage unit for Sol Alliance navy dress uniforms." + +/obj/structure/closet/sol/navy_dress/New() + ..() + new /obj/item/clothing/under/rank/dress(src) + new /obj/item/clothing/under/rank/dress(src) + new /obj/item/clothing/under/rank/dress(src) + new /obj/item/clothing/head/dress(src) + new /obj/item/clothing/head/dress(src) + new /obj/item/clothing/head/dress(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/gloves/white(src) + new /obj/item/clothing/gloves/white(src) + new /obj/item/clothing/gloves/white(src) + +/obj/structure/closet/sol/marine_dress + name = "sol marine dress uniform closet" + desc = "It's a storage unit for Sol Alliance marine dress uniforms." + +/obj/structure/closet/sol/marine_dress/New() + ..() + new /obj/item/clothing/under/rank/dress/marine(src) + new /obj/item/clothing/under/rank/dress/marine(src) + new /obj/item/clothing/under/rank/dress/marine(src) + new /obj/item/clothing/head/dress/marine(src) + new /obj/item/clothing/head/dress/marine(src) + new /obj/item/clothing/head/dress/marine(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/gloves/white(src) + new /obj/item/clothing/gloves/white(src) + new /obj/item/clothing/gloves/white(src) + +/obj/structure/closet/secure_closet/soll_officer + name = "sol alliance officer locker" + req_access = list(access_captain) + icon_state = "capsecure1" + icon_closed = "capsecure" + icon_locked = "capsecure1" + icon_opened = "capsecureopen" + icon_broken = "capsecurebroken" + icon_off = "capsecureoff" + +/obj/structure/closet/secure_closet/soll_officer/New() + ..() + if(prob(50)) + new /obj/item/weapon/storage/backpack/captain(src) + else + new /obj/item/weapon/storage/backpack/satchel_cap(src) + new /obj/item/clothing/under/rank/dress/officer(src) + new /obj/item/clothing/head/dress/officer(src) + new /obj/item/clothing/suit/storage/vest(src) + new /obj/item/weapon/cartridge/captain(src) + new /obj/item/clothing/head/helmet(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/device/radio/headset/heads/captain(src) + new /obj/item/clothing/gloves/white(src) + new /obj/item/weapon/gun/energy/pistol(src) + new /obj/item/device/flash(src) + new /obj/item/weapon/melee/telebaton(src) + new /obj/item/weapon/melee/ceremonial_sword(src) + new /obj/item/clothing/under/rank/fatigues(src) + new /obj/item/clothing/under/rank/service(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/accessory/holster/armpit(src) + return diff --git a/code/modules/cargo/randomstock.dm b/code/modules/cargo/randomstock.dm index cfa4149685d..1efaea7d4f3 100644 --- a/code/modules/cargo/randomstock.dm +++ b/code/modules/cargo/randomstock.dm @@ -134,6 +134,7 @@ var/list/global/random_stock_common = list( "paicard" = 2, "phoronsheets" = 2, "hide" = 1, + "paint" = 0.5, "nothing" = 0) var/list/global/random_stock_uncommon = list( @@ -177,7 +178,6 @@ var/list/global/random_stock_uncommon = list( "crimekit" = 1, "carpet" = 2, "gift" = 4, - "linenbin" = 1, "coatrack" = 1, "riotshield" = 2, "fireaxe" = 1, @@ -203,6 +203,7 @@ var/list/global/random_stock_uncommon = list( "lizardhide" = 0.5, "wintercoat" = 0.5, "cookingoil" = 1, + "coin" = 1.3, "nothing" = 0) var/list/global/random_stock_rare = list( @@ -214,7 +215,6 @@ var/list/global/random_stock_rare = list( "combatmeds" = 3, "batterer" = 0.75, "posibrain" = 3, - "thermals" = 0.75, "bsbeaker" = 3, "energyshield" = 2, "hardsuit" = 0.75, @@ -227,6 +227,7 @@ var/list/global/random_stock_rare = list( "voice" = 1.5, "xenohide" = 0.5, "humanhide" = 0.5, + "modkit" = 1, "nothing" = 0) var/list/global/random_stock_large = list( @@ -236,7 +237,7 @@ var/list/global/random_stock_large = list( "tacticool" = 0.2, "radsuit" = 3, "exosuit" = 1.2,//A randomly generated exosuit in a very variable condition. - "EOD" = 1.5, + "EOD" = 1.5, "biosuit" = 3, "hydrotray" = 3, "oxycanister" = 6,//Cargo should almost always have an oxycanister @@ -261,6 +262,7 @@ var/list/global/random_stock_large = list( "jukebox" = 1.2, "pipemachine" = 1.7, "bike" = 0.3, + "sol" = 0.2, "nothing" = 0) @@ -987,13 +989,18 @@ var/list/global/random_stock_large = list( if ("hide") new /obj/item/stack/material/animalhide(L, rand(5,50)) - - - - - - - + if ("paint") + var/list/paints = list( + /obj/item/weapon/reagent_containers/glass/paint/red, + /obj/item/weapon/reagent_containers/glass/paint/yellow, + /obj/item/weapon/reagent_containers/glass/paint/green, + /obj/item/weapon/reagent_containers/glass/paint/blue, + /obj/item/weapon/reagent_containers/glass/paint/purple, + /obj/item/weapon/reagent_containers/glass/paint/black, + /obj/item/weapon/reagent_containers/glass/paint/white + ) + var/type = pick(paints) + new type(L) @@ -1067,7 +1074,8 @@ var/list/global/random_stock_large = list( if ("flare") new /obj/item/device/flashlight/flare(L) new /obj/item/device/flashlight/flare(L) - new /obj/item/device/flashlight/flare(L) + if (prob(50)) + new /obj/random/glowstick(L) if("deathalarm") new /obj/item/weapon/storage/box/cdeathalarm_kit(L) if("trackimp") @@ -1232,8 +1240,6 @@ var/list/global/random_stock_large = list( new /obj/item/stack/tile/carpet(L, 50) if ("gift") new /obj/item/weapon/a_gift(L) - if ("linenbin") - new /obj/structure/bedsheetbin(get_turf(L)) if ("coatrack") var/turf/T = get_turf(L) if (!turf_clear(T)) @@ -1432,7 +1438,8 @@ var/list/global/random_stock_large = list( break new /obj/structure/reagent_dispensers/cookingoil(T) - + if("coin") + new /obj/random/coin(L) @@ -1502,8 +1509,6 @@ var/list/global/random_stock_large = list( new /obj/item/device/batterer(L) if("posibrain") new /obj/item/device/mmi/digital/posibrain(L) - if("thermals") - new /obj/item/clothing/glasses/thermal(L) if("bsbeaker") new /obj/item/weapon/reagent_containers/glass/beaker/bluespace(L) if (prob(50)) @@ -1521,7 +1526,8 @@ var/list/global/random_stock_large = list( /obj/item/weapon/material/sword/rapier, /obj/item/weapon/material/sword/longsword, /obj/item/weapon/material/sword/trench, - /obj/item/weapon/material/sword/sabre + /obj/item/weapon/material/sword/sabre, + /obj/item/weapon/material/sword/axe ) var/type = pick(swords) @@ -1542,8 +1548,8 @@ var/list/global/random_stock_large = list( /obj/item/weapon/rig/ert/assetprotection = 0.05, /obj/item/weapon/rig/light = 0.5, /obj/item/weapon/rig/light/hacker = 0.8, - /obj/item/weapon/rig/light/stealth = 1.5, - /obj/item/weapon/rig/merc = 0.5, + /obj/item/weapon/rig/light/stealth = 0.5, + /obj/item/weapon/rig/merc/empty = 0.5, /obj/item/weapon/rig/industrial = 3, /obj/item/weapon/rig/eva = 3, /obj/item/weapon/rig/ce = 2, @@ -1606,10 +1612,24 @@ var/list/global/random_stock_large = list( if("humanhide") new /obj/item/stack/material/animalhide/human(L, rand(2,15)) + if("modkit") + var/list/modkits = list( + /obj/item/device/kit/paint/ripley, + /obj/item/device/kit/paint/ripley/death, + /obj/item/device/kit/paint/ripley/flames_red, + /obj/item/device/kit/paint/ripley/flames_blue, + /obj/item/device/kit/paint/ripley/titan, + /obj/item/device/kit/paint/ripley/earth, + /obj/item/device/kit/paint/durand, + /obj/item/device/kit/paint/durand/seraph, + /obj/item/device/kit/paint/durand/phazon, + /obj/item/device/kit/paint/gygax, + /obj/item/device/kit/paint/gygax/darkgygax, + /obj/item/device/kit/paint/gygax/recitence + ) - - - + var/type = pick(modkits) + new type(L) @@ -1799,6 +1819,12 @@ var/list/global/random_stock_large = list( if ("bike") new /obj/vehicle/bike(L) + + if ("sol") + if (prob(50)) + new /obj/structure/closet/sol/navy(L) + else + new /obj/structure/closet/sol/marine(L) //This will be complex //Spawns a random exosuit, Probably not in good condition diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 72cad917ada..5c67ae30d10 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -194,11 +194,6 @@ return - // Antag contest shit - if (href_list["contest_action"] && config.antag_contest_enabled) - src.process_contest_topic(href_list) - return - ..() //redirect to hsrc.() /client/proc/handle_spam_prevention(var/message, var/mute_type) diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index 71037aade69..0d2d0e7262c 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -105,12 +105,12 @@ return TOPIC_NOACTION else if(href_list["namehelp"]) - alert(user, "Due to game mechanics, you are no longer able to edit the name for this character. The grace period offered is 5 days since the character's initial save.

If you have a need to change the character's name, or further questions regarding this policy, please contact an administrator.") + alert(user, "Due to game mechanics, you are no longer able to edit the name for this character. The grace period offered is 5 days since the character's initial save.\n\nIf you have a need to change the character's name, or further questions regarding this policy, please contact an administrator.") return TOPIC_NOACTION else if(href_list["random_name"]) if (!pref.can_edit_name) - alert(user, "You can no longer edit the name of your character.

If there is a legitimate need, please contact an administrator regarding the matter.") + alert(user, "You can no longer edit the name of your character.\n\nIf there is a legitimate need, please contact an administrator regarding the matter.") return TOPIC_NOACTION pref.real_name = random_name(pref.gender, pref.species) @@ -141,4 +141,4 @@ pref.metadata = sanitize(new_metadata) return TOPIC_REFRESH - return ..() \ No newline at end of file + return ..() diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm index bc2d74e32fb..b147871ffd2 100644 --- a/code/modules/client/preference_setup/general/02_language.dm +++ b/code/modules/client/preference_setup/general/02_language.dm @@ -75,6 +75,9 @@ else var/new_lang = input(user, "Select an additional language", "Character Generation", null) as null|anything in available_languages if(new_lang) - pref.alternate_languages |= new_lang + if (pref.alternate_languages.len >= S.num_alternate_languages) + alert(user, "You have already selected the maximum number of alternate languages for this species!") + else + pref.alternate_languages |= new_lang return TOPIC_REFRESH return ..() diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/client/preference_setup/global/02_settings.dm index 04a82b4336f..01e5b3a8665 100644 --- a/code/modules/client/preference_setup/global/02_settings.dm +++ b/code/modules/client/preference_setup/global/02_settings.dm @@ -63,6 +63,7 @@ . += "Ghost radio: [(pref.toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]
" . += "Space Parallax: [(pref.parallax_togs & PARALLAX_SPACE) ? "Yes" : "No"]
" . += "Space Dust: [(pref.parallax_togs & PARALLAX_DUST) ? "Yes" : "No"]
" + . += "Progress Bars: [(pref.parallax_togs & PROGRESS_BARS) ? "Yes" : "No"]
" /datum/category_item/player_setup_item/player_global/settings/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["toggle"]) diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index 9f804a87bf1..35b5fe56baa 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -14,7 +14,36 @@ return /* -* Path adjustment +Color adjustment +*/ + +var/datum/gear_tweak/color/gear_tweak_free_color_choice = new() + +/datum/gear_tweak/color + var/list/valid_colors + +/datum/gear_tweak/color/New(var/list/valid_colors) + src.valid_colors = valid_colors + ..() + +/datum/gear_tweak/color/get_contents(var/metadata) + return "Color: " + +/datum/gear_tweak/color/get_default() + return valid_colors ? valid_colors[1] : COLOR_GRAY + +/datum/gear_tweak/color/get_metadata(var/user, var/metadata) + if(valid_colors) + return input(user, "Choose an item color.", "Character Preference", metadata) as null|anything in valid_colors + return input(user, "Choose an item color.", "Global Preference", metadata) as color|null + +/datum/gear_tweak/color/tweak_item(var/obj/item/I, var/metadata) + if(valid_colors && !(metadata in valid_colors)) + return + I.color = metadata + +/* +Path adjustment */ /datum/gear_tweak/path @@ -25,7 +54,7 @@ ..() /datum/gear_tweak/path/get_contents(var/metadata) - return "(Type: [metadata])" + return "Type: [metadata]" /datum/gear_tweak/path/get_default() return valid_paths[1] @@ -39,27 +68,28 @@ gear_data.path = valid_paths[metadata] /* -* Content adjustment +Content adjustment */ /datum/gear_tweak/contents var/list/valid_contents /datum/gear_tweak/contents/New() - valid_contents = args + valid_contents = args.Copy() ..() /datum/gear_tweak/contents/get_contents(var/metadata) - return "(Contents)" + return "Contents: [english_list(metadata, and_text = ", ")]" /datum/gear_tweak/contents/get_default() . = list() for(var/i = 1 to valid_contents.len) - var/list/contents = valid_contents[i] - . += contents[1] + . += "Random" /datum/gear_tweak/contents/get_metadata(var/user, var/list/metadata) . = list() + for(var/i = metadata.len to (valid_contents.len - 1)) + metadata += "Random" for(var/i = 1 to valid_contents.len) var/entry = input(user, "Choose an entry.", "Character Preference", metadata[i]) as null|anything in (valid_contents[i] + list("Random", "None")) if(entry) @@ -71,16 +101,17 @@ if(metadata.len != valid_contents.len) return for(var/i = 1 to valid_contents.len) + var/path var/list/contents = valid_contents[i] - var/path = contents[metadata[i]] - if(path) - if(path == "Random") - path = pick(contents) - path = contents[path] - else if(path == "None") - continue - new path(I) - + if(metadata[i] == "Random") + path = pick(contents) + path = contents[path] + else if(metadata[i] == "None") + continue + else + path = contents[metadata[i]] + new path(I) + /* Reagents adjustment */ diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index bffc269c5a4..bbb94611fed 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -34,6 +34,7 @@ var/list/gear_datums = list() name = "Loadout" sort_order = 1 var/current_tab = "General" + var/gear_reset = FALSE /datum/category_item/player_setup_item/loadout/load_character(var/savefile/S) S["gear"] >> pref.gear @@ -46,12 +47,12 @@ var/list/gear_datums = list() /datum/category_item/player_setup_item/loadout/gather_load_query() return list("ss13_characters" = list("vars" = list("gear"), "args" = list("id"))) - + /datum/category_item/player_setup_item/loadout/gather_save_query() return list("ss13_characters" = list("gear", "id" = 1, "ckey" = 1)) - + /datum/category_item/player_setup_item/loadout/gather_save_parameters() - return list(":gear" = list2params(pref.gear), ":id" = pref.current_character, ":ckey" = pref.client.ckey) + return list(":gear" = json_encode(pref.gear), ":id" = pref.current_character, ":ckey" = pref.client.ckey) /datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost) . = list() @@ -66,9 +67,18 @@ var/list/gear_datums = list() . += gear_name /datum/category_item/player_setup_item/loadout/sanitize_character(var/sql_load = 0) - if (sql_load) - pref.gear = params2list(pref.gear) + gear_reset = FALSE + if (pref.gear && istext(pref.gear)) + try + pref.gear = json_decode(pref.gear) + catch + log_debug("SQL CHARACTER LOAD: Unable to load custom loadout for client [pref.client ? pref.client.ckey : "UNKNOWN"].") + pref.gear = list() + gear_reset = TRUE + else + pref.gear = list() + gear_reset = TRUE var/mob/preference_mob = preference_mob() if(!islist(pref.gear)) @@ -92,7 +102,7 @@ var/list/gear_datums = list() preference_mob << "You cannot afford to take \the [gear_name]" else total_cost += G.cost - + /datum/category_item/player_setup_item/loadout/content() var/total_cost = 0 if(pref.gear && pref.gear.len) @@ -106,6 +116,8 @@ var/list/gear_datums = list() fcolor = "#E67300" . = list() . += "" + if (gear_reset) + . += "" . += "" . += "
Your loadout failed to load and will be reset if you save this slot.
[total_cost]/[MAX_GEAR_COST] loadout points spent. \[Clear Loadout\]
" diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm index 2230162f0a4..8b4d6bb598e 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm @@ -28,7 +28,7 @@ /datum/gear/accessory/holster display_name = "holster selection" - path = /obj/item/clothing/accessory/holster + path = /obj/item/clothing/accessory/holster/armpit allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective", "Security Cadet") /datum/gear/accessory/holster/New() @@ -42,7 +42,7 @@ /datum/gear/accessory/tie display_name = "tie selection" - path = /obj/item/clothing/accessory + path = /obj/item/clothing/accessory/blue /datum/gear/accessory/tie/New() ..() @@ -55,18 +55,22 @@ /datum/gear/accessory/brown_vest display_name = "webbing, engineering" path = /obj/item/clothing/accessory/storage/brown_vest - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer") + allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer", "Engineering Apprentice") /datum/gear/accessory/black_vest display_name = "webbing, security" path = /obj/item/clothing/accessory/storage/black_vest - allowed_roles = list("Security Officer","Head of Security","Warden") + allowed_roles = list("Security Officer","Head of Security","Warden", "Security Cadet", "Detective" ) /datum/gear/accessory/webbing display_name = "webbing, simple" path = /obj/item/clothing/accessory/storage/webbing cost = 2 +/datum/gear/accessory/locket + display_name = "silver locket" + path = /obj/item/clothing/accessory/locket + /datum/gear/accessory/scarf display_name = "scarf selection" path = /obj/item/clothing/accessory/scarf diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/client/preference_setup/loadout/loadout_eyes.dm index fef99095d78..cc051c6d147 100644 --- a/code/modules/client/preference_setup/loadout/loadout_eyes.dm +++ b/code/modules/client/preference_setup/loadout/loadout_eyes.dm @@ -28,6 +28,11 @@ /datum/gear/eyes/sciencegoggles display_name = "science Goggles" path = /obj/item/clothing/glasses/science + +/datum/gear/eyes/mesonprescription + display_name = "meson goggles, prescription" + path = /obj/item/clothing/glasses/meson/prescription + allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice", "Research Director","Scientist") /datum/gear/eyes/security display_name = "security HUD" @@ -47,4 +52,3 @@ /datum/gear/eyes/shades/prescriptionsun display_name = "sunglasses, presciption" path = /obj/item/clothing/glasses/sunglasses/prescription - cost = 2 diff --git a/code/modules/client/preference_setup/loadout/loadout_gloves.dm b/code/modules/client/preference_setup/loadout/loadout_gloves.dm index 3680312c54f..d22fccc4664 100644 --- a/code/modules/client/preference_setup/loadout/loadout_gloves.dm +++ b/code/modules/client/preference_setup/loadout/loadout_gloves.dm @@ -1,7 +1,7 @@ /datum/gear/gloves display_name = "watch" path = /obj/item/clothing/gloves/watch - cost = 2 + cost = 1 slot = slot_gloves sort_category = "Gloves and Handwear" @@ -12,14 +12,15 @@ /datum/gear/gloves/color/New() ..() var/gloves = list() - gloves["black gloves"] = /obj/item/clothing/gloves + gloves["black gloves"] = /obj/item/clothing/gloves/black gloves["red gloves"] = /obj/item/clothing/gloves/red gloves["blue gloves"] = /obj/item/clothing/gloves/blue gloves["orange gloves"] = /obj/item/clothing/gloves/orange gloves["purple gloves"] = /obj/item/clothing/gloves/purple gloves["brown gloves"] = /obj/item/clothing/gloves/brown gloves["light-brown gloves"] = /obj/item/clothing/gloves/light_brown - gloves["white gloves"] = /obj/item/clothing/gloves/green + gloves["white gloves"] = /obj/item/clothing/gloves/white + gloves["green gloves"] = /obj/item/clothing/gloves/green gloves["grey gloves"] = /obj/item/clothing/gloves/grey gloves["rainbow gloves"] = /obj/item/clothing/gloves/rainbow gear_tweaks += new/datum/gear_tweak/path(gloves) diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/client/preference_setup/loadout/loadout_head.dm index 503c55a684f..3a8d9aca4ff 100644 --- a/code/modules/client/preference_setup/loadout/loadout_head.dm +++ b/code/modules/client/preference_setup/loadout/loadout_head.dm @@ -1,6 +1,6 @@ /datum/gear/head - display_name = "hat, boatsman" - path = /obj/item/clothing/head/boaterhat + display_name = "ushanka" + path = /obj/item/clothing/head/ushanka slot = slot_head sort_category = "Hats and Headwear" @@ -64,12 +64,12 @@ path = /obj/item/clothing/head/beret/sec/hos allowed_roles = list("Head of Security") -/datum/gear/head/cap/corp +/datum/gear/head/corp display_name = "cap, corporate (security)" path = /obj/item/clothing/head/soft/sec/corp allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") -/datum/gear/head/cap/sec +/datum/gear/head/sec display_name = "cap, security" path = /obj/item/clothing/head/soft/sec allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") @@ -92,26 +92,29 @@ display_name = "hair flower pin, red" path = /obj/item/clothing/head/hairflower -/datum/gear/head/bowler - display_name = "hat, bowler" - path = /obj/item/clothing/head/bowler +/datum/gear/head/hats + display_name = "hat selection" + path = /obj/item/clothing/head/boaterhat -/datum/gear/head/fez - display_name = "hat, fez" - path = /obj/item/clothing/head/fez - -/datum/gear/head/tophat - display_name = "hat, tophat" - path = /obj/item/clothing/head/that +/datum/gear/head/hats/New() + ..() + var/hats = list() + hats["hat, boatsman"] = /obj/item/clothing/head/boaterhat + hats["hat, bowler"] = /obj/item/clothing/head/bowler + hats["hat, fez"] = /obj/item/clothing/head/fez + hats["hat, tophat"] = /obj/item/clothing/head/that + hats["hat, feather trilby"] = /obj/item/clothing/head/feathertrilby + hats["hat, fedora"] = /obj/item/clothing/head/fedora + hats["hat, beaver"] = /obj/item/clothing/head/beaverhat + hats["hat, cowboy"] = /obj/item/clothing/head/cowboy + hats["hat, wide-brimmed cowboy"] = /obj/item/clothing/head/cowboy/wide + hats["hat, sombrero"] = /obj/item/clothing/head/sombrero + gear_tweaks += new/datum/gear_tweak/path(hats) /datum/gear/head/philosopher_wig display_name = "natural philosopher's wig" path = /obj/item/clothing/head/philosopher_wig -/datum/gear/head/ushanka - display_name = "ushanka" - path = /obj/item/clothing/head/ushanka - /datum/gear/head/hijab display_name = "hijab selection" path = /obj/item/clothing/head/hijab @@ -127,3 +130,17 @@ hijab["blue hijab"] = /obj/item/clothing/head/hijab/blue gear_tweaks += new/datum/gear_tweak/path(hijab) + +/datum/gear/head/surgical + display_name = "surgical cap selection" + path = /obj/item/clothing/head/surgery/blue + allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Chemist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective") + +/datum/gear/head/surgical/New() + ..() + var/surgical = list() + surgical["surgical cap, purple"] = /obj/item/clothing/head/surgery/purple + surgical["surgical cap, blue"] = /obj/item/clothing/head/surgery/blue + surgical["surgical cap, green"] = /obj/item/clothing/head/surgery/green + surgical["surgical cap, black"] = /obj/item/clothing/head/surgery/black + gear_tweaks += new/datum/gear_tweak/path(surgical) diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 2973900b7c2..5a7fae169d0 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -79,6 +79,10 @@ display_name = "track jacket" path = /obj/item/clothing/suit/storage/toggle/tracksuit +/datum/gear/suit/ian + display_name = "worn shirt" + path = /obj/item/clothing/suit/ianshirt + /datum/gear/suit/winter display_name = "winter coat" path = /obj/item/clothing/suit/storage/hooded/wintercoat @@ -101,7 +105,7 @@ /datum/gear/suit/winter/medical display_name = "winter coat, medical" path = /obj/item/clothing/suit/storage/hooded/wintercoat/medical - allowed_roles = list("Chief Medical Officer","Medical Doctor","Paramedic","Nursing Intern","Psychiatrist","Chemist",) + allowed_roles = list("Chief Medical Officer","Medical Doctor","Paramedic","Nursing Intern","Psychiatrist","Chemist") /datum/gear/suit/winter/engineering display_name = "winter coat, engineering" @@ -126,4 +130,4 @@ /datum/gear/suit/winter/mining display_name = "winter coat, mining" path = /obj/item/clothing/suit/storage/hooded/wintercoat/miner - allowed_roles = list("Quartermaster","Head of Personnel","Shaft Miner") \ No newline at end of file + allowed_roles = list("Quartermaster","Head of Personnel","Shaft Miner") diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm index 6566570d82f..cbb8b8036bd 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm @@ -5,18 +5,10 @@ slot = slot_w_uniform sort_category = "Uniforms and Casual Dress" -/datum/gear/uniform/cheongsam - display_name = "cheongsam, white" - path = /obj/item/clothing/under/cheongsam - /datum/gear/uniform/kilt display_name = "kilt" path = /obj/item/clothing/under/kilt -/datum/gear/uniform/jumpskirt - display_name = "jumpskirt, black" - path = /obj/item/clothing/under/blackjumpskirt - /datum/gear/uniform/jumpsuit display_name = "generic jumpsuits" path = /obj/item/clothing/under/color/grey @@ -43,19 +35,21 @@ jumpsuit["yellow green jumpsuit"] = /obj/item/clothing/under/yellowgreen jumpsuit["light red jumpsuit"] = /obj/item/clothing/under/lightred jumpsuit["dark red jumpsuit"] = /obj/item/clothing/under/darkred + jumpsuit["rainbow jumpsuit"] = /obj/item/clothing/under/rainbow gear_tweaks += new/datum/gear_tweak/path(jumpsuit) /datum/gear/uniform/skirt - display_name = "plaid skirt, blue" + display_name = "skirt selection" path = /obj/item/clothing/under/dress/plaid_blue -/datum/gear/uniform/skirt/purple - display_name = "plaid skirt, purple" - path = /obj/item/clothing/under/dress/plaid_purple - -/datum/gear/uniform/skirt/red - display_name = "plaid skirt, red" - path = /obj/item/clothing/under/dress/plaid_red +/datum/gear/uniform/skirt/New() + ..() + var/skirts = list() + skirts["plaid skirt, blue"] = /obj/item/clothing/under/dress/plaid_blue + skirts["plaid skirt, purple"] = /obj/item/clothing/under/dress/plaid_purple + skirts["plaid skirt, red"] = /obj/item/clothing/under/dress/plaid_red + skirts["jumpskirt, black"] = /obj/item/clothing/under/blackjumpskirt + gear_tweaks += new/datum/gear_tweak/path(skirts) /datum/gear/uniform/suit display_name = "suit selection" @@ -87,7 +81,7 @@ /datum/gear/uniform/scrubs display_name = "scrubs selection" path = /obj/item/clothing/under/rank/medical/black - allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective",) + allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Chemist","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective") /datum/gear/uniform/scrubs/New() ..() @@ -98,17 +92,22 @@ scrubs["scrubs, purple"] = /obj/item/clothing/under/rank/medical/purple gear_tweaks += new/datum/gear_tweak/path(scrubs) -/datum/gear/uniform/sundress - display_name = "sundress" +/datum/gear/uniform/dress + display_name = "dress selection" path = /obj/item/clothing/under/sundress -/datum/gear/uniform/sundress/white - display_name = "sundress, white" - path = /obj/item/clothing/under/sundress_white - -/datum/gear/uniform/dress_fire - display_name = "flame dress" - path = /obj/item/clothing/under/dress/dress_fire +/datum/gear/uniform/dress/New() + ..() + var/dress = list() + dress["sundress"] = /obj/item/clothing/under/sundress + dress["sundress, white"] = /obj/item/clothing/under/sundress_white + dress["dress, flame"] = /obj/item/clothing/under/dress/dress_fire + dress["dress, green"] = /obj/item/clothing/under/dress/dress_green + dress["dress, orange"] = /obj/item/clothing/under/dress/dress_orange + dress["dress, pink"] = /obj/item/clothing/under/dress/dress_pink + dress["dress, yellow"] = /obj/item/clothing/under/dress/dress_yellow + dress["cheongsam, white"] = /obj/item/clothing/under/cheongsam + gear_tweaks += new/datum/gear_tweak/path(dress) /datum/gear/uniform/uniform_captain display_name = "uniform, captain's dress" diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm index 135c22be02b..6bd887c8fbb 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm +++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm @@ -65,21 +65,21 @@ display_name = "vaurca blindfold (Vaurca)" path = /obj/item/clothing/glasses/sunglasses/blinders cost = 2 - whitelisted = "Vaurca" + whitelisted = "Vaurca Worker" sort_category = "Xenowear" /datum/gear/mask/vaurca display_name = "mandible garment (Vaurca)" path = /obj/item/clothing/mask/breath/vaurca cost = 1 - whitelisted = "Vaurca" + whitelisted = "Vaurca Worker" sort_category = "Xenowear" /datum/gear/cape display_name = "tunnel cloak (Vaurca)" path = /obj/item/weapon/storage/backpack/cloak cost = 1 - whitelisted = "Vaurca" + whitelisted = "Vaurca Worker" sort_category = "Xenowear" //beastmen gloves diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 5455a4370ed..349ba8bcc24 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -62,8 +62,8 @@ datum/preferences var/species = "Human" //Species datum to use. var/species_preview //Used for the species selection window. var/list/alternate_languages = list() //Secondary language(s) - var/list/language_prefixes = list() //Kanguage prefix keys - var/list/gear //Custom/fluff item loadout. + var/list/language_prefixes = list() // Language prefix keys + var/list/gear // Custom/fluff item loadout. //Some faction information. var/home_system = "Unset" //System of birth. @@ -127,7 +127,7 @@ datum/preferences // SPAAAACE var/parallax_speed = 2 - var/parallax_togs = PARALLAX_SPACE + var/parallax_togs = PARALLAX_SPACE | PROGRESS_BARS var/list/pai = list() // A list for holding pAI related data. diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 180fd7c6914..1ca3dbd2201 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -189,3 +189,15 @@ if (mob.hud_used) mob.hud_used.update_parallax() + +/client/verb/toggle_progress() + set name = "Show/Hide Progress Bars" + set category = "Preferences" + set desc = "Toggles progress bars on slow actions." + + prefs.parallax_togs ^= PROGRESS_BARS + prefs.save_preferences() + if (prefs.parallax_togs & PROGRESS_BARS) + src << "You will now see progress bars on delayed actions." + else + src << "You will no longer see progress bars on delayed actions." diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 9a8d00bbafd..6d0bc2fc5fc 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -50,7 +50,7 @@ /obj/item/clothing/under/chameleon/New() ..() if(!clothing_choices) - var/blocked = list(src.type, /obj/item/clothing/under/cloud, /obj/item/clothing/under/gimmick)//Prevent infinite loops and bad jumpsuits. + var/blocked = list(src.type, /obj/item/clothing/under/gimmick, /obj/item/clothing/under/rank/centcom_officer/bst)//Prevent infinite loops and bad jumpsuits. clothing_choices = generate_chameleon_choices(/obj/item/clothing/under, blocked) /obj/item/clothing/under/chameleon/emp_act(severity) @@ -158,7 +158,7 @@ /obj/item/clothing/shoes/chameleon/New() ..() if(!clothing_choices) - var/blocked = list(src.type, /obj/item/clothing/shoes/syndigaloshes, /obj/item/clothing/shoes/cyborg)//prevent infinite loops and bad shoes. + var/blocked = list(src.type, /obj/item/clothing/shoes/syndigaloshes, /obj/item/clothing/shoes/cyborg, /obj/item/clothing/shoes/black/bst)//prevent infinite loops and bad shoes. clothing_choices = generate_chameleon_choices(/obj/item/clothing/shoes, blocked) /obj/item/clothing/shoes/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. @@ -233,11 +233,12 @@ desc = "It looks like a pair of gloves, but it seems to have a small dial inside." origin_tech = list(TECH_ILLEGAL = 3) var/global/list/clothing_choices - + /obj/item/clothing/gloves/chameleon/New() ..() if(!clothing_choices) - clothing_choices = generate_chameleon_choices(/obj/item/clothing/gloves, list(src.type)) + var/blocked = list(src.type, /obj/item/clothing/gloves/swat/bst) + clothing_choices = generate_chameleon_choices(/obj/item/clothing/gloves, blocked) /obj/item/clothing/gloves/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. name = "black gloves" @@ -307,7 +308,8 @@ /obj/item/clothing/glasses/chameleon/New() ..() if(!clothing_choices) - clothing_choices = generate_chameleon_choices(/obj/item/clothing/glasses, list(src.type)) + var/blocked = list(src.type, /obj/item/clothing/glasses/sunglasses/bst) + clothing_choices = generate_chameleon_choices(/obj/item/clothing/glasses, blocked) /obj/item/clothing/glasses/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. name = "optical meson scanner" diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index bcc8f350eaf..91b3f1c84cd 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -275,7 +275,6 @@ BLIND // can't see anything var/light_applied var/brightness_on var/on = 0 - //offset_light = 1 sprite_sheets = list( "Vox" = 'icons/mob/species/vox/head.dmi', diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 4519a560b2c..0ebb659c50f 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -188,6 +188,7 @@ flags_inv |= HIDEEYES body_parts_covered |= EYES icon_state = initial(icon_state) + item_state = initial(item_state) flash_protection = initial(flash_protection) tint = initial(tint) usr << "You flip \the [src] down to protect your eyes." @@ -196,6 +197,7 @@ flags_inv &= ~HIDEEYES body_parts_covered &= ~EYES icon_state = "[initial(icon_state)]up" + item_state = "[initial(item_state)]up" flash_protection = FLASH_PROTECTION_NONE tint = TINT_NONE usr << "You push \the [src] up out of your face." diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index 1fc44809c2a..9b5c9850887 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -44,14 +44,6 @@ siemens_coefficient = 1.0 //thin latex gloves, much more conductive than fabric gloves (basically a capacitor for AC) permeability_coefficient = 0.01 germ_level = 0 - -/obj/item/clothing/gloves/botanic_leather - desc = "These leather work gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin." - name = "botanist's leather gloves" - icon_state = "leather" - item_state = "ggloves" - permeability_coefficient = 0.05 - siemens_coefficient = 0.50 //thick work gloves /obj/item/clothing/gloves/latex/unathi name = "unathi latex gloves" @@ -62,6 +54,22 @@ name = "tajaran latex gloves" desc = "Sterile latex gloves. Designed for Tajara use." species_restricted = list("Tajara") + +/obj/item/clothing/gloves/botanic_leather + desc = "These leather work gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin." + name = "leather gloves" + icon_state = "leather" + item_state = "ggloves" + permeability_coefficient = 0.05 + siemens_coefficient = 0.50 //thick work gloves + +/obj/item/clothing/gloves/botanic_leather/unathi + name = "unathi leather gloves" + species_restricted = list("Unathi") + +/obj/item/clothing/gloves/botanic_leather/tajara + name = "tajaran leather gloves" + species_restricted = list("Tajara") /obj/item/clothing/gloves/watch desc = "A small wristwatch, capable of telling time." diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 4bf7dfcde6a..fb5e45584a3 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -8,6 +8,7 @@ armor = list(melee = 30, bullet = 5, laser = 20,energy = 10, bomb = 20, bio = 10, rad = 20) flags_inv = 0 siemens_coefficient = 0.9 + light_wedge = LIGHT_WIDE /obj/item/clothing/head/hardhat/orange icon_state = "hardhat0_orange" diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index a7f474cfffd..d392ca245c6 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -121,8 +121,11 @@ desc = "A cap surgeons wear during operations. Keeps their hair from tickling your internal organs. This one is dark green." icon_state = "surgcap_green" -//Detective +/obj/item/clothing/head/surgery/black + desc = "A cap surgeons wear during operations. Keeps their hair from tickling your internal organs. This one is black." + icon_state = "surgcap_black" +//Detective /obj/item/clothing/head/det name = "fedora" diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 045af3d30fd..ddb9e35291a 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -289,4 +289,20 @@ name = "blue hijab" icon = 'icons/obj/clothing/hijabs.dmi' icon_state = "hijab_blue" - item_state = "hijab_blue" \ No newline at end of file + item_state = "hijab_blue" + +/obj/item/clothing/head/cowboy + name = "cowboy hat" + desc = "A wide-brimmed hat, in the prevalent style of the frontier." + icon_state = "cowboyhat" + body_parts_covered = 0 + +/obj/item/clothing/head/cowboy/wide + name = "wide-brimmed cowboy hat" + icon_state = "cowboy_wide" + +/obj/item/clothing/head/sombrero + name = "sombrero" + desc = "You can practically taste the fiesta." + icon_state = "sombrero" + body_parts_covered = 0 diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm index ab70bcdbd60..6f4556c5b0c 100644 --- a/code/modules/clothing/masks/boxing.dm +++ b/code/modules/clothing/masks/boxing.dm @@ -16,7 +16,7 @@ w_class = 2 /obj/item/clothing/mask/luchador - name = "Luchador Mask" + name = "luchador mask" desc = "Worn by robust fighters, flying high to defeat their foes!" icon_state = "luchag" item_state = "luchag" @@ -26,13 +26,13 @@ siemens_coefficient = 3.0 /obj/item/clothing/mask/luchador/tecnicos - name = "Tecnicos Mask" + name = "tecnicos mask" desc = "Worn by robust fighters who uphold justice and fight honorably." icon_state = "luchador" item_state = "luchador" /obj/item/clothing/mask/luchador/rudos - name = "Rudos Mask" + name = "rudos mask" desc = "Worn by robust fighters who are willing to do anything to win." icon_state = "luchar" item_state = "luchar" diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 56d4216ae98..d47a291c383 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -47,7 +47,7 @@ body_parts_covered = 0 /obj/item/clothing/mask/snorkel - name = "Snorkel" + name = "snorkel" desc = "For the Swimming Savant." icon_state = "snorkel" flags_inv = HIDEFACE diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index ac7915a38aa..a584c367f4c 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -220,7 +220,7 @@ if(!instant) wearer.visible_message("[wearer]'s suit emits a quiet hum as it begins to adjust its seals.","With a quiet hum, the suit begins running checks and adjusting components.") - if(seal_delay && !do_after(wearer,seal_delay)) + if(seal_delay && !do_after(wearer, seal_delay, act_target = src)) if(wearer) wearer << "You must remain still while the suit is adjusting the components." failed_to_seal = 1 @@ -244,7 +244,7 @@ if(!failed_to_seal && wearer.back == src && piece == compare_piece) - if(seal_delay && !instant && !do_after(wearer,seal_delay,needhand=0)) + if(seal_delay && !instant && !do_after(wearer,seal_delay,needhand=0, act_target = src)) failed_to_seal = 1 piece.icon_state = "[initial(icon_state)][!seal_target ? "_sealed" : ""]" diff --git a/code/modules/clothing/spacesuits/rig/suits/ert.dm b/code/modules/clothing/spacesuits/rig/suits/ert.dm index 3786a5e102d..e686453d1c3 100644 --- a/code/modules/clothing/spacesuits/rig/suits/ert.dm +++ b/code/modules/clothing/spacesuits/rig/suits/ert.dm @@ -79,6 +79,7 @@ suit_type = "heavy asset protection" icon_state = "asset_protection_rig" armor = list(melee = 60, bullet = 60, laser = 60,energy = 40, bomb = 50, bio = 100, rad = 100) + siemens_coefficient = 0 emp_protection = 50 initial_modules = list( @@ -86,8 +87,9 @@ /obj/item/rig_module/maneuvering_jets, /obj/item/rig_module/grenade_launcher, /obj/item/rig_module/vision/multi, - /obj/item/rig_module/mounted/egun, + /obj/item/rig_module/mounted/pulse, /obj/item/rig_module/chem_dispenser/combat, + /obj/item/rig_module/chem_dispenser/injector, /obj/item/rig_module/mounted/plasmacutter, /obj/item/rig_module/device/rcd, /obj/item/rig_module/datajack diff --git a/code/modules/clothing/under/accessories/armband.dm b/code/modules/clothing/under/accessories/armband.dm index 2494c1d820f..e971d1d1124 100644 --- a/code/modules/clothing/under/accessories/armband.dm +++ b/code/modules/clothing/under/accessories/armband.dm @@ -38,7 +38,6 @@ name = "synthetic intelligence movement armband" desc = "An armband, signifying membership of the Synthetic Intelligence Movement. It's white, with a brown stripe that appears to look like an active positronic brain." icon_state = "movement" - slot = "armband" /obj/item/clothing/accessory/armband/atlas name = "atlas armband" diff --git a/code/modules/clothing/under/accessories/lockets.dm b/code/modules/clothing/under/accessories/lockets.dm index 2aaa6750e5c..7643bd6e712 100644 --- a/code/modules/clothing/under/accessories/lockets.dm +++ b/code/modules/clothing/under/accessories/lockets.dm @@ -1,6 +1,6 @@ /obj/item/clothing/accessory/locket name = "silver locket" - desc = "This oval shaped, argentium sterling silver locket hangs on an incredibly fine, refractive string, almost thin as hair and microweaved from links to a deceptive strength, of similar material. The edges are engraved very delicately with an elegant curving design, but overall the main is unmarked and smooth to the touch, leaving room for either remaining as a stolid piece or future alterations. There is an obvious internal place for a picture or lock of some sort, but even behind that is a very thin compartment unhinged with the pinch of a thumb and forefinger." + desc = "A silver locket that seems to have space for a photo within." icon_state = "locket" item_state = "locket" slot_flags = 0 diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm index 4592ed8e229..b27653f9e7f 100644 --- a/code/modules/clothing/under/jobs/engineering.dm +++ b/code/modules/clothing/under/jobs/engineering.dm @@ -28,9 +28,3 @@ icon_state = "robotics" item_state = "bl_suit" worn_state = "robotics" - -/obj/item/clothing/under/rank/roboticist/skirt - desc = "It's a slimming black jumpskirt with reinforced seams; great for industrial work." - name = "roboticist's jumpskirt" - icon_state = "roboticsf" - worn_state = "roboticsf" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index e8f1ee2da7f..2276df9b822 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -166,12 +166,6 @@ item_state = "rainbow" worn_state = "rainbow" -/obj/item/clothing/under/cloud - name = "cloud" - desc = "cloud" - icon_state = "cloud" - worn_state = "cloud" - /obj/item/clothing/under/psysuit name = "dark undersuit" desc = "A thick, layered grey undersuit lined with power cables. Feels a little like wearing an electrical storm." @@ -344,7 +338,6 @@ item_state = "p_suit" worn_state = "dress_saloon" - /obj/item/clothing/under/dress/dress_cap name = "captain's dress uniform" desc = "Feminine fashion for the style concious captain." diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index cf37d1ced15..222a4d7f77e 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -96,7 +96,7 @@ All custom items with worn sprites must follow the contained sprite system: http /obj/item/clothing/gloves/swat/fluff/hawk_gloves //Sharpshooter gloves - Hawk Silverstone - nebulaflare - name = "\improper sharpshooter gloves" + name = "sharpshooter gloves" desc = "These tactical gloves are tailor made for a marksman." icon = 'icons/obj/custom_items/hawk_gloves.dmi' icon_state = "hawk_gloves" @@ -165,7 +165,7 @@ All custom items with worn sprites must follow the contained sprite system: http /obj/item/weapon/melee/fluff/tina_knife //Consecrated Athame - Tina Kaekel - tainavaa name = "consecrated athame" - desc = "An athame used in occult rituals. The double-edged dagger is dull. The handle is black with a pink/white occult design strewn about it, and 'Tina' is inscribed into it in decorated letters." + desc = "An athame used in occult rituals. The double-edged dagger is dull. The handle is black with a pink/white occult design strewn about it, and \"Tina\" is inscribed into it in decorated letters." icon = 'icons/obj/custom_items/tina_knife.dmi' icon_state = "tina_knife" item_state = "knife" @@ -178,7 +178,7 @@ All custom items with worn sprites must follow the contained sprite system: http name = "\"Hephaestus Industrial Exosuit MK III\" APLU customisation kit" desc = "A ripley APLU model manufactured by Hephaestus industries, a common sight in New Gibson nowadays. It shines with chrome painting and a fancy reinforced glass cockpit." new_name = "Hephaestus Industrial Exosuit MK III" - new_desc = "An ripley APLU model manufactured by Hephaestus industries, a common sight in New Gibson nowadays. It shines with chrome painting and a fancy reinforced glass cockpit." + new_desc = "A ripley APLU model manufactured by Hephaestus industries, a common sight in New Gibson nowadays. It shines with chrome painting and a fancy reinforced glass cockpit." new_icon = "ripley_zairjah" //a lot of thanks to cakeisossim for the sprites allowed_types = list("ripley","firefighter") @@ -258,6 +258,7 @@ All custom items with worn sprites must follow the contained sprite system: http name = "ATLAS poster" /obj/item/weapon/contraband/poster/fluff/conservan_poster/New() + ..() serial_number = 59 @@ -341,7 +342,7 @@ All custom items with worn sprites must follow the contained sprite system: http /obj/item/weapon/fluff/moon_baton //Tiger Claw - Zander Moon - omnivac name = "tiger claw" - desc = "A small cerimonial energy dagger given to Golden Tigers." + desc = "A small ceremonial energy dagger given to Golden Tigers." icon = 'icons/obj/custom_items/moon_baton.dmi' icon_state = "tigerclaw" item_state = "tigerclaw" @@ -406,14 +407,6 @@ All custom items with worn sprites must follow the contained sprite system: http desc = "A NT Asset Protection Force Beret. It has the NT APF insignia on it as well as the Name \"Goellstein\" inside." -/obj/item/clothing/accessory/armband/fluff/vittorio_armband //ATLAS Armband - Vittorio Giurifiglio - tytostyris - name = "ATLAS armband" - desc = "This is an atlas armband showing anyone who sees this person, as a member of the Political party Atlas." - icon = 'icons/obj/custom_items/vittorio_armband.dmi' - icon_state = "vittorio_armband" - item_state = "vittorio_armband" - contained_sprite = 1 - /obj/item/clothing/head/fluff/vittorio_fez //Black Fez - Vittorio Giurifiglio - tytostyris name = "black fez" desc = "It is a black fez, it bears an Emblem of the Astronomical symbol of Earth, It also has some nice tassels." @@ -475,12 +468,12 @@ All custom items with worn sprites must follow the contained sprite system: http contained_sprite = 1 canremove = 0 abstract = 1 - species_restricted = list("Baseline Frame") + species_restricted = list("Machine") /obj/item/weapon/reagent_containers/food/drinks/flask/fluff/barcia_flask //First Shot - Gabriel Barcia - mrgabol100 name = "first shot" - desc = "A flask. Smells of absinthe, maybe vodka. The bottom left corner has a silver bar. \"The bottom is engraved, it reads 'The First Shot\"." + desc = "A flask. Smells of absinthe, maybe vodka. The bottom left corner has a silver bar. The bottom is engraved, it reads: \"The First Shot\"." icon = 'icons/obj/custom_items/barcia_flask.dmi' icon_state = "barcia_flask" @@ -497,6 +490,7 @@ All custom items with worn sprites must follow the contained sprite system: http gender = NEUTER body_parts_covered = null + /obj/item/clothing/under/dress/fluff/sayyidah_dress //Traditional Jumper Dress - Sayyidah Al-Kateb - alberyk name = "traditional jumper dress" desc = "A light summer-time dress, decorated neatly with black and silver colors, it seems to be rather old." @@ -552,7 +546,7 @@ All custom items with worn sprites must follow the contained sprite system: http user.visible_message("[user] thrust the [src.name] into [M]'s face.") -/obj/item/weapon/fluff/akela_photo // Akela's Family Photo - Akela Ha'kim - moltenkore +/obj/item/weapon/fluff/akela_photo //Akela's Family Photo - Akela Ha'kim - moltenkore name = "family photo" desc = "You see on the photo a tajaran couple holding a small kit in their arms, while looking very happy. On the back it is written; \"Nasir, Akela and Ishka\", with a little gold mark that reads: \"Two months\"." icon = 'icons/obj/custom_items/akela_photo.dmi' @@ -625,7 +619,7 @@ All custom items with worn sprites must follow the contained sprite system: http contained_sprite = 1 -/obj/item/sign/fluff/alexis_degree //Xenonuerology Doctorate - Alexis Shaw - Tenenza +/obj/item/sign/fluff/alexis_degree //Xenonuerology Doctorate - Alexis Shaw - tenenza name = "xenonuerology degree" desc = "Certification for a doctorate in Xenonuerology, made out to Alexis Shaw by the St. Grahelm University of Biesel, authenticated by watermarking." icon_state = "alexis_degree" @@ -730,8 +724,8 @@ All custom items with worn sprites must follow the contained sprite system: http w_class = 2 -/obj/item/clothing/accessory/fluff/zahra_pin //Indigo remembrance pin - Zahra Karimi - synnono - name = "Indigo remembrance pin" +/obj/item/clothing/accessory/fluff/zahra_pin //Indigo Remembrance Pin - Zahra Karimi - synnono + name = "indigo remembrance pin" desc = "A small metal pin, worked into the likeness of an indigo iris blossom." icon = 'icons/obj/custom_items/zahra_pin.dmi' icon_state = "zahra_pin" @@ -739,7 +733,7 @@ All custom items with worn sprites must follow the contained sprite system: http contained_sprite = 1 -/obj/item/clothing/accessory/armband/fluff/karl_armband //Medizinercorps armband - Karl Jonson - arrow768 +/obj/item/clothing/accessory/armband/fluff/karl_armband //Medizinercorps Armband - Karl Jonson - arrow768 name = "medizinercorps armband" desc = "A plain black armband with the golden Medizinercorps logo on it." icon = 'icons/obj/custom_items/karl_armband.dmi' @@ -856,7 +850,7 @@ All custom items with worn sprites must follow the contained sprite system: http /obj/item/clothing/head/beret/engineering/fluff/ikrad_beret //LR-31MTA Beret - Ikrad Yam'hir - houseofsynth - name = "LR-31MTA Beret" + name = "LR-31MTA beret" desc = "A silver beret with an insignia on the front, it looks like an old Tajaran cannon with a ring around it. \ Along the top half of the ring \"LR-31MTA\" is engraved. The word \"Yam'hir\" is engraved along the bottom half of the ring. \ The beret looks old and is worn in some places around the edges. It appears to have a flap inside, \ @@ -939,7 +933,7 @@ All custom items with worn sprites must follow the contained sprite system: http var/licensed_systems = "Republic of Biesel, Sol Alliance, Nralakk" var/supplementary_endorsements = "Licensed Medical Examiner; Sol Alliance, Republic of Biesel - Concealed firearm carry; Sol Alliance, Republic of Biesel" var/citizenship = "Republic of Biesel" - + /obj/item/clothing/accessory/badge/fluff/bell_badge/verb/read() set name = "Review credentials" set category = "Object" @@ -953,3 +947,83 @@ All custom items with worn sprites must follow the contained sprite system: http usr << "The systems that the credentials show the user is licensed to investigate in are [licensed_systems]." usr << "Additional endorsements registered on the card show: [supplementary_endorsements]." return + + +/obj/item/clothing/head/beret/engineering/fluff/karlan_beret //Family Beret - Kar'lan Sel'ler - toasterstrudes + name = "family beret" + desc = "A brown beret with an orange patch. The patch have the initials; \"K.S.\" sewn into it." + icon = 'icons/obj/custom_items/karlan_beret.dmi' + icon_state = "karlan_beret" + item_state = "karlan_beret" + contained_sprite = 1 + + +/obj/item/clothing/under/fluff/guskov_uniform //Tajaran Service Uniform - Guskov Andrei - fireandglory + name = "tajaran service uniform" + desc = "This is obviously a military service uniform, there are signs that it is of Tajaran make, modified to be a bit less warm, although it doesn't look like any uniform used by the People's Republic of Adhomai." + icon = 'icons/obj/custom_items/guskov_uniform.dmi' + icon_state = "guskov_uniform" + item_state = "guskov_uniform" + contained_sprite = 1 + + +/obj/item/weapon/fluff/zhilin_book //Siik'maas-Tau Ceti Basic Dictionary - Zhilin Vadim - fireandglory + name = "siik'maas-tau ceti basic dictionary" + desc = "A hefty dictionary with a simple design on the cover, it seems to be for translations. There's a label on the back denoting that it belongs to a \"Zhilin Vadim\"." + icon = 'icons/obj/custom_items/zhilin_book.dmi' + icon_state = "zhilin_book" + w_class = 3 + +/obj/item/weapon/fluff/zhilin_book/attack_self(mob/user as mob) + user.visible_message("[user] starts flipping through \the [src].", + "You start looking through \the [src], it appears to be filled with translations of Tau-Ceti basic for tajaran users.", + "You hear pages being flipped.") + playsound(src.loc, "pageturn", 50, 1) + + +/obj/item/clothing/suit/storage/toggle/fluff/fay_jacket //Emergency Response Team Duty Jacket - Fai Sinsa - soundscopes + name = "emergency response team duty jacket" + desc = "A militaristic duty jacket worn by members of the NanoTrasen Emergency Response Teams. The nameplate reads: \"Tpr Sinsa\"." + icon = 'icons/obj/custom_items/fai_jacket.dmi' + icon_state = "fai_jacket" + item_state = "fai_jacket" + icon_open = "fai_jacket_open" + icon_closed = "fai_jacket" + contained_sprite = 1 + + +/obj/item/clothing/under/fluff/faysal_uniform //Old Tajaran Nobleman Suit - Faysal Al-Shennawi - alberyk + name = "old tajaran nobleman suit" + desc = "A fancy looking suit, made of white line, adorned with golden details and buttons bearing long forgotten meanings. A blue sash decorates this piece of clothing." + icon = 'icons/obj/custom_items/faysal_uniform.dmi' + icon_state = "faysal_uniform" + item_state = "faysal_uniform" + contained_sprite = 1 + + +/obj/item/clothing/glasses/welding/fluff/ghoz_eyes //Prosthetic Vaurca Eyelids - Ka'Akaix'Ghoz Zo'ra - sleepywolf + name = "prosthetic vaurca eyelids" + desc = "A small contraption of micro-actuators with a button on the side." + icon = 'icons/obj/custom_items/ghoz_eyes.dmi' + icon_state = "ghoz_eyes" + item_state = "ghoz_eyes" + contained_sprite = 1 + action_button_name = "Toggle Eyelids" + species_restricted = list("Vaurca") //i think this would make sense since those are some kind of vaurca build prothestic + + +/obj/item/clothing/head/det/fluff/leo_hat //Tagged brown hat - Leo Wyatt - keinto + name = "tagged brown hat" + desc = "A worn mid 20th century brown hat. If you look closely at the back, you can see a an embedded tag from the \"Museum of Terran Culture and Technology\"." + icon = 'icons/obj/custom_items/leo_coat.dmi' + icon_state = "leo_hat" + item_state = "leo_hat" + contained_sprite = 1 + +/obj/item/clothing/suit/storage/det_trench/fluff/leo_coat //Tagged brown coat - Leo Wyatt - keinto + name = "tagged brown coat" + desc = "A worn mid 20th century brown trenchcoat. If you look closely at bottom of the back, you can see an embedded tag from the \"Museum of Terran Culture and Technology\"." + icon = 'icons/obj/custom_items/leo_coat.dmi' + icon_state = "leo_coat" + item_state = "leo_coat" + contained_sprite = 1 diff --git a/code/modules/detectivework/tools/uvlight.dm b/code/modules/detectivework/tools/uvlight.dm index 7cfc4bdf9c3..b2e62477855 100644 --- a/code/modules/detectivework/tools/uvlight.dm +++ b/code/modules/detectivework/tools/uvlight.dm @@ -7,7 +7,6 @@ item_state = "electronic" matter = list(DEFAULT_WALL_MATERIAL = 150) origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) - //offset_light = 1 var/list/scanned = list() var/list/stored_alpha = list() var/list/reset_objects = list() diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm index 3c211144a71..85edb8f37e7 100644 --- a/code/modules/economy/ATM.dm +++ b/code/modules/economy/ATM.dm @@ -32,12 +32,19 @@ log transactions var/obj/item/weapon/card/held_card var/editing_security_level = 0 var/view_screen = NO_SCREEN - var/datum/effect_system/sparks/spark_system -/obj/machinery/atm/New() +/obj/machinery/atm/initialize() ..() machine_id = "[station_name()] RT #[num_financial_terminals++]" - spark_system = bind_spark(src, 5) + +/obj/machinery/atm/Destroy() + authenticated_account = null + if (held_card) + held_card.forceMove(loc) + held_card = null + + return ..() + /obj/machinery/atm/process() if(stat & NOPOWER) @@ -66,7 +73,7 @@ log transactions //short out the machine, shoot sparks, spew money! emagged = 1 - spark_system.queue() + spark(src, 5, alldirs) spawn_money(rand(100,500),src.loc) //we don't want to grief people by locking their id in an emagged ATM release_held_id(user) diff --git a/code/modules/effects/effect_system.dm b/code/modules/effects/effect_system.dm index 2c6a985de9c..a68dcecb1ca 100644 --- a/code/modules/effects/effect_system.dm +++ b/code/modules/effects/effect_system.dm @@ -29,3 +29,9 @@ /datum/effect_system/proc/bind(var/target) holder = target + +/datum/effect_system/proc/set_loc(var/atom/movable/loc) + if (istype(loc, /turf/)) + location = loc + else + location = get_turf(loc) diff --git a/code/modules/effects/sparks/spawner.dm b/code/modules/effects/sparks/spawner.dm index dc195a04328..6f3790b866e 100644 --- a/code/modules/effects/sparks/spawner.dm +++ b/code/modules/effects/sparks/spawner.dm @@ -5,13 +5,10 @@ // Using the spark procs is preferred to directly instancing this. /datum/effect_system/sparks/New(var/atom/movable/loc, var/start_immediately = TRUE, var/amt = 1, var/list/spread_dirs = list()) - if(!loc || loc.gcDestroyed) + if(QDELETED(loc)) return - if (istype(loc, /turf)) - location = loc - else - holder = loc + set_loc(loc) if (amt) amount = amt @@ -34,8 +31,9 @@ var/total_sparks = 1 if (location) - var/obj/visual_effect/sparks/S = new /obj/visual_effect/sparks(location, src, 0) //Trigger one on the tile it's on + var/obj/visual_effect/sparks/S = getFromPool(/obj/visual_effect/sparks, location, src, 0) //Trigger one on the tile it's on S.start() + playsound(location, "sparks", 100, 1) effects_visuals += S // Queue it. while (total_sparks <= src.amount) @@ -47,7 +45,7 @@ else direction = pick(src.spread) - S = new /obj/visual_effect/sparks(location, src) + S = getFromPool(/obj/visual_effect/sparks, location, src) S.start(direction) effects_visuals += S total_sparks++ diff --git a/code/modules/effects/sparks/visuals.dm b/code/modules/effects/sparks/visuals.dm index 185a46f5af1..7e55170e3d1 100644 --- a/code/modules/effects/sparks/visuals.dm +++ b/code/modules/effects/sparks/visuals.dm @@ -1,27 +1,24 @@ // -- Spark visual_effect -- /obj/visual_effect/sparks name = "sparks" - icon = 'icons/effects/effects.dmi' - //icon_state = "sparks" + icon_state = "sparks" anchored = 1 mouse_opacity = 0 - live_icon_state = "sparks" /obj/visual_effect/sparks/New(var/turf/loc) ..(loc) - life_ticks = rand(2,10) - -/obj/visual_effect/sparks/resetVariables() - . = ..() - life_ticks = rand(2,10) + life_ticks = rand(5,10) /obj/visual_effect/sparks/tick() . = ..() - var/turf/T = loc + var/turf/T = get_turf(src) if(T) T.hotspot_expose(1000, 100) + if (life_ticks < 2) + animate(src, alpha = 0, time = 2, easing = SINE_EASING | EASE_IN) + /obj/visual_effect/sparks/start(var/direction) ..() if (direction) diff --git a/code/modules/effects/visual_effect.dm b/code/modules/effects/visual_effect.dm index a8caa85fdc2..454d1e3c2fe 100644 --- a/code/modules/effects/visual_effect.dm +++ b/code/modules/effects/visual_effect.dm @@ -1,23 +1,22 @@ /obj/visual_effect name = "effect" + icon = 'icons/effects/effects.dmi' anchored = 1 simulated = 0 mouse_opacity = 0 var/life_ticks // How many ticks this effect will life before it stops processing. var/life_ticks_max // The high limit for the random tick picker. var/life_ticks_min // The low limit for the random tick picker. - var/live_icon_state // The icon-state to use when this object is shown to the user. /obj/visual_effect/New(var/life_min = 3 SECONDS, var/life_max = 5 SECONDS) ..() life_ticks_min = life_min life_ticks_max = life_max life_ticks = rand(life_ticks_min, life_ticks_max) + flick(icon_state, src) // Called when the visual_effect is manifested. /obj/visual_effect/proc/start() - if (live_icon_state) - icon_state = live_icon_state // Called every effects processor tick. Return value determines what the process does to this object. /obj/visual_effect/proc/tick() @@ -30,8 +29,6 @@ // Called just before the visual_effect is returned to the pool. /obj/visual_effect/proc/end() loc = null - if (live_icon_state) - icon_state = null /obj/visual_effect/Destroy() // ¯\_(ツ)_/¯ diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 2cdf60c4ba1..f1fa744ffca 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -142,7 +142,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Trivial News", /datum/event/trivial_news, 400), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 60, list(ASSIGNMENT_JANITOR = 20, ASSIGNMENT_SECURITY = 10)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 75, list(ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_GARDENER = 20)), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Clogged Vents", /datum/event/vent_clog, 70), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Clogged Vents", /datum/event/vent_clog, 55), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "False Alarm", /datum/event/false_alarm, 100), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Supply Drop", /datum/event/supply_drop, 80), @@ -172,13 +172,13 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT /datum/event_container/major severity = EVENT_LEVEL_MAJOR available_events = list( - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Nothing", /datum/event/nothing, 105), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 50, list(ASSIGNMENT_ENGINEER = 5,ASSIGNMENT_SECURITY = 5), 1), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, 60, list(ASSIGNMENT_SECURITY = 10), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Nothing", /datum/event/nothing, 135), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 40, list(ASSIGNMENT_ENGINEER = 5,ASSIGNMENT_SECURITY = 5), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, 50, list(ASSIGNMENT_SECURITY = 10), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 40, list(ASSIGNMENT_ENGINEER = 10),1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 75, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_GARDENER = 20), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Viral Infection", /datum/event/viral_infection, 20, list(ASSIGNMENT_MEDICAL = 15), 1), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Bluespace Bears", /datum/event/bear_attack, 35, list(ASSIGNMENT_SECURITY = 10), 1) + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Bluespace Bears", /datum/event/bear_attack, 25, list(ASSIGNMENT_SECURITY = 10), 1) ) //NOTE: Re added nothing option, but with fairly low weight diff --git a/code/modules/food/recipe.dm b/code/modules/food/recipe.dm index 394aaf2651a..a4a2a32ddbf 100644 --- a/code/modules/food/recipe.dm +++ b/code/modules/food/recipe.dm @@ -69,6 +69,10 @@ /datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents) if (!reagents || !reagents.len) return 1 + + if (!avail_reagents) + return 0 + . = 1 for (var/r_r in reagents) var/aval_r_amnt = avail_reagents.get_reagent_amount(r_r) diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index 6b4f613f47d..3e0bc2582a0 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -146,9 +146,10 @@ I said no! proc/warm_up(var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked) being_cooked.heat() make_food(var/obj/container as obj) - var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked = ..(container) - warm_up(being_cooked) - return being_cooked + . = ..(container) + for (var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/D in .) + if (!D.warm) + warm_up(D) /datum/recipe/donkpocket/warm reagents = list() //This is necessary since this is a child object of the above recipe and we don't want donk pockets to need flour @@ -156,11 +157,6 @@ I said no! /obj/item/weapon/reagent_containers/food/snacks/donkpocket ) result = /obj/item/weapon/reagent_containers/food/snacks/donkpocket //SPECIAL - make_food(var/obj/container as obj) - var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked = locate() in container - if(being_cooked && !being_cooked.warm) - warm_up(being_cooked) - return being_cooked @@ -300,9 +296,10 @@ I said no! reagents = list("water" = 5, "vodka" = 5, "amatoxin" = 5) result = /obj/item/weapon/reagent_containers/food/snacks/amanitajelly make_food(var/obj/container as obj) - var/obj/item/weapon/reagent_containers/food/snacks/amanitajelly/being_cooked = ..(container) - being_cooked.reagents.del_reagent("amatoxin") - return being_cooked + + . = ..(container) + for (var/obj/item/weapon/reagent_containers/food/snacks/amanitajelly/being_cooked in .) + being_cooked.reagents.del_reagent("amatoxin") /datum/recipe/meatballsoup fruit = list("carrot" = 1, "potato" = 1) @@ -653,9 +650,10 @@ I said no! items = list(/obj/item/weapon/reagent_containers/food/snacks/meatball) result = /obj/item/weapon/reagent_containers/food/snacks/validsalad make_food(var/obj/container as obj) - var/obj/item/weapon/reagent_containers/food/snacks/validsalad/being_cooked = ..(container) - being_cooked.reagents.del_reagent("toxin") - return being_cooked + + . = ..(container) + for (var/obj/item/weapon/reagent_containers/food/snacks/validsalad/being_cooked in .) + being_cooked.reagents.del_reagent("toxin") diff --git a/code/modules/food/recipes_oven.dm b/code/modules/food/recipes_oven.dm index 42142abb433..21bf6cf2214 100644 --- a/code/modules/food/recipes_oven.dm +++ b/code/modules/food/recipes_oven.dm @@ -226,12 +226,35 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/fortunecookie make_food(var/obj/container as obj) - var/obj/item/weapon/paper/paper = locate() in container - paper.loc = null //prevent deletion - var/obj/item/weapon/reagent_containers/food/snacks/fortunecookie/being_cooked = ..(container) - paper.loc = being_cooked - being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn - return being_cooked + + var/obj/item/weapon/paper/paper + + //Fuck fortune cookies. This is a quick hack + //Duplicate the item searching code with a special case for paper + for (var/i in items) + var/obj/item/I = locate(i) in container + if (!paper && istype(I, /obj/item/weapon/paper)) + paper = I + continue + + if (I) + qdel(I) + + //Then store and null out the items list so it wont delete any paper + var/list/L = items.Copy() + items = null + . = ..(container) + + //Restore items list, so that making fortune cookies once doesnt break the oven + items = L + + + for (var/obj/item/weapon/reagent_containers/food/snacks/fortunecookie/being_cooked in .) + paper.loc = being_cooked + being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn + return + + check_items(var/obj/container as obj) . = ..() if (.) diff --git a/code/modules/http/post_request.dm b/code/modules/http/post_request.dm index ffc04a1d872..e7de7a6affe 100644 --- a/code/modules/http/post_request.dm +++ b/code/modules/http/post_request.dm @@ -58,7 +58,7 @@ var/result = call("ByondPOST.dll", "send_post_request")(arglist(args)) if (!result) - log_debug("ByondPOST: No result returned from external library.") + log_debug("ByondPOST POST: No result returned from external library.") return -1 var/list/A = params2list(result) @@ -67,14 +67,61 @@ // Log the proc error. It should be reviewed by coders ASAP. switch (A["proc"]) if ("1") - log_debug("ByondPOST: Proc error: Too few arguments sent to function.") + log_debug("ByondPOST POST: Proc error: Too few arguments sent to function.") if ("2") - log_debug("ByondPOST: Proc error: Unable to initialize curl object.") + log_debug("ByondPOST POST: Proc error: Unable to initialize curl object.") else - log_debug("ByondPOST: Proc error: Unknown error.") + log_debug("ByondPOST POST: Proc error: Unknown error.") return -1 // Curl oriented errors should leave the HTTP response code at 0, as no request was executed. // All HTTP oriented errors will definately return a response code other than 0, so prioritize that. // Fallback is a curl error code (0 - 92). return text2num(A["http"]) != 0 ? text2num(A["http"]) : text2num(A["curl"]) + +/* + * A generic proc for sending a header equipped get requests with the aforementioned .DLL files. + * If you're using this without sending custom headers, please stop. Use world.Export() instead. + * Expected arg structure: + * 1st arg - the url + * 2nd - nth arg - individual headers and their values in format: "headername: value" + * + * @return mixed - Returns list if request was successful, integer (specific cURL or HTTP error) if failed. + * -1 indicates proc or library failure. + * 0 - 92 are curl errors, and are usually accompanied by a HTTP response code of 0 (request was never made). + * 100 - 6xx are HTTP response codes. Curl error code should be 0 in this case, but, in case that it is not, + * the HTTP response code is always returned as long as it is not 0. + * + */ +/proc/send_get_request() + if (args.len < 2) + return -1 + + var/result = call("ByondPOST.dll", "send_get_request")(arglist(args)) + + if (!result) + log_debug("ByondPOST GET: No result returned from external library.") + return -1 + + var/list/A + + // Try to evaluate it as JSON data (successful request) + try + A = json_decode(result) + + return A + catch() + // Nope, we failed. do regular error parsing instead. + A = params2list(result) + + if (!isnull(A["proc"])) + switch (A["proc"]) + if ("1") + log_debug("ByondPOST GET: Proc error: Too few arguments sent to function.") + if ("2") + log_debug("ByondPOST GET: Proc error: Unable to initialize curl object.") + else + log_debug("ByondPOST GET: Proc error: Unknown error.") + return -1 + + return text2num(A["http"]) != 0 ? text2num(A["http"]) : text2num(A["curl"]) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 526ba4285b5..995e372de8a 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -226,19 +226,20 @@ qdel(src) return else if(seed.get_trait(TRAIT_FLESH_COLOUR)) - user << "You slice up \the [src]." - var/slices = rand(3,5) - var/reagents_to_transfer = round(reagents.total_volume/slices) - for(var/i=i;i<=slices;i++) - var/obj/item/weapon/reagent_containers/food/snacks/fruit_slice/F = new(get_turf(src),seed) - if(reagents_to_transfer) reagents.trans_to_obj(F,reagents_to_transfer) - qdel(src) - return + if (reagents.total_volume) + user << "You slice up \the [src]." + var/slices = rand(3,5) + var/reagents_to_transfer = reagents.total_volume/slices + for(var/i=0;i 0 @@ -314,15 +323,12 @@ var/tb = PSEUDO_WEDGE(test_x, test_y, limit_b_x, limit_b_y) // if the signs of both at and tb are NOT the same, the point is NOT within the cone. - if ((at > 0) != targ_sign) - return TRUE - - if ((tb > 0) != targ_sign) - return TRUE + return (((at > 0) != targ_sign) || ((tb > 0) != targ_sign)) #undef POLAR_TO_CART_X #undef POLAR_TO_CART_Y #undef PSEUDO_WEDGE +#undef MINMAX // This is the define used to calculate falloff. #define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) @@ -332,6 +338,9 @@ var/static/update_gen = 1 applied = 1 + if (!source_turf) + return + var/Tx var/Ty var/Sx = source_turf.x diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 848a99af2e6..4935e8d2ea2 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -39,10 +39,10 @@ var/area/A = loc if (A.dynamic_lighting && dynamic_lighting) - if (!lighting_corners_initialised) + if (!lighting_corners_initialised || !corners) generate_missing_corners() - getFromPool(/atom/movable/lighting_overlay, src) + new /atom/movable/lighting_overlay(src) for (var/datum/lighting_corner/C in corners) if (!C.active) // We would activate the corner, calculate the lighting for it. @@ -55,7 +55,7 @@ #define SCALE(targ,min,max) (targ - min) / (max - min) // Used to get a scaled lumcount. -/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) +/turf/proc/get_lumcount(minlum = 0, maxlum = 1) if (!lighting_overlay) return 0.5 @@ -70,7 +70,7 @@ return CLAMP01(totallums) // Gets the current UV illumination of the turf. Always 100% for space & other static-lit tiles. -/turf/proc/get_uv_lumcount(var/minlum = 0, var/maxlum = 1) +/turf/proc/get_uv_lumcount(minlum = 0, maxlum = 1) if (!lighting_overlay) return 1 @@ -97,21 +97,21 @@ return // No need to continue if we find something opaque. // If an opaque movable atom moves around we need to potentially update visibility. -/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc) +/turf/Entered(atom/movable/Obj, atom/OldLoc) . = ..() if (Obj && Obj.opacity) has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. reconsider_lights() -/turf/Exited(var/atom/movable/Obj, var/atom/newloc) +/turf/Exited(atom/movable/Obj, atom/newloc) . = ..() if (Obj && Obj.opacity) recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates. reconsider_lights() -/turf/change_area(var/area/old_area, var/area/new_area) +/turf/change_area(area/old_area, area/new_area) if (new_area.dynamic_lighting != old_area.dynamic_lighting) if (new_area.dynamic_lighting) lighting_build_overlay() diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index 7588f29ffb1..9d10a706e23 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -429,8 +429,9 @@ var/list/name_to_material if(!is_reinforced()) user << "This material is not reinforced enough to use for a door." return - if((locate(/obj/structure/windoor_assembly) in T.contents) || (locate(/obj/machinery/door/window) in T.contents)) - failed_to_build = 1 + for(var/obj/obstacle in T) + if((obstacle.flags & ON_BORDER) && obstacle.dir == user.dir) + failed_to_build = 1 if(failed_to_build) user << "There is no room in this location." return 1 @@ -466,7 +467,7 @@ var/list/name_to_material tableslam_noise = 'sound/effects/Glasshit.ogg' hardness = 40 weight = 30 - stack_origin_tech = "materials=2" + stack_origin_tech = list(TECH_MATERIAL = 2) composite_material = list(DEFAULT_WALL_MATERIAL = 1875,"glass" = 3750) window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 5) created_window = /obj/structure/window/reinforced @@ -768,7 +769,7 @@ var/list/name_to_material flags = MATERIAL_PADDING hardness = 1 weight = 1 - + /material/hide/corgi name = "corgi hide" stack_type = /obj/item/stack/material/animalhide/corgi @@ -778,17 +779,17 @@ var/list/name_to_material name = "cat hide" stack_type = /obj/item/stack/material/animalhide/cat icon_colour = "#444444" - + /material/hide/monkey name = "monkey hide" stack_type = /obj/item/stack/material/animalhide/monkey icon_colour = "#914800" - + /material/hide/lizard name = "lizard hide" stack_type = /obj/item/stack/material/animalhide/lizard icon_colour = "#34AF10" - + /material/hide/xeno name = "alien hide" stack_type = /obj/item/stack/material/animalhide/xeno @@ -811,7 +812,7 @@ var/list/name_to_material integrity = 70 stack_origin_tech = list(TECH_MATERIAL = 2) door_icon_base = "stone" - + /material/bone/necromancer name = "cursed bone" weight = 20 diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm index b5035b2cf20..e3c786dc85e 100644 --- a/code/modules/mining/drilling/drill.dm +++ b/code/modules/mining/drilling/drill.dm @@ -55,6 +55,10 @@ RefreshParts() +/obj/machinery/mining/drill/Destroy() + QDEL_NULL(spark_system) + return ..() + /obj/machinery/mining/drill/process() if(need_player_check) diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index ea15d8391f5..f06cb656a38 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -31,11 +31,9 @@ has_resources = 1 -/turf/simulated/mineral/New() - spawn(0) - MineralSpread() - spawn(2) - updateMineralOverlays(1) +/turf/simulated/mineral/initialize() + MineralSpread() + updateMineralOverlays(TRUE) /turf/simulated/mineral/proc/updateMineralOverlays(var/update_neighbors) var/list/step_overlays = list("s" = NORTH, "n" = SOUTH, "w" = EAST, "e" = WEST) @@ -45,7 +43,9 @@ var/turf/simulated/floor/asteroid/T = turf_to_check T.updateMineralOverlays() else if(istype(turf_to_check,/turf/space) || istype(turf_to_check,/turf/simulated/floor)) - turf_to_check.overlays += image('icons/turf/walls.dmi', "rock_side", dir = turn(step_overlays[direction], 180)) + var/image/overlay = image('icons/turf/walls.dmi', "rock_side", dir = turn(step_overlays[direction], 180)) + overlay.plane = 0 + turf_to_check.overlays += overlay /turf/simulated/mineral/examine(mob/user) ..() @@ -507,6 +507,9 @@ if(prob(20)) overlay_detail = rand(0,9) +/turf/simulated/floor/asteroid/initialize() + updateMineralOverlays(1) + /turf/simulated/floor/asteroid/ex_act(severity) switch(severity) if(3.0) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 15765004498..b90e90b0538 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -13,6 +13,7 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images blinded = 0 anchored = 1 // don't get pushed around invisibility = INVISIBILITY_OBSERVER + simulated = FALSE var/can_reenter_corpse var/datum/hud/living/carbon/hud = null // hud var/bootime = 0 diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm index 08531eca1f4..45a2dccbff5 100644 --- a/code/modules/mob/holder.dm +++ b/code/modules/mob/holder.dm @@ -18,6 +18,7 @@ var/list/holder_mob_icon_cache = list() var/last_loc_specific//This stores specific extra information about the location, pocket, hand, worn on head, etc. Only relevant to mobs /obj/item/weapon/holder/New() + tag = rand(0,9999) if (!item_state) item_state = icon_state @@ -27,6 +28,7 @@ var/list/holder_mob_icon_cache = list() processing_objects.Add(src) /obj/item/weapon/holder/Destroy() + reagents = null processing_objects.Remove(src) if (contained) release_mob() @@ -36,23 +38,10 @@ var/list/holder_mob_icon_cache = list() if (contained) contained.examine(user) - -/obj/item/weapon/holder/GetID() - for(var/mob/M in contents) - var/obj/item/I = M.GetIdCard() - if(I) - return I - return null - -/obj/item/weapon/holder/GetAccess() - var/obj/item/I = GetID() - return I ? I.GetAccess() : ..() - /obj/item/weapon/holder/attack_self() for(var/mob/M in contents) M.show_inv(usr) - //Mob specific holders. /obj/item/weapon/holder/diona origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 5) @@ -104,6 +93,8 @@ var/list/holder_mob_icon_cache = list() //Releases all mobs inside the holder, then deletes it. //is_unsafe_container should be checked before calling this +//This function releases mobs into wherever the holder currently is. Its not safe to call from a lot of places +//Use release_to_floor for a simple, safe release /obj/item/weapon/holder/proc/release_mob() for(var/mob/M in contents) var/atom/movable/mob_container @@ -112,6 +103,7 @@ var/list/holder_mob_icon_cache = list() M.reset_view() M.Released() + contained = null var/mob/L = get_holding_mob() if (L) @@ -120,6 +112,23 @@ var/list/holder_mob_icon_cache = list() qdel(src) +//Similar to above function, but will not deposit things in any container, only directly on a turf. +//Can be called safely anywhere. Notably on holders held or worn on a mob +/obj/item/weapon/holder/proc/release_to_floor() + var/turf/T = get_turf(src) + var/mob/L = get_holding_mob() + if (L) + L.drop_from_inventory(src) + + for(var/mob/M in contents) + M.forceMove(T) //if the holder was placed into a disposal, this should place the animal in the disposal + M.reset_view() + M.Released() + + contained = null + + qdel(src) + /obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob) for(var/mob/M in src.contents) M.attackby(W,user) @@ -368,19 +377,17 @@ var/list/holder_mob_icon_cache = list() desc_dead = "It used to be a little plant critter." icon_state = "nymph" icon_state_dead = "nymph_dead" - origin_tech = "magnets=3;biotech=5" + origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 5) slot_flags = SLOT_HEAD | SLOT_OCLOTHING w_class = 2 - - /obj/item/weapon/holder/drone name = "maintenance drone" desc = "It's a small maintenance robot." icon_state = "drone" item_state = "drone" - origin_tech = "magnets=3;engineering=5" + origin_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 5) slot_flags = SLOT_HEAD w_class = 4 contained_sprite = 1 @@ -429,7 +436,7 @@ var/list/holder_mob_icon_cache = list() name = "cortical borer" desc = "It's a slimy brain slug. Gross." icon_state = "brainslug" - origin_tech = "biotech=6" + origin_tech = list(TECH_BIO = 6) w_class = 1 /obj/item/weapon/holder/monkey @@ -476,7 +483,7 @@ var/list/holder_mob_icon_cache = list() icon_state_dead = "mouse_brown_dead" slot_flags = SLOT_EARS contained_sprite = 1 - origin_tech = "biotech=2" + origin_tech = list(TECH_BIO = 2) w_class = 1 /obj/item/weapon/holder/mouse/white @@ -579,4 +586,4 @@ var/list/holder_mob_icon_cache = list() /obj/item/weapon/holder/pai/rabbit icon_state = "rabbit_rest" - item_state = "rabbit" \ No newline at end of file + item_state = "rabbit" diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index 23ee3510c46..1508c3056e5 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -52,6 +52,8 @@ var/list/cleanbot_types // Going to use this to generate a list of types once th listener = new /obj/cleanbot_listener(src) listener.cleanbot = src + janitorial_supplies |= src + if(radio_controller) radio_controller.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS) @@ -61,6 +63,7 @@ var/list/cleanbot_types // Going to use this to generate a list of types once th patrol_path = null target = null ignorelist = null + janitorial_supplies -= src /mob/living/bot/cleanbot/proc/handle_target() if(target.clean_marked && target.clean_marked != src) diff --git a/code/modules/mob/living/carbon/alien/diona/progression.dm b/code/modules/mob/living/carbon/alien/diona/progression.dm index d5990e00d32..73c4f521df3 100644 --- a/code/modules/mob/living/carbon/alien/diona/progression.dm +++ b/code/modules/mob/living/carbon/alien/diona/progression.dm @@ -66,6 +66,10 @@ for (var/obj/item/W in src.contents) src.drop_from_inventory(W) + //So that the nymph doesn't get basic for free when evolving. + if (adult.languages) + adult.languages.Cut() + for(var/datum/language/L in languages) adult.add_language(L.name) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 29da49536fe..f7857ed2899 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -17,13 +17,10 @@ germ_level++ /mob/living/carbon/Destroy() - qdel(ingested) - qdel(touching) + QDEL_NULL(touching) // We don't qdel(bloodstr) because it's the same as qdel(reagents) for(var/guts in internal_organs) qdel(guts) - for(var/food in stomach_contents) - qdel(food) return ..() /mob/living/carbon/rejuvenate() diff --git a/code/modules/mob/living/carbon/diona_base.dm b/code/modules/mob/living/carbon/diona_base.dm index 70ef8be96ac..11fd1775d32 100644 --- a/code/modules/mob/living/carbon/diona_base.dm +++ b/code/modules/mob/living/carbon/diona_base.dm @@ -81,19 +81,19 @@ var/list/diona_banned_languages = list( //But diona gestalts gain nutrition by extracting matter from gases in the air. If a gestalt spends a long time in space or on the asteroid, it may need to actually eat food //For simplicity, we'll assume any gas is fine, so they'll just absorb nutrition based on pressure if (!pressure) - return + return 0 if (DS.nutrient_organ) if (DS.nutrient_organ.is_broken()) - return + return 0 var/plus= (min(pressure,diona_max_pressure) / diona_max_pressure)* diona_nutrition_factor if (DS.nutrient_organ) if(DS.nutrient_organ.is_bruised()) plus *= 0.5 + plus = min(plus, max_nutrition - nutrition) nutrition += plus - if (nutrition > max_nutrition) - nutrition = max_nutrition + return plus*7 //The return value is the number of moles to remove from the local environment /mob/living/carbon/proc/diona_handle_temperature(var/datum/dionastats/DS) if (bodytemperature < TEMP_REGEN_STOP) @@ -270,7 +270,7 @@ var/list/diona_banned_languages = list( for (var/i in species.has_limbs) path = species.has_limbs[i]["path"] var/limb_exists = 0 - for (var/obj/item/organ/external/diona/B in H.organs) + for (var/obj/item/organ/external/B in H.organs) if (B.type == path) limb_exists = 1 break diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 847715dd270..75731569f93 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -39,20 +39,21 @@ var/obj/item/organ/external/head = get_organ("head") var/mob/living/simple_animal/borer/B - for(var/I in head.implants) - if(istype(I,/mob/living/simple_animal/borer)) - B = I - if(B) - if(!B.ckey && ckey && B.controlling) - B.ckey = ckey - B.controlling = 0 - if(B.host_brain.ckey) - ckey = B.host_brain.ckey - B.host_brain.ckey = null - B.host_brain.name = "host brain" - B.host_brain.real_name = "host brain" + if (head) + for(var/I in head.implants) + if(istype(I,/mob/living/simple_animal/borer)) + B = I + if(B) + if(!B.ckey && ckey && B.controlling) + B.ckey = ckey + B.controlling = 0 + if(B.host_brain.ckey) + ckey = B.host_brain.ckey + B.host_brain.ckey = null + B.host_brain.name = "host brain" + B.host_brain.real_name = "host brain" - verbs -= /mob/living/carbon/proc/release_control + verbs -= /mob/living/carbon/proc/release_control callHook("death", list(src, gibbed)) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index e644681b0f3..e9fa53899a0 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -81,8 +81,30 @@ human_mob_list -= src for(var/organ in organs) qdel(organ) - if (DS) - qdel(DS)//prevents the dionastats holding onto references and blocking GC + organs = null + internal_organs_by_name = null + internal_organs = null + organs_by_name = null + bad_internal_organs = null + bad_external_organs = null + + QDEL_NULL(DS) + // qdel and null out our equipment. + QDEL_NULL(shoes) + QDEL_NULL(belt) + QDEL_NULL(gloves) + QDEL_NULL(glasses) + QDEL_NULL(head) + QDEL_NULL(l_ear) + QDEL_NULL(r_ear) + QDEL_NULL(wear_id) + QDEL_NULL(r_store) + QDEL_NULL(l_store) + QDEL_NULL(s_store) + QDEL_NULL(wear_suit) + // Do this last so the mob's stuff doesn't drop on del. + QDEL_NULL(w_uniform) + return ..() /mob/living/carbon/human/Stat() @@ -210,7 +232,11 @@ /mob/living/carbon/human/proc/implant_loyalty(mob/living/carbon/human/M, override = FALSE) // Won't override by default. if(!config.use_loyalty_implants && !override) return // Nuh-uh. - var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(M) + var/obj/item/weapon/implant/loyalty/L + if(isipc(M)) + L = new/obj/item/weapon/implant/loyalty/ipc(M) + else + L = new/obj/item/weapon/implant/loyalty(M) L.imp_in = M L.implanted = 1 var/obj/item/organ/external/affected = M.organs_by_name["head"] diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index a65027aca39..93a7da1fbfa 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -116,4 +116,3 @@ /mob/living/carbon/human/terminator mob_size = 30 - //offset_light = 1 diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index aa26a0710d2..674304f1e33 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -618,7 +618,7 @@ var/adjusted_pressure = calculate_affecting_pressure(pressure) if (is_diona()) - diona_handle_air(get_dionastats(), pressure) + environment.remove(diona_handle_air(get_dionastats(), pressure)) //Check for contaminants before anything else because we don't want to skip it. for(var/g in environment.gas) @@ -1055,11 +1055,14 @@ handle_statuses() if (drowsyness) - drowsyness-- - eye_blurry = max(2, eye_blurry) - if (prob(5)) - sleeping += 1 - Paralyse(5) + if (drowsyness < 0) + drowsyness = 0 + else + drowsyness-- + eye_blurry = max(2, eye_blurry) + if (prob(5)) + sleeping += 1 + Paralyse(5) confused = max(0, confused - 1) @@ -1461,7 +1464,7 @@ if (BITTEST(hud_updateflag, ID_HUD) && hud_list[ID_HUD]) var/image/holder = hud_list[ID_HUD] - + //The following function is found in code/defines/procs/hud.dm holder.icon_state = get_sec_hud_icon(src) hud_list[ID_HUD] = holder diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 8fa5dddad77..7a04d4e972e 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -40,6 +40,8 @@ var/virus_immune var/short_sighted var/bald = 0 + var/light_range + var/light_power // Language/culture vars. var/default_language = "Ceti Basic" // Default language is used when 'say' is used without modifiers. @@ -438,3 +440,6 @@ return 0 H.hud_used.move_intent.update_move_icon(H) return 1 + +/datum/species/proc/get_light_color(hair_style) + return diff --git a/code/modules/mob/living/carbon/human/species/species_hud.dm b/code/modules/mob/living/carbon/human/species/species_hud.dm index d3591803be6..13354058ebb 100644 --- a/code/modules/mob/living/carbon/human/species/species_hud.dm +++ b/code/modules/mob/living/carbon/human/species/species_hud.dm @@ -57,7 +57,8 @@ gear = list( "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1), "o_clothing" = list("loc" = ui_shoes, "name" = "Suit", "slot" = slot_wear_suit, "state" = "suit", "toggle" = 1), - "l_ear" = list("loc" = ui_gloves, "name" = "Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), + "l_ear" = list("loc" = ui_glasses, "name" = "Left Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), + "r_ear" = list("loc" = ui_gloves, "name" = "Right Ear", "slot" = slot_r_ear, "state" = "ears", "toggle" = 1), "head" = list("loc" = ui_oclothing, "name" = "Hat", "slot" = slot_head, "state" = "hair", "toggle" = 1), "suit storage" = list("loc" = ui_sstore1, "name" = "Suit Storage", "slot" = slot_s_store, "state" = "suitstore"), "back" = list("loc" = ui_back, "name" = "Back", "slot" = slot_back, "state" = "back"), diff --git a/code/modules/mob/living/carbon/human/species/station/machine_subspecies.dm b/code/modules/mob/living/carbon/human/species/station/machine_subspecies.dm index 84431259827..39e460840ed 100644 --- a/code/modules/mob/living/carbon/human/species/station/machine_subspecies.dm +++ b/code/modules/mob/living/carbon/human/species/station/machine_subspecies.dm @@ -17,6 +17,9 @@ icobase = 'icons/mob/human_races/r_human.dmi' deform = 'icons/mob/human_races/robotic.dmi' + light_range = 0 + light_power = 0 + eyes = "eyes_s" show_ssd = "completely quiescent" @@ -48,6 +51,8 @@ "r_foot" = list("path" = /obj/item/organ/external/foot/right/shell) ) +/datum/species/machine/shell/get_light_color(hair_style) + return /datum/species/machine/shell/handle_post_spawn(var/mob/living/carbon/human/H) add_inherent_verbs(H) @@ -128,6 +133,9 @@ sprint_speed_factor = 1.4 +/datum/species/machine/industrial/get_light_color(hair_style) + return LIGHT_COLOR_TUNGSTEN + /datum/species/machine/industrial/handle_sprint_cost(var/mob/living/carbon/human/H, var/cost) if (H.stat == CONSCIOUS) H.bodytemperature += cost*0.9 @@ -156,6 +164,9 @@ icobase = 'icons/mob/human_races/r_terminator.dmi' deform = 'icons/mob/human_races/r_terminator.dmi' + light_range = 0 + light_power = 0 + unarmed_types = list(/datum/unarmed_attack/terminator) rarity_value = 20 @@ -231,6 +242,8 @@ sprint_speed_factor = 1.25 slowdown = 1 +/datum/species/machine/terminator/get_light_color(hair_style) + return /datum/species/machine/terminator/handle_sprint_cost(var/mob/living/carbon/human/H, var/cost) if (H.stat == CONSCIOUS) diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index 2caa05ba8ee..2ec56544d9f 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -185,6 +185,7 @@ spawn_flags = CAN_JOIN | IS_WHITELISTED appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_SOCKS + flags = NO_SLIP flesh_color = "#8CD7A3" blood_color = "#1D2CBF" @@ -237,17 +238,17 @@ ) has_limbs = list( - "chest" = list("path" = /obj/item/organ/external/diona/chest), - "groin" = list("path" = /obj/item/organ/external/diona/groin), - "head" = list("path" = /obj/item/organ/external/diona/head), - "l_arm" = list("path" = /obj/item/organ/external/diona/arm), - "r_arm" = list("path" = /obj/item/organ/external/diona/arm/right), - "l_leg" = list("path" = /obj/item/organ/external/diona/leg), - "r_leg" = list("path" = /obj/item/organ/external/diona/leg/right), - "l_hand" = list("path" = /obj/item/organ/external/diona/hand), - "r_hand" = list("path" = /obj/item/organ/external/diona/hand/right), - "l_foot" = list("path" = /obj/item/organ/external/diona/foot), - "r_foot" = list("path" = /obj/item/organ/external/diona/foot/right) + "chest" = list("path" = /obj/item/organ/external/chest/diona), + "groin" = list("path" = /obj/item/organ/external/groin/diona), + "head" = list("path" = /obj/item/organ/external/head/diona), + "l_arm" = list("path" = /obj/item/organ/external/arm/diona), + "r_arm" = list("path" = /obj/item/organ/external/arm/right/diona), + "l_leg" = list("path" = /obj/item/organ/external/leg/diona), + "r_leg" = list("path" = /obj/item/organ/external/leg/right/diona), + "l_hand" = list("path" = /obj/item/organ/external/hand/diona), + "r_hand" = list("path" = /obj/item/organ/external/hand/right/diona), + "l_foot" = list("path" = /obj/item/organ/external/foot/diona), + "r_foot" = list("path" = /obj/item/organ/external/foot/right/diona) ) //inherent_verbs = list() @@ -355,6 +356,9 @@ icobase = 'icons/mob/human_races/r_machine.dmi' deform = 'icons/mob/human_races/r_machine.dmi' + light_range = 2 + light_power = 0.5 + unarmed_types = list(/datum/unarmed_attack/punch) rarity_value = 2 @@ -503,6 +507,55 @@ datum/species/machine/handle_post_spawn(var/mob/living/carbon/human/H) var/DBQuery/update_query = dbcon.NewQuery("UPDATE ss13_ipc_tracking SET tag_status = :status WHERE player_ckey = :ckey AND character_name = :character_name") update_query.Execute(query_details) +/datum/species/machine/get_light_color(hair_style) + // I hate this, but I can't think of a better way that doesn't involve + // rewriting hair. + switch (hair_style) + if ("pink IPC screen") + return LIGHT_COLOR_PINK + + if ("red IPC screen") + return LIGHT_COLOR_RED + + if ("green IPC screen") + return LIGHT_COLOR_GREEN + + if ("blue IPC screen") + return LIGHT_COLOR_BLUE + + if ("breakout IPC screen") + return LIGHT_COLOR_CYAN + + if ("eight IPC screen") + return LIGHT_COLOR_CYAN + + if ("goggles IPC screen") + return LIGHT_COLOR_RED + + if ("heart IPC screen") + return LIGHT_COLOR_PINK + + if ("monoeye IPC screen") + return LIGHT_COLOR_ORANGE + + if ("nature IPC screen") + return LIGHT_COLOR_CYAN + + if ("orange IPC screen") + return LIGHT_COLOR_ORANGE + + if ("purple IPC screen") + return LIGHT_COLOR_PURPLE + + if ("shower IPC screen") + return "#FFFFFF" + + if ("static IPC screen") + return "#FFFFFF" + + if ("yellow IPC screen") + return LIGHT_COLOR_YELLOW + /datum/species/bug name = "Vaurca Worker" short_name = "vau" diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 163cd728143..dd4c8932cd4 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -389,6 +389,16 @@ var/global/list/damage_icon_parts = list() face_standing.Blend(hair_s, ICON_OVERLAY) + if (species.light_range) + var/col = species.get_light_color(h_style) + if (!col) + col = "#FFFFFF" + + set_light(species.light_range, species.light_power, col, uv = 0, angle = LIGHT_WIDE) + + else if (species.light_range) + set_light(FALSE) + overlays_standing[HAIR_LAYER] = image(face_standing) if(update_icons) update_icons() @@ -769,8 +779,9 @@ var/global/list/damage_icon_parts = list() if(istype(head,/obj/item/clothing/head)) var/obj/item/clothing/head/hat = head - if(hat.on && light_overlay_cache["[hat.light_overlay]"]) - standing.overlays |= light_overlay_cache["[hat.light_overlay]"] + var/cache_key = "[hat.light_overlay]_[species.get_bodytype()]" + if(hat.on && light_overlay_cache["[cache_key]"]) + standing.overlays |= light_overlay_cache["[cache_key]"] standing.color = head.color overlays_standing[HEAD_LAYER] = standing diff --git a/code/modules/mob/living/carbon/metroid/items.dm b/code/modules/mob/living/carbon/metroid/items.dm index 77832a39bf2..626b011f6f1 100644 --- a/code/modules/mob/living/carbon/metroid/items.dm +++ b/code/modules/mob/living/carbon/metroid/items.dm @@ -268,7 +268,7 @@ var/mob/living/carbon/human/G = new(src.loc) G.set_species("Golem") G.key = ghost.key - G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost." + G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. Serve [user], and assist them in completing their goals at any cost." qdel(src) diff --git a/code/modules/mob/living/devour.dm b/code/modules/mob/living/devour.dm index c68c4f99006..80b1795af66 100644 --- a/code/modules/mob/living/devour.dm +++ b/code/modules/mob/living/devour.dm @@ -47,7 +47,8 @@ return 0 if (devouring == victim) - src << span("danger","You're already eating that!.") + src << span("notice","You stop eating [victim].") + devouring = null return if (ishuman(src)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 408554a6ea9..923cc05d5bc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -782,3 +782,11 @@ default behaviour is: src << "You are now \the [src]!" src << "Remember to stay in character for a mob of this type!" return 1 + +/mob/living/Destroy() + for (var/thing in stomach_contents) + qdel(thing) + stomach_contents = null + QDEL_NULL(ingested) + + return ..() diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm index 9d9117b9330..72493c1617e 100644 --- a/code/modules/mob/living/silicon/robot/login.dm +++ b/code/modules/mob/living/silicon/robot/login.dm @@ -6,5 +6,5 @@ winset(src, null, "mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5") // Forces synths to select an icon relevant to their module - if(!icon_selected) + if(module && !icon_selected) choose_icon(icon_selection_tries, module_sprites) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index dc32aebae8a..bd865a06e85 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -22,7 +22,7 @@ var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best var/crisis //Admin-settable for combat module use. var/crisis_override = 0 - var/integrated_light_power = 6 + var/integrated_light_power = 4 var/datum/wires/robot/wires //Icon stuff @@ -249,6 +249,7 @@ connected_ai.connected_robots -= src qdel(wires) wires = null + QDEL_NULL(spark_system) return ..() /mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites) @@ -424,7 +425,7 @@ /mob/living/silicon/robot/proc/update_robot_light() if(lights_on) if(intenselight) - set_light(integrated_light_power * 2, integrated_light_power) + set_light(integrated_light_power * 2, 1) else set_light(integrated_light_power) else @@ -1032,6 +1033,7 @@ verbs -= /mob/living/silicon/robot/proc/choose_icon src << "Your icon has been set. You now require a module reset to change it." + /mob/living/silicon/robot/proc/sensor_mode() //Medical/Security HUD controller for borgs set name = "Set Sensor Augmentation" set category = "Robot Commands" diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 2248c7f28cd..1a15d52810c 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -90,7 +90,10 @@ user << "Your [src] already has something inside. Analyze or eject it first." return var/obj/item/I = target - I.loc = src + if (I.anchored) + user << span("notice", "\The [I] is anchored in place.") + return + I.forceMove(src) loaded_item = I for(var/mob/M in viewers()) M.show_message(text("[user] adds the [I] to the [src]."), 1) @@ -296,7 +299,7 @@ /obj/item/weapon/inflatable_dispenser/proc/try_deploy_inflatable(var/turf/T, var/mob/living/user) if (deploying) return - deploying = 1 + var/newtype if(mode) // Door deployment if(!stored_doors) @@ -314,9 +317,10 @@ if(T && istype(T)) newtype = /obj/structure/inflatable/wall + deploying = 1 user.visible_message(span("notice", "[user] starts deploying an inflatable"), span("notice", "You start deploying an inflatable [mode ? "door" : "wall"]!")) playsound(T, 'sound/items/zip.ogg', 75, 1) - if (do_after(user, 20, needhand = 0)) + if (do_after(user, 15, needhand = 0)) new newtype(T) if (mode) stored_doors-- diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 26cb5e11852..03a121bd61e 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -173,6 +173,7 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/standard/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/melee/baton/loaded(src) src.modules += new /obj/item/weapon/extinguisher(src) @@ -180,7 +181,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/crowbar(src) src.modules += new /obj/item/device/healthanalyzer(src) src.emag = new /obj/item/weapon/melee/energy/sword(src) - ..() + /obj/item/weapon/robot_module/medical name = "medical robot module" @@ -194,7 +195,7 @@ var/global/list/robot_modules = list( "Heavy" = "heavyMed", "Needles" = "medicalrobot", "Standard" = "surgeon", - "Advanced Droid - Medical" = "droid-surgery", + "Advanced Droid - Medical" = "droid-medical", "Advanced Droid - Chemistry" = "droid-chemistry", "Drone - Medical" = "drone-surgery", "Drone - Chemistry" = "drone-chemistry", @@ -241,7 +242,6 @@ var/global/list/robot_modules = list( src.modules += N src.modules += B - ..() /obj/item/weapon/robot_module/medical/general/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules @@ -307,7 +307,6 @@ var/global/list/robot_modules = list( src.modules += B src.modules += S - ..() /obj/item/weapon/robot_module/medical/rescue/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules @@ -388,6 +387,7 @@ var/global/list/robot_modules = list( src.modules += RG /obj/item/weapon/robot_module/engineering/general/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/weapon/extinguisher(src) @@ -450,8 +450,6 @@ var/global/list/robot_modules = list( PL.synths = list(plasteel) src.modules += PL - ..() - /obj/item/weapon/robot_module/security name = "security robot module" channels = list("Security" = 1) @@ -477,6 +475,7 @@ var/global/list/robot_modules = list( supported_upgrades = list(/obj/item/robot_parts/robot_component/jetpack) /obj/item/weapon/robot_module/security/general/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/hud/sec(src) src.modules += new /obj/item/weapon/handcuffs/cyborg(src) @@ -485,7 +484,6 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/taperoll/police(src) src.modules += new /obj/item/device/holowarrant(src) src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src) - ..() /obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) ..() @@ -513,6 +511,7 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/janitor/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/soap/nanotrasen(src) src.modules += new /obj/item/weapon/storage/bag/trash(src) @@ -521,7 +520,6 @@ var/global/list/robot_modules = list( src.emag = new /obj/item/weapon/reagent_containers/spray(src) src.emag.reagents.add_reagent("lube", 250) src.emag.name = "Lube spray" - ..() /obj/item/weapon/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) ..() @@ -563,6 +561,7 @@ var/global/list/robot_modules = list( /obj/item/weapon/robot_module/clerical/butler/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/gripper/service(src) src.modules += new /obj/item/weapon/reagent_containers/glass/bucket(src) @@ -593,19 +592,18 @@ var/global/list/robot_modules = list( R.my_atom = src.emag R.add_reagent("beer2", 50) src.emag.name = "Mickey Finn's Special Brew" - ..() /obj/item/weapon/robot_module/clerical/general name = "clerical robot module" /obj/item/weapon/robot_module/clerical/general/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/pen/robopen(src) src.modules += new /obj/item/weapon/form_printer(src) src.modules += new /obj/item/weapon/gripper/paperwork(src) src.modules += new /obj/item/weapon/hand_labeler(src) src.emag = new /obj/item/weapon/stamp/denied(src) - ..() /obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) ..() @@ -632,6 +630,7 @@ var/global/list/robot_modules = list( supported_upgrades = list(/obj/item/robot_parts/robot_component/jetpack) /obj/item/weapon/robot_module/miner/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/material(src) src.modules += new /obj/item/weapon/wrench(src) @@ -657,6 +656,7 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/research/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) src.modules += new /obj/item/weapon/gripper/research(src) @@ -687,8 +687,6 @@ var/global/list/robot_modules = list( N.synths = list(nanite) src.modules += N - ..() - /obj/item/weapon/robot_module/syndicate name = "syndicate robot module" languages = list( @@ -733,6 +731,7 @@ var/global/list/robot_modules = list( supported_upgrades = list(/obj/item/robot_parts/robot_component/jetpack) /obj/item/weapon/robot_module/combat/New() + ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/hud/sec(src) src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) @@ -741,7 +740,6 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/borg/combat/mobility(src) src.modules += new /obj/item/weapon/crowbar(src) src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src) - ..() /obj/item/weapon/robot_module/drone name = "drone module" @@ -749,6 +747,7 @@ var/global/list/robot_modules = list( networks = list(NETWORK_ENGINEERING) /obj/item/weapon/robot_module/drone/New(var/mob/living/silicon/robot/robot) + ..() src.modules += new /obj/item/weapon/weldingtool(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/wrench(src) @@ -823,16 +822,14 @@ var/global/list/robot_modules = list( P.synths = list(plastic) src.modules += P - ..() - /obj/item/weapon/robot_module/drone/construction name = "construction drone module" channels = list("Engineering" = 1) languages = list() /obj/item/weapon/robot_module/drone/construction/New() - src.modules += new /obj/item/weapon/rcd/borg(src) ..() + src.modules += new /obj/item/weapon/rcd/borg(src) /obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/device/lightreplacer/LR = locate() in src.modules diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm index 163f1fc08db..60e05c41602 100644 --- a/code/modules/mob/living/simple_animal/constructs/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm @@ -35,6 +35,7 @@ mob_push_flags = ALLMOBS hunger_enabled = 0 var/list/construct_spells = list() + var/can_repair = 0 /mob/living/simple_animal/construct/cultify() return @@ -58,16 +59,19 @@ /mob/living/simple_animal/construct/attack_generic(var/mob/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(istype(user, /mob/living/simple_animal/construct/builder)) - if(getBruteLoss() > 0) - adjustBruteLoss(-5) - user.visible_message("\The [user] mends some of \the [src]'s wounds.") - else - if (health < maxHealth) - user << "Healing \the [src] any further is beyond your abilities." + if(istype(user, /mob/living/simple_animal/construct)) + var/mob/living/simple_animal/construct/C = user + if (C.can_repair) + if(getBruteLoss() > 0) + adjustBruteLoss(-5) + adjustFireLoss(-5) + user.visible_message("\The [user] mends some of \the [src]'s wounds.") else - user << "\The [src] is undamaged." - return + if (health < maxHealth) + user << "Healing \the [src] any further is beyond your abilities." + else + user << "\The [src] is undamaged." + return return ..() /mob/living/simple_animal/construct/examine(mob/user) @@ -188,6 +192,7 @@ speed = 0 environment_smash = 1 attack_sound = 'sound/weapons/rapidslice.ogg' + can_repair = 1 construct_spells = list(/spell/aoe_turf/conjure/construct/lesser, /spell/aoe_turf/conjure/wall, /spell/aoe_turf/conjure/floor, @@ -242,13 +247,19 @@ environment_smash = 1 see_in_dark = 7 attack_sound = 'sound/weapons/pierce.ogg' - + can_repair = 1 construct_spells = list( /spell/targeted/harvest, /spell/aoe_turf/knock/harvester, - /spell/rune_write + /spell/rune_write, + /spell/aoe_turf/conjure/construct/lesser, + /spell/aoe_turf/conjure/wall, + /spell/aoe_turf/conjure/floor, + /spell/aoe_turf/conjure/soulstone, + /spell/aoe_turf/conjure/pylon, + /spell/aoe_turf/conjure/forcewall/lesser ) - + //Harvesters are endgame stuff, no harm giving them construct spells ////////////////Glow////////////////// /mob/living/simple_animal/construct/proc/add_glow() diff --git a/code/modules/mob/living/simple_animal/familiars/familiars.dm b/code/modules/mob/living/simple_animal/familiars/familiars.dm index df29138c2f9..fbe9f9949e1 100644 --- a/code/modules/mob/living/simple_animal/familiars/familiars.dm +++ b/code/modules/mob/living/simple_animal/familiars/familiars.dm @@ -13,7 +13,7 @@ min_oxy = 1 //still require a /bit/ of air. max_co2 = 0 unsuitable_atoms_damage = 1 - + hunger_enabled = 0 supernatural = 1 @@ -21,7 +21,7 @@ /mob/living/simple_animal/familiar/New() ..() - add_language("Ceti Basic") + add_language(LANGUAGE_TCB) for(var/spell in wizardy_spells) src.add_spell(new spell, "const_spell_ready") @@ -104,26 +104,27 @@ /mob/living/simple_animal/familiar/goat name = "goat" - desc = "An elder looking goat." + desc = "A sprightly looking goat." icon_state = "goat" icon_living = "goat" icon_dead = "goat_dead" speak_emote = list("brays") attacktext = "kicked" - mob_size = MOB_SMALL + health = 80 + maxHealth = 80 - health = 50 - maxHealth = 50 + melee_damage_lower = 8 + melee_damage_upper = 12 + mob_size = 4.5 //weight based on Chanthangi goats + density = 0 + wizardy_spells = list(/spell/aoe_turf/smoke) - wizardy_spells = list(/spell/targeted/heal_target, - /spell/targeted/heal_target/area) /mob/living/simple_animal/familiar/pet //basically variants of normal animals with spells. icon = 'icons/mob/animal.dmi' - var/icon_rest //so that we can have resting little guys. /mob/living/simple_animal/familiar/pet/MouseDrop(atom/over_object) var/mob/living/carbon/H = over_object @@ -135,44 +136,8 @@ else return ..() -/mob/living/simple_animal/familiar/pet/Life() - ..() - if(!icon_rest) - return - if(stat == UNCONSCIOUS || resting) - icon_state = icon_rest -/mob/living/simple_animal/familiar/pet/mouse - name = "mouse" - desc = "A small rodent. It looks very old." - icon_state = "mouse_gray" - icon_living = "mouse_gray" - icon_dead = "mouse_gray_dead" - icon_rest = "mouse_gray_sleep" - speak_emote = list("squeeks") - holder_type = /obj/item/weapon/holder/mouse - pass_flags = PASSTABLE - mob_size = MOB_MINISCULE - - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_NOLIGHTING - - response_harm = "stamps on" - - health = 15 - maxHealth = 15 - melee_damage_lower = 1 - melee_damage_upper = 1 - attacktext = "nibbled" - - wizardy_spells = list(/spell/aoe_turf/smoke) - -/mob/living/simple_animal/familiar/pet/mouse/New() - ..() - - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide /mob/living/simple_animal/familiar/pet/cat name = "black cat" @@ -181,6 +146,7 @@ icon_living = "cat3" icon_dead = "cat3_dead" icon_rest = "cat3_rest" + can_nap = 1 see_in_dark = 8 see_invisible = SEE_INVISIBLE_NOLIGHTING @@ -189,10 +155,44 @@ holder_type = /obj/item/weapon/holder/cat mob_size = MOB_SMALL - health = 25 - maxHealth = 25 + health = 45 + maxHealth = 45 melee_damage_lower = 3 melee_damage_upper = 4 attacktext = "clawed" + density = 0 wizardy_spells = list(/spell/targeted/subjugation) + + +/mob/living/simple_animal/mouse/familiar + name = "ancient mouse" + desc = "A small rodent. It looks very old." + body_color = "gray" + + + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_NOLIGHTING + + + health = 25 + maxHealth = 25 + melee_damage_lower = 1 + melee_damage_upper = 1 + attacktext = "nibbled" + universal_speak = 1 + universal_understand = 1 + + min_oxy = 1 //still require a /bit/ of air. + max_co2 = 0 + unsuitable_atoms_damage = 1 + + supernatural = 1 + +/mob/living/simple_animal/mouse/familiar/New() + ..() + add_spell(new /spell/targeted/heal_target, "const_spell_ready") + add_spell(new /spell/targeted/heal_target/area, "const_spell_ready") + add_language(LANGUAGE_TCB) + name = initial(name) + desc = initial(desc) diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 22ec87fc34e..ff32edd1782 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -6,6 +6,8 @@ item_state = "cat2" icon_living = "cat2" icon_dead = "cat2_dead" + icon_rest = "cat2_rest" + can_nap = 1 speak = list("Meow!","Esp!","Purr!","HSSSSS") speak_emote = list("purrs", "meows") emote_hear = list("meows","mews") @@ -38,42 +40,43 @@ ..() - for(var/mob/living/simple_animal/mouse/snack in oview(src,7)) - if(snack.stat != DEAD && prob(65))//The probability allows her to not get stuck target the first mouse, reducing exploits - mousetarget = snack - movement_target = snack - foodtarget = 0//chasing mice takes precedence over eating food - if(prob(15)) - audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily.")) - break + if (!stat) + for(var/mob/living/simple_animal/mouse/snack in oview(src,7)) + if(snack.stat != DEAD && prob(65))//The probability allows her to not get stuck target the first mouse, reducing exploits + mousetarget = snack + movement_target = snack + foodtarget = 0//chasing mice takes precedence over eating food + if(prob(15)) + audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily.")) + break - if(!stat && !resting && !buckled) - if (turns_since_move > 5 || (flee_target || mousetarget)) + if(!buckled) + if (turns_since_move > 5 || (flee_target || mousetarget)) + walk_to(src,0) + turns_since_move = 0 + + if (flee_target) //fleeing takes precendence + handle_flee_target() + else + handle_movement_target() + + if (!movement_target) walk_to(src,0) - turns_since_move = 0 - if (flee_target) //fleeing takes precendence - handle_flee_target() - else - handle_movement_target() + spawn(2) + attack_mice() - if (!movement_target) - walk_to(src,0) - - spawn(2) - attack_mice() - - if(prob(2)) //spooky - var/mob/dead/observer/spook = locate() in range(src,5) - if(spook) - var/turf/T = spook.loc - var/list/visible = list() - for(var/obj/O in T.contents) - if(!O.invisibility && O.name) - visible += O - if(visible.len) - var/atom/A = pick(visible) - visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].") + if(prob(2)) //spooky + var/mob/dead/observer/spook = locate() in range(src,5) + if(spook) + var/turf/T = spook.loc + var/list/visible = list() + for(var/obj/O in T.contents) + if(!O.invisibility && O.name) + visible += O + if(visible.len) + var/atom/A = pick(visible) + visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].") /mob/living/simple_animal/cat/proc/handle_movement_target() //if our target is neither inside a turf or inside a human(???), stop @@ -240,6 +243,8 @@ item_state = "cat" icon_living = "cat" icon_dead = "cat_dead" + icon_rest = "cat_rest" + can_nap = 1 befriend_job = "Chief Medical Officer" holder_type = /obj/item/weapon/holder/cat/black @@ -254,6 +259,7 @@ item_state = "kitten" icon_living = "kitten" icon_dead = "kitten_dead" + can_nap = 0 //No resting sprite gender = NEUTER holder_type = /obj/item/weapon/holder/cat/kitten @@ -269,6 +275,8 @@ item_state = "cat3" icon_living = "cat3" icon_dead = "cat3_dead" + icon_rest = "cat3_rest" + can_nap = 1 var/friend_name = "Erstatz Vryroxes" holder_type = /obj/item/weapon/holder/cat/black diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index d7ca060dbb4..ca7bed3bd9b 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -179,6 +179,7 @@ beg_for_food = 0 density = 0 mob_size = 0.75//just a rough estimate, the real value should be way lower + hunger_enabled = FALSE /mob/living/simple_animal/chick/New() ..() @@ -227,6 +228,7 @@ var/global/chicken_count = 0 holder_type = /obj/item/weapon/holder/chicken density = 0 mob_size = 2 + hunger_enabled = FALSE /mob/living/simple_animal/chicken/New() ..() @@ -256,14 +258,17 @@ var/global/chicken_count = 0 var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O if(G.seed && G.seed.kitchen_tag == "wheat") if(!stat && eggsleft < 8) - user.visible_message("\blue [user] feeds [O] to [name]! It clucks happily.","\blue You feed [O] to [name]! It clucks happily.") + user.visible_message( + span("notice", "\The [user] feeds \the [O] to \the [name]! It clucks happily."), + span("notice", "You feed \the [O] to \the [name]! It clucks happily."), + "You hear a cluck.") user.drop_item() qdel(O) eggsleft += rand(1, 4) else - user << "\blue [name] doesn't seem hungry!" + user << "\The [name] doesn't seem hungry!" else - user << "[name] doesn't seem interested in that." + user << "\The [name] doesn't seem interested in that." else ..() diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 56d8efcbeb4..4b9b3bf0ae5 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -1,12 +1,15 @@ /mob/living/simple_animal/mouse name = "mouse" real_name = "mouse" - desc = "It's a small rodent." + desc = "It's a small rodent, often seen hiding in maintenance areas and making a nuisance of itself." + icon = 'icons/mob/mouse.dmi' icon_state = "mouse_gray" item_state = "mouse_gray" icon_living = "mouse_gray" icon_dead = "mouse_gray_dead" + icon_rest = "mouse_gray_sleep" + can_nap = 1 speak = list("Squeek!","SQUEEK!","Squeek?") speak_emote = list("squeeks","squeeks","squiks") emote_hear = list("squeeks","squeaks","squiks") @@ -53,6 +56,7 @@ kitchen_tag = "rodent" + /mob/living/simple_animal/mouse/Life() if(..()) @@ -73,25 +77,19 @@ squeals++ last_squealgain = world.time - if(!ckey && stat == CONSCIOUS && prob(0.5)) - stat = UNCONSCIOUS - icon_state = "mouse_[body_color]_sleep" - wander = 0 - speak_chance = 0 - //snuffles - else if(stat == UNCONSCIOUS) - if(ckey || prob(1)) - stat = CONSCIOUS - icon_state = "mouse_[body_color]" - wander = 1 - speak_chance = initial(speak_chance) - else if(prob(5)) - audible_emote("snuffles.") else if ((world.time - timeofdeath) > decompose_time) dust() - +//Pixel offsetting as they scamper around +/mob/living/simple_animal/mouse/Move() + if(..()) + if (prob(50)) + pixel_x += rand(-2,2) + pixel_x = Clamp(pixel_x, -10, 10) + else + pixel_y += rand(-2,2) + pixel_y = Clamp(pixel_y, -4, 14) /mob/living/simple_animal/mouse/New() ..() @@ -109,8 +107,8 @@ icon_state = "mouse_[body_color]" item_state = "mouse_[body_color]" icon_living = "mouse_[body_color]" + icon_rest = "mouse_[body_color]_sleep" icon_dead = "mouse_[body_color]_dead" - desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." if (body_color == "brown") holder_type = /obj/item/weapon/holder/mouse/brown if (body_color == "gray") @@ -144,17 +142,6 @@ if(client) client.time_died_as_mouse = world.time -/mob/living/simple_animal/mouse/MouseDrop(atom/over_object) - - var/mob/living/carbon/H = over_object - if(!istype(H) || !Adjacent(H)) return ..() - - if(H.a_intent == "help") - get_scooped(H, usr) - return - else - return ..() - //Plays a sound. @@ -170,7 +157,7 @@ //Plays a random selection of four sounds, at a low volume //This is triggered randomly periodically by any mouse, or manually /mob/living/simple_animal/mouse/proc/squeak_soft(var/manual = 1) - if (stat == CONSCIOUS) + if (stat != DEAD) //Soft squeaks are allowed while sleeping var/list/new_squeaks = last_softsqueak ? soft_squeaks - last_softsqueak : soft_squeaks var/sound = pick(new_squeaks) @@ -215,6 +202,7 @@ if(!stat) var/mob/M = AM M << "\blue \icon[src] Squeek!" + poke(1) //Wake up if stepped on if (prob(95)) squeak(0) else @@ -233,15 +221,9 @@ /mob/living/simple_animal/mouse/dust() ..(anim = "dust_[body_color]", remains = /obj/effect/decal/remains/mouse, iconfile = 'icons/mob/mouse.dmi') -/mob/living/simple_animal/mouse/lay_down() - set name = "Rest" - set category = "IC" - resting = !resting - icon_state = resting ? "mouse_[body_color]_sleep" : "mouse_[body_color]" - src << "\blue You are now [resting ? "resting" : "getting up"]" - canmove = !resting + /* @@ -251,16 +233,19 @@ /mob/living/simple_animal/mouse/white body_color = "white" icon_state = "mouse_white" + icon_rest = "mouse_white_sleep" holder_type = /obj/item/weapon/holder/mouse/white /mob/living/simple_animal/mouse/gray body_color = "gray" icon_state = "mouse_gray" + icon_rest = "mouse_gray_sleep" holder_type = /obj/item/weapon/holder/mouse/gray /mob/living/simple_animal/mouse/brown body_color = "brown" icon_state = "mouse_brown" + icon_rest = "mouse_brown_sleep" holder_type = /obj/item/weapon/holder/mouse/brown //TOM IS ALIVE! SQUEEEEEEEE~K :) diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index c2063c02630..2ffd9112c0d 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -439,9 +439,8 @@ spark_system = bind_spark(src, 5) /mob/living/simple_animal/hostile/bear/spatial/Destroy() - if (spark_system) - qdel(spark_system) - ..() + QDEL_NULL(spark_system) + return ..() //Called when we want to bypass ticks and attack immediately. For example in response to being shot //This calls several procs and some duplicated code from the parent class to immediately put us in an assault state and lash out diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index 043b912a588..dbacbd9ca34 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -151,7 +151,7 @@ if(busy == LAYING_EGGS) E = locate() in get_turf(src) if(!E) - getFromPool(/obj/effect/spider/eggcluster, list(loc, src)) + getFromPool(/obj/effect/spider/eggcluster, loc, src) fed-- busy = 0 stop_automated_movement = 0 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 33178935f43..092b9e01f59 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -96,6 +96,10 @@ var/kitchen_tag = "animal" //Used for cooking with animals + //Napping + var/can_nap = 0 + var/icon_rest = null + /mob/living/simple_animal/proc/beg(var/atom/thing, var/atom/holder) visible_emote("gazes longingly at [holder]'s [thing]") @@ -115,6 +119,9 @@ reagents = new/datum/reagents(20, src) nutrition = max_nutrition + if (can_nap) + verbs += /mob/living/simple_animal/lay_down + /mob/living/simple_animal/Move(NewLoc, direct) . = ..() if(.) @@ -142,6 +149,8 @@ user << "It looks hungry." else if ((reagents.total_volume > 0 && nutrition > max_nutrition *0.75) || nutrition > max_nutrition *0.9) user << "It looks full and contented." + if (stat == DEAD) + user << "It looks dead." if (health < maxHealth * 0.5) user << "It looks badly wounded." else if (health < maxHealth) @@ -169,51 +178,58 @@ handle_foodscanning() //Movement turns_since_move++ - if(!client && !stop_automated_movement && wander && !anchored) - if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc. + if (!client) + if(!stop_automated_movement && wander && !anchored) + if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc. - if(turns_since_move >= turns_per_move) - if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled - var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND - moving_to = pick(cardinal) - dir = moving_to //How about we turn them the direction they are moving, yay. - Move(get_step(src,moving_to)) - turns_since_move = 0 + if(turns_since_move >= turns_per_move) + if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled + var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND + moving_to = pick(cardinal) + dir = moving_to //How about we turn them the direction they are moving, yay. + Move(get_step(src,moving_to)) + turns_since_move = 0 - //Speaking - if(!client && speak_chance) - if(rand(0,200) < speak_chance) - if(speak && speak.len) - if((emote_hear && emote_hear.len) || (emote_see && emote_see.len)) - var/length = speak.len - if(emote_hear && emote_hear.len) - length += emote_hear.len - if(emote_see && emote_see.len) - length += emote_see.len - var/randomValue = rand(1,length) - if(randomValue <= speak.len) - say(pick(speak)) + //Speaking + if(speak_chance) + if(rand(0,200) < speak_chance) + if(speak && speak.len) + if((emote_hear && emote_hear.len) || (emote_see && emote_see.len)) + var/length = speak.len + if(emote_hear && emote_hear.len) + length += emote_hear.len + if(emote_see && emote_see.len) + length += emote_see.len + var/randomValue = rand(1,length) + if(randomValue <= speak.len) + say(pick(speak)) + else + randomValue -= speak.len + if(emote_see && randomValue <= emote_see.len) + visible_emote("[pick(emote_see)].") + else + audible_emote("[pick(emote_hear)].") else - randomValue -= speak.len - if(emote_see && randomValue <= emote_see.len) + say(pick(speak)) + else + if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len)) + visible_emote("[pick(emote_see)].") + if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len)) + audible_emote("[pick(emote_hear)].") + if((emote_hear && emote_hear.len) && (emote_see && emote_see.len)) + var/length = emote_hear.len + emote_see.len + var/pick = rand(1,length) + if(pick <= emote_see.len) visible_emote("[pick(emote_see)].") else audible_emote("[pick(emote_hear)].") - else - say(pick(speak)) - else - if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len)) - visible_emote("[pick(emote_see)].") - if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len)) - audible_emote("[pick(emote_hear)].") - if((emote_hear && emote_hear.len) && (emote_see && emote_see.len)) - var/length = emote_hear.len + emote_see.len - var/pick = rand(1,length) - if(pick <= emote_see.len) - visible_emote("[pick(emote_see)].") - else - audible_emote("[pick(emote_hear)].") - speak_audio() + speak_audio() + + if (can_nap) + if (!resting && prob(1)) + fall_asleep() + else if (resting && prob(0.5)) + wake_up() //Atmos @@ -346,16 +362,17 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) /mob/living/simple_animal/attack_hand(mob/living/carbon/human/M as mob) ..() - switch(M.a_intent) if(I_HELP) if (health > 0) M.visible_message("\blue [M] [response_help] \the [src]") + poke() if(I_DISARM) M.visible_message("\blue [M] [response_disarm] \the [src]") M.do_attack_animation(src) + poke(1) //TODO: Push the mob away or something if(I_GRAB) @@ -377,17 +394,20 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) M.visible_message("\red [M] has grabbed [src] passively!") M.do_attack_animation(src) + poke(1) if(I_HURT) apply_damage(harm_intent_damage, BRUTE, used_weapon = "Attack by [M.name]") M.visible_message("\red [M] [response_harm] \the [src]") M.do_attack_animation(src) + poke(1) return /mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user) if(istype(O, /obj/item/weapon/reagent_containers) || istype(O, /obj/item/stack/medical) || istype(O,/obj/item/weapon/gripper/)) ..() + poke() else if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/kitchen/utensil/knife )) @@ -400,6 +420,7 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!O.force) visible_message("[user] gently taps [src] with \the [O].") + poke() return 0 if(O.force > resistance) @@ -411,8 +432,10 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) purge = 3 apply_damage(damage, O.damtype, used_weapon = "[O.name]") + poke(1) else usr << "This weapon is ineffective, it does no damage." + poke() visible_message("\The [src] has been attacked with the [O] by [user].") user.do_attack_animation(src) @@ -437,6 +460,7 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) if(statpanel("Status") && show_stat_health) stat(null, "Health: [round((health / maxHealth) * 100)]%") + stat(null, "Nutrition: [nutrition]/[max_nutrition]%") /mob/living/simple_animal/updatehealth() ..() @@ -583,7 +607,7 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) UnarmedAttack(movement_target) if (get_turf(movement_target) == src.loc) set_dir(pick(1,2,4,8,1,1))//Face a random direction when eating, but mostly upwards - else if(ishuman(movement_target.loc) && Adjacent(src, get_turf(movement_target)) && prob(15)) + else if(ishuman(movement_target.loc) && Adjacent(src, get_turf(movement_target)) && prob(10)) beg(movement_target, movement_target.loc) else scan_interval = max(min_scan_interval, min(scan_interval+1, max_scan_interval))//If nothing is happening, ian's scanning frequency slows down to save processing @@ -609,3 +633,55 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) return /mob/living/simple_animal/ExtinguishMob() return + + + +//I wanted to call this proc alert but it already exists. +//Basically makes the mob pay attention to the world, resets sleep timers, awakens it from a sleeping state sometimes +/mob/living/simple_animal/proc/poke(var/force_wake = 0) + if (stat != DEAD) + scan_interval = min_scan_interval + if (force_wake || (!client && prob(30))) + wake_up() + +//Puts the mob to sleep +/mob/living/simple_animal/proc/fall_asleep() + if (stat != DEAD) + resting = 1 + stat = UNCONSCIOUS + canmove = 0 + wander = 0 + walk_to(src,0) + movement_target = null + foodtarget = 0 + update_icons() + +//Wakes the mob up from sleeping +/mob/living/simple_animal/proc/wake_up() + if (stat != DEAD) + stat = CONSCIOUS + resting = 0 + canmove = 1 + wander = 1 + update_icons() + +/mob/living/simple_animal/update_icons() + if (stat == DEAD) + icon_state = icon_dead + else if ((stat == UNCONSCIOUS || resting) && icon_rest) + icon_state = icon_rest + else if (icon_living) + icon_state = icon_living + +/mob/living/simple_animal/lay_down() + set name = "Rest" + set category = "Abilities" + + if (resting) + wake_up() + else + fall_asleep() + + src << span("notice","You are now [resting ? "resting" : "getting up"]") + + update_icons() diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index c11c6a69485..12f92976f0a 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -1,4 +1,5 @@ /obj/item/modular_computer/process() + handle_power() // Handles all computer power interaction if(!enabled) // The computer is turned off last_power_usage = 0 return 0 @@ -30,7 +31,7 @@ else idle_threads.Remove(P) - handle_power() // Handles all computer power interaction + check_update_ui_need() /obj/item/modular_computer/proc/get_preset_programs(var/app_preset_name) @@ -75,7 +76,7 @@ return NO_EMAG_ACT else computer_emagged = 1 - to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") + to_chat(user, "You emag \the [src]. Its screen briefly displays a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") return 1 /obj/item/modular_computer/update_icon() @@ -85,7 +86,10 @@ if(!enabled) var/probably_working = hard_drive && processor_unit && damage < broken_damage && (apc_power(0) || battery_power(0)) if(icon_state_screensaver && probably_working) - overlays.Add(icon_state_screensaver) + if (is_holographic) + holographic_overlay(src, src.icon, icon_state_screensaver) + else + overlays += image(icon_state_screensaver) if (screensaver_light_range && probably_working) set_light(screensaver_light_range, 1, screensaver_light_color ? screensaver_light_color : "#FFFFFF") @@ -93,10 +97,17 @@ set_light(0) return if(active_program) - overlays.Add(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu) + var/state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu + if (is_holographic) + holographic_overlay(src, src.icon, state) + else + overlays += image(state) set_light(light_strength, l_color = active_program.color) else - overlays.Add(icon_state_menu) + if (is_holographic) + holographic_overlay(src, src.icon, icon_state_menu) + else + overlays += image(icon_state_menu) set_light(light_strength, l_color = menu_light_color) /obj/item/modular_computer/proc/turn_on(var/mob/user) diff --git a/code/modules/modular_computers/computers/modular_computer/power.dm b/code/modules/modular_computers/computers/modular_computer/power.dm index 48871619fab..db5db333e16 100644 --- a/code/modules/modular_computers/computers/modular_computer/power.dm +++ b/code/modules/modular_computers/computers/modular_computer/power.dm @@ -7,6 +7,9 @@ PRG.event_powerfailure(1) shutdown_computer(0) + power_has_failed = TRUE + update_icon() + // Tries to use power from battery. Passing 0 as parameter results in this proc returning whether battery is functional or not. /obj/item/modular_computer/proc/battery_power(var/power_usage = 0) apc_powered = FALSE @@ -38,14 +41,21 @@ // Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged /obj/item/modular_computer/proc/handle_power() var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage - for(var/obj/item/weapon/computer_hardware/H in get_all_components()) - if(H.enabled) - power_usage += H.power_usage - last_power_usage = power_usage + if (enabled) + for(var/obj/item/weapon/computer_hardware/H in get_all_components()) + if(H.enabled) + power_usage += H.power_usage + last_power_usage = power_usage // First tries to charge from an APC, if APC is unavailable switches to battery power. If neither works the computer fails. if(apc_power(power_usage)) + if (power_has_failed) + power_has_failed = FALSE + update_icon() return if(battery_power(power_usage)) + if (power_has_failed) + power_has_failed = FALSE + update_icon() return - power_failure() \ No newline at end of file + power_failure() diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm index cf8836f089a..40f8c386d84 100644 --- a/code/modules/modular_computers/computers/modular_computer/variables.dm +++ b/code/modules/modular_computers/computers/modular_computer/variables.dm @@ -35,6 +35,8 @@ var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer. var/light_strength = 0 // Intensity of light this computer emits. Comparable to numbers light fixtures use. var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with. + var/power_has_failed = FALSE + var/is_holographic = FALSE // Damage of the chassis. If the chassis takes too much damage it will break apart. var/damage = 0 // Current damage level diff --git a/code/modules/modular_computers/computers/subtypes/dev_console.dm b/code/modules/modular_computers/computers/subtypes/dev_console.dm index 7780ba21a2f..0fe95cc5dfd 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_console.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_console.dm @@ -19,3 +19,4 @@ broken_damage = 150 screensaver_light_range = 1.4 screensaver_light_color = "#0099ff" + is_holographic = TRUE diff --git a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm index 3df8b0e0d27..1fb08ea1cb3 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm @@ -16,6 +16,7 @@ max_damage = 300 broken_damage = 150 w_class = 5 + is_holographic = TRUE /obj/item/modular_computer/telescreen/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) if(istype(W, /obj/item/weapon/crowbar)) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 750cd99080b..c0db16020eb 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -28,6 +28,7 @@ var/list/organ_cache = list() var/emp_coeff = 1 //coefficient for damages taken by EMP, if the organ is robotic. /obj/item/organ/Destroy() + processing_objects -= src if(!owner) return ..() @@ -44,6 +45,9 @@ var/list/organ_cache = list() if(src in owner.contents) owner.contents -= src + owner = null + QDEL_NULL(dna) + return ..() /obj/item/organ/proc/update_health() diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm deleted file mode 100644 index a248455e16f..00000000000 --- a/code/modules/organs/organ_alien.dm +++ /dev/null @@ -1,431 +0,0 @@ -/proc/spawn_diona_nymph_from_organ(var/obj/item/organ/organ) - if(!istype(organ)) - return 0 - - //This is a terrible hack and I should be ashamed. - var/datum/seed/diona = plant_controller.seeds["diona"] - if(!diona) - return 0 - - spawn(1) // So it has time to be thrown about by the gib() proc. - var/mob/living/carbon/alien/diona/D = new(get_turf(organ)) - diona.request_player(D) - spawn(60) - if(D) - if(!D.ckey || !D.client) - D.death() - return 1 - -/obj/item/organ/external/diona - name = "tendril" - cannot_break = 1 - amputation_point = "branch" - joint = "structural ligament" - dislocated = -1 - status = ORGAN_PLANT - - - -/obj/item/organ/external/diona/chest - name = "core trunk" - limb_name = "chest" - icon_name = "torso" - health = 200 - min_broken_damage = 50 - body_part = UPPER_TORSO - vital = 1 - cannot_amputate = 1 - parent_organ = null - -/obj/item/organ/external/diona/groin - name = "fork" - limb_name = "groin" - icon_name = "groin" - health = 100 - min_broken_damage = 50 - body_part = LOWER_TORSO - parent_organ = "chest" - -/obj/item/organ/external/diona/arm - name = "left upper tendril" - limb_name = "l_arm" - icon_name = "l_arm" - health = 35 - min_broken_damage = 20 - body_part = ARM_LEFT - parent_organ = "chest" - can_grasp = 1 - -/obj/item/organ/external/diona/arm/right - name = "right upper tendril" - limb_name = "r_arm" - icon_name = "r_arm" - body_part = ARM_RIGHT - -/obj/item/organ/external/diona/leg - name = "left lower tendril" - limb_name = "l_leg" - icon_name = "l_leg" - health = 35 - min_broken_damage = 20 - body_part = LEG_LEFT - icon_position = LEFT - parent_organ = "groin" - can_stand = 1 - -/obj/item/organ/external/diona/leg/right - name = "right lower tendril" - limb_name = "r_leg" - icon_name = "r_leg" - body_part = LEG_RIGHT - icon_position = RIGHT - -/obj/item/organ/external/diona/foot - name = "left foot" - limb_name = "l_foot" - icon_name = "l_foot" - health = 20 - min_broken_damage = 10 - body_part = FOOT_LEFT - icon_position = LEFT - parent_organ = "l_leg" - can_stand = 1 - -/obj/item/organ/external/diona/foot/right - name = "right foot" - limb_name = "r_foot" - icon_name = "r_foot" - body_part = FOOT_RIGHT - icon_position = RIGHT - parent_organ = "r_leg" - joint = "right ankle" - amputation_point = "right ankle" - -/obj/item/organ/external/diona/hand - name = "left grasper" - limb_name = "l_hand" - icon_name = "l_hand" - health = 30 - min_broken_damage = 15 - body_part = HAND_LEFT - parent_organ = "l_arm" - can_grasp = 1 - -/obj/item/organ/external/diona/hand/right - name = "right grasper" - limb_name = "r_hand" - icon_name = "r_hand" - body_part = HAND_RIGHT - parent_organ = "r_arm" - -/obj/item/organ/external/diona/head - limb_name = "head" - icon_name = "head" - name = "head" - health = 50 - min_broken_damage = 25 - body_part = HEAD - parent_organ = "chest" - -/obj/item/organ/external/diona/head/removed() - if(owner) - owner.u_equip(owner.head) - owner.u_equip(owner.l_ear) - ..() - -//DIONA ORGANS. -/obj/item/organ/external/diona/removed() - var/mob/living/carbon/human/H = owner - ..() - if(!istype(H) || !H.organs || !H.organs.len) - H.death()//if you somehow remove all of a gestalt's organs, it will dissolve into nymphs - - if (H.is_diona()) - spawn(1) - H.update_dionastats()//This ensures that the dionastats registers the removal of an organ - -/obj/item/organ/diona/process() - - if(loc != owner) - owner = null - - //Set/remove bad organ status, only every 10 ticks to reduce processing - //Unfortunately internal organs aren't a special subclass so this runs on every organ - if (owner && owner.life_tick % 10 == 0) - internal_set_bad() - - germ_level = 0//Diona don't get infections or organ decay - - -/obj/item/organ/diona/strata - name = "neural strata" - parent_organ = "chest" - organ_tag = "neural strata" - -/obj/item/organ/diona/bladder - name = "gas bladder" - parent_organ = "head" - organ_tag = "gas bladder" - -/obj/item/organ/diona/polyp - name = "polyp segment" - parent_organ = "groin" - organ_tag = "polyp segment" - -/obj/item/organ/diona/ligament - name = "anchoring ligament" - parent_organ = "groin" - organ_tag = "anchoring ligament" - -/obj/item/organ/diona - name = "diona nymph" - icon = 'icons/obj/objects.dmi' - icon_state = "nymph" - organ_tag = "special" // Turns into a nymph instantly, no transplanting possible. - -/obj/item/organ/diona/removed(var/mob/living/user) - var/mob/living/carbon/human/H = owner - ..() - if(!istype(H) || !H.organs || !H.organs.len) - H.death() - -/obj/item/organ/diona/removed() - var/mob/living/carbon/human/H = owner - ..() - if(!istype(H) || !H.organs || !H.organs.len) - H.death()//if you somehow remove all of a gestalt's organs, it will dissolve into nymphs - - if (H.is_diona()) - spawn(1) - H.update_dionastats()//This ensures that the dionastats registers the removal of an organ - - -// These are different to the standard diona organs as they have a purpose in other -// species (absorbing radiation and light respectively) -/obj/item/organ/diona/nutrients - name = "nutrient channel" - parent_organ = "chest" - organ_tag = "nutrient channel" - icon = 'icons/mob/alien.dmi' - icon_state = "claw" - -/obj/item/organ/diona/node - name = "response node" - parent_organ = "head" - organ_tag = "response node" - icon = 'icons/mob/alien.dmi' - icon_state = "claw" - - -//CORTICAL BORER ORGANS. -/obj/item/organ/borer - name = "cortical borer" - parent_organ = "head" - vital = 1 - -/obj/item/organ/borer/process() - - // Borer husks regenerate health, feel no pain, and are resistant to stuns and brainloss. - for(var/chem in list("tricordrazine","tramadol","hyperzine","alkysine")) - if(owner.reagents.get_reagent_amount(chem) < 3) - owner.reagents.add_reagent(chem, 5) - - // They're also super gross and ooze ichor. - if(prob(5)) - var/mob/living/carbon/human/H = owner - if(!istype(H)) - return - - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in H.vessel.reagent_list - blood_splatter(H,B,1) - var/obj/effect/decal/cleanable/blood/splatter/goo = locate() in get_turf(owner) - if(goo) - goo.name = "husk ichor" - goo.desc = "It's thick and stinks of decay." - goo.basecolor = "#412464" - goo.update_icon() - -/obj/item/organ/borer - name = "cortical borer" - icon = 'icons/obj/objects.dmi' - icon_state = "borer" - organ_tag = "brain" - desc = "A disgusting space slug." - -/obj/item/organ/borer/removed(var/mob/living/user) - - ..() - - var/mob/living/simple_animal/borer/B = owner.has_brain_worms() - if(B) - B.leave_host() - B.ckey = owner.ckey - - spawn(0) - qdel(src) - -//XENOMORPH ORGANS -/obj/item/organ/xenos/eggsac - name = "egg sac" - parent_organ = "groin" - -/obj/item/organ/xenos/plasmavessel - name = "plasma vessel" - parent_organ = "chest" - var/stored_plasma = 0 - var/max_plasma = 500 - -/obj/item/organ/xenos/plasmavessel/queen - name = "bloated plasma vessel" - stored_plasma = 200 - max_plasma = 500 - -/obj/item/organ/xenos/plasmavessel/sentinel - stored_plasma = 100 - max_plasma = 250 - -/obj/item/organ/xenos/plasmavessel/hunter - name = "tiny plasma vessel" - stored_plasma = 100 - max_plasma = 150 - -/obj/item/organ/xenos/acidgland - name = "acid gland" - parent_organ = "head" - -/obj/item/organ/xenos/hivenode - name = "hive node" - parent_organ = "chest" - -/obj/item/organ/xenos/resinspinner - name = "resin spinner" - parent_organ = "head" - -/obj/item/organ/xenos - name = "xeno organ" - icon = 'icons/effects/blood.dmi' - desc = "It smells like an accident in a chemical factory." - -/obj/item/organ/xenos/eggsac - name = "egg sac" - icon_state = "xgibmid1" - organ_tag = "egg sac" - -/obj/item/organ/xenos/plasmavessel - name = "plasma vessel" - icon_state = "xgibdown1" - organ_tag = "plasma vessel" - -/obj/item/organ/xenos/acidgland - name = "acid gland" - icon_state = "xgibtorso" - organ_tag = "acid gland" - -/obj/item/organ/xenos/hivenode - name = "hive node" - icon_state = "xgibmid2" - organ_tag = "hive node" - -/obj/item/organ/xenos/resinspinner - name = "hive node" - icon_state = "xgibmid2" - organ_tag = "resin spinner" - -//VOX ORGANS. -/obj/item/organ/stack - name = "cortical stack" - parent_organ = "head" - robotic = 2 - vital = 1 - var/backup_time = 0 - var/datum/mind/backup - -/obj/item/organ/stack/process() - if(owner && owner.stat != 2 && !is_broken()) - backup_time = world.time - if(owner.mind) backup = owner.mind - -/obj/item/organ/stack/vox - -/obj/item/organ/stack/vox/stack - -/obj/item/organ/stack - name = "cortical stack" - icon_state = "brain-prosthetic" - organ_tag = "stack" - robotic = 2 - -/obj/item/organ/stack/vox - name = "vox cortical stack" - -// Slime limbs. -/obj/item/organ/external/chest/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/groin/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/arm/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/arm/right/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/leg/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/leg/right/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/foot/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/foot/right/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/hand/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/hand/right/slime - cannot_break = 1 - dislocated = -1 - -/obj/item/organ/external/head/slime - cannot_break = 1 - dislocated = -1 - -/*//VAURCA ORGANS -/obj/item/organ/vaurca/neuralsocket - name = "neural socket" - organ_tag = "neural socket" - icon = 'icons/mob/alien.dmi' - icon_state = "neural_socket" - -/obj/item/organ/vaurca/neuralsocket/removed() - return - -/obj/item/organ/vaurca/breathingapparatus - name = "breathing apparatus" - organ_tag = "breathing apparatus" - icon = 'icons/mob/alien.dmi' - icon_state = "breathing_app" - -/obj/item/organ/vaurca/breathingapparatus/removed() - return - -/obj/item/organ/vaurca/tracheae - name = "tracheae" - organ_tag = "tracheae" - icon = 'icons/mob/alien.dmi' - icon_state = "tracheae" -/obj/item/organ/vaurca/tracheae/removed() - return */ diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 0564b37e479..50ffd360d96 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -433,7 +433,7 @@ obj/item/organ/vaurca/neuralsocket/process() return null var/tank_pressure = air_contents.return_pressure() - if(tank_pressure < distribute_pressure) + if((tank_pressure < distribute_pressure) && prob(5)) owner << "There is a buzzing in your [parent_organ]." var/moles_needed = distribute_pressure*volume_to_return/(R_IDEAL_GAS_EQUATION*air_contents.temperature) diff --git a/code/modules/organs/subtypes/diona.dm b/code/modules/organs/subtypes/diona.dm index 61652aafd44..6b9b7975c9c 100644 --- a/code/modules/organs/subtypes/diona.dm +++ b/code/modules/organs/subtypes/diona.dm @@ -17,14 +17,17 @@ D.death() return 1 + +//Probable future TODO: Refactor diona organs to be /obj/item/organ/external/bodypart/diona +//Having them not inherit from specific bodypart classes is a problem + /obj/item/organ/external/diona name = "tendril" cannot_break = 1 - amputation_point = "branch" - joint = "structural ligament" - dislocated = -1 -/obj/item/organ/external/diona/chest + + +/obj/item/organ/external/chest/diona name = "core trunk" limb_name = "chest" icon_name = "torso" @@ -35,8 +38,12 @@ vital = 1 cannot_amputate = 1 parent_organ = null - -/obj/item/organ/external/diona/groin + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" +//------ +/obj/item/organ/external/groin/diona name = "fork" limb_name = "groin" icon_name = "groin" @@ -45,8 +52,12 @@ w_class = 4 body_part = LOWER_TORSO parent_organ = "chest" + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/arm +/obj/item/organ/external/arm/diona name = "left upper tendril" limb_name = "l_arm" icon_name = "l_arm" @@ -56,14 +67,22 @@ body_part = ARM_LEFT parent_organ = "chest" can_grasp = 1 + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/arm/right +/obj/item/organ/external/arm/right/diona name = "right upper tendril" limb_name = "r_arm" icon_name = "r_arm" body_part = ARM_RIGHT + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/leg +/obj/item/organ/external/leg/diona name = "left lower tendril" limb_name = "l_leg" icon_name = "l_leg" @@ -74,15 +93,23 @@ icon_position = LEFT parent_organ = "groin" can_stand = 1 + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/leg/right +/obj/item/organ/external/leg/right/diona name = "right lower tendril" limb_name = "r_leg" icon_name = "r_leg" body_part = LEG_RIGHT icon_position = RIGHT + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/foot +/obj/item/organ/external/foot/diona name = "left foot" limb_name = "l_foot" icon_name = "l_foot" @@ -93,8 +120,12 @@ icon_position = LEFT parent_organ = "l_leg" can_stand = 1 + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/foot/right +/obj/item/organ/external/foot/right/diona name = "right foot" limb_name = "r_foot" icon_name = "r_foot" @@ -103,8 +134,12 @@ parent_organ = "r_leg" joint = "right ankle" amputation_point = "right ankle" + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/hand +/obj/item/organ/external/hand/diona name = "left grasper" limb_name = "l_hand" icon_name = "l_hand" @@ -114,15 +149,23 @@ body_part = HAND_LEFT parent_organ = "l_arm" can_grasp = 1 + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/hand/right +/obj/item/organ/external/hand/right/diona name = "right grasper" limb_name = "r_hand" icon_name = "r_hand" body_part = HAND_RIGHT parent_organ = "r_arm" + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/head +/obj/item/organ/external/head/diona limb_name = "head" icon_name = "head" name = "head" @@ -131,21 +174,12 @@ w_class = 3 body_part = HEAD parent_organ = "chest" + cannot_break = 1 + dislocated = -1 + joint = "structural ligament" + amputation_point = "branch" -/obj/item/organ/external/diona/head/removed() - if(owner) - owner.u_equip(owner.head) - owner.u_equip(owner.l_ear) - ..() -//DIONA ORGANS. -/obj/item/organ/external/diona/removed() - var/mob/living/carbon/human/H = owner - ..() - if(!istype(H) || !H.organs || !H.organs.len) - H.death() - if(prob(50) && spawn_diona_nymph(get_turf(src))) - qdel(src) /obj/item/organ/diona/process() return @@ -154,7 +188,7 @@ name = "neural strata" parent_organ = "chest" organ_tag = "neural strata" - + /obj/item/organ/diona/bladder name = "gas bladder" diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index eba0e9df844..14b72bc778e 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -111,7 +111,7 @@ * Parapens */ /obj/item/weapon/pen/reagent/paralysis - origin_tech = "materials=2;syndicate=5" + origin_tech = list(TECH_MATERIAL = 2, TECH_ILLEGAL = 5) /obj/item/weapon/pen/reagent/paralysis/New() ..() diff --git a/code/modules/power/antimatter/computer.dm b/code/modules/power/antimatter/computer.dm index d531ccfb540..bbb9220f539 100644 --- a/code/modules/power/antimatter/computer.dm +++ b/code/modules/power/antimatter/computer.dm @@ -18,10 +18,10 @@ /obj/machinery/computer/am_engine/New() ..() spawn( 24 ) - for(var/obj/machinery/power/am_engine/engine/E in world) + for(var/obj/machinery/power/am_engine/engine/E in machines) if(E.engine_id == src.engine_id) src.connected_E = E - for(var/obj/machinery/power/am_engine/injector/I in world) + for(var/obj/machinery/power/am_engine/injector/I in machines) if(I.engine_id == src.engine_id) src.connected_I = I return @@ -45,7 +45,7 @@ src.state = STATE_DEFAULT if("login") var/mob/M = usr - var/obj/item/weapon/card/id/I = M.get_active_hand() + var/obj/item/weapon/card/id/I = M.equipped() if (I && istype(I)) if(src.check_access(I)) authenticated = 1 @@ -57,6 +57,7 @@ src.updateUsrDialog() /obj/machinery/computer/am_engine/attack_ai(var/mob/user as mob) + src.add_hiddenprint(user) return src.attack_hand(user) /obj/machinery/computer/am_engine/attack_paw(var/mob/user as mob) diff --git a/code/modules/power/antimatter/containment_jar.dm b/code/modules/power/antimatter/containment_jar.dm index dd0e503bd47..7c2c07b0022 100644 --- a/code/modules/power/antimatter/containment_jar.dm +++ b/code/modules/power/antimatter/containment_jar.dm @@ -1,6 +1,7 @@ /obj/item/weapon/am_containment name = "antimatter containment jar" - desc = "Holds antimatter." + desc = "Holds antimatter. Warranty void if exposed to matter." + description_antag = "Antimatter is extremely volatile, and containment jars are not particularly strong. Weak explosions will reduce the container's integrity, and larger ones will cause it to explode immediately." icon = 'icons/obj/machines/antimatter.dmi' icon_state = "jar" density = 0 @@ -10,24 +11,28 @@ throw_speed = 1 throw_range = 2 - var/fuel = 10000 - var/fuel_max = 10000//Lets try this for now + var/fuel = 1000 // WAS ORIGINALLY 10000 + var/fuel_max = 1000//Lets try this for now var/stability = 100//TODO: add all the stability things to this so its not very safe if you keep hitting in on things + var/exploded = 0 +/obj/item/weapon/am_containment/proc/boom() + var/percent = 0 + if(fuel) + percent = (fuel / fuel_max) * 100 + if(!exploded && percent >= 10) + explosion(get_turf(src), 1, 2, 3, 5)//Should likely be larger but this works fine for now I guess + exploded=1 + if(src) + qdel(src) /obj/item/weapon/am_containment/ex_act(severity) switch(severity) if(1.0) - explosion(get_turf(src), 1, 2, 3, 5)//Should likely be larger but this works fine for now I guess - if(src) - qdel(src) - return + boom() if(2.0) if(prob((fuel/10)-stability)) - explosion(get_turf(src), 1, 2, 3, 5) - if(src) - qdel(src) - return + boom() stability -= 40 if(3.0) stability -= 20 @@ -38,4 +43,4 @@ if(fuel < wanted) wanted = fuel fuel -= wanted - return wanted \ No newline at end of file + return wanted diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm index 8c7af58346e..2ed4d447265 100644 --- a/code/modules/power/antimatter/control.dm +++ b/code/modules/power/antimatter/control.dm @@ -1,9 +1,13 @@ /obj/machinery/power/am_control_unit name = "antimatter control unit" - desc = "This device injects antimatter into connected shielding units, the more antimatter injected the more power produced. Wrench the device to set it up." - icon = 'icons/obj/machines/antimatter.dmi' + desc = "The control unit for an antimatter reactor. Probably safe." + description_info = "Use a wrench to attach the control unit to the ground, then arrange the reactor sections nearby. Reactor sections can only be activated if they are near the control unit, but otherwise are not restricted in how they must be placed." + description_antag = "The antimatter engine will quickly destabilize if the fuel injection rate is set too high, causing a large explosion." + icon = 'icons/obj/machines/new_ame.dmi' icon_state = "control" - anchored = 1 + var/icon_mod = "on" // on, critical, or fuck + var/old_icon_mod = "on" + anchored = 0 density = 1 use_power = 1 idle_power_usage = 100 @@ -15,18 +19,19 @@ var/update_shield_icons = 0 var/stability = 100 var/exploding = 0 + var/exploded = 0 - var/active = 0//On or not - var/fuel_injection = 2//How much fuel to inject - var/shield_icon_delay = 0//delays resetting for a short time + var/active = 0 //On or not + var/fuel_injection = 2 //How much fuel to inject + var/shield_icon_delay = 0 //delays resetting for a short time var/reported_core_efficiency = 0 var/power_cycle = 0 - var/power_cycle_delay = 4//How many ticks till produce_power is called + var/power_cycle_delay = 4 //How many ticks till produce_power is called var/stored_core_stability = 0 var/stored_core_stability_delay = 0 - var/stored_power = 0//Power to deploy per tick + var/stored_power = 0 //Power to deploy per tick /obj/machinery/power/am_control_unit/New() @@ -34,17 +39,25 @@ linked_shielding = list() linked_cores = list() - -/obj/machinery/power/am_control_unit/Destroy()//Perhaps damage and run stability checks rather than just qdel on the others +/obj/machinery/power/am_control_unit/Destroy()//Perhaps damage and run stability checks rather than just del on the others for(var/obj/machinery/am_shielding/AMS in linked_shielding) + AMS.control_unit = null qdel(AMS) + for(var/obj/machinery/am_shielding/AMS in linked_cores) + AMS.control_unit = null + qdel(AMS) + qdel(fueljar) + fueljar = null ..() /obj/machinery/power/am_control_unit/process() - if(exploding) - explosion(get_turf(src),8,12,18,12) - if(src) qdel(src) + if(exploding && !exploded) + message_admins("AME explosion at ([x],[y],[z] - JMP) - Last touched by [fingerprintslast]",0,1) + exploded=1 + explosion(get_turf(src),8,10,12,15) + if(src) + qdel(src) if(update_shield_icons && !shield_icon_delay) check_shield_icons() @@ -58,6 +71,8 @@ //Angry buzz or such here return + check_core_stability() + add_avail(stored_power) power_cycle++ @@ -65,41 +80,43 @@ produce_power() power_cycle = 0 - return - - /obj/machinery/power/am_control_unit/proc/produce_power() - playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) - var/core_power = reported_core_efficiency//Effectively how much fuel we can safely deal with - if(core_power <= 0) return 0//Something is wrong + playsound(get_turf(src), 'sound/effects/bang.ogg', 25, 1) + for (var/thing in linked_cores) + flick("core2", thing) + var/core_power = reported_core_efficiency //Effectively how much fuel we can safely deal with + if(core_power <= 0) + return 0//Something is wrong var/core_damage = 0 var/fuel = fueljar.usefuel(fuel_injection) - stored_power = (fuel/core_power)*fuel*200000 + stored_power = (fuel / core_power) * fuel * AM_POWER_FACTOR // Was 200000, was too much. New value run past Aurx. - N3X //Now check if the cores could deal with it safely, this is done after so you can overload for more power if needed, still a bad idea - if(fuel > (2*core_power))//More fuel has been put in than the current cores can deal with - if(prob(50))core_damage = 1//Small chance of damage - if((fuel-core_power) > 5) core_damage = 5//Now its really starting to overload the cores - if((fuel-core_power) > 10) core_damage = 20//Welp now you did it, they wont stand much of this - if(core_damage == 0) return + if(fuel > (2*core_power)) //More fuel has been put in than the current cores can deal with + if(prob(50)) + core_damage = 1 //Small chance of damage + if((fuel-core_power) > 5) + core_damage = 5 //Now its really starting to overload the cores + if((fuel-core_power) > 10) + core_damage = 20 //Welp now you did it, they wont stand much of this + if(core_damage == 0) + return for(var/obj/machinery/am_shielding/AMS in linked_cores) AMS.stability -= core_damage AMS.check_stability(1) - playsound(src.loc, 'sound/effects/bang.ogg', 50, 1) - return - + playsound(get_turf(src), 'sound/effects/bang.ogg', 50, 1) /obj/machinery/power/am_control_unit/emp_act(severity) switch(severity) if(1) - if(active) toggle_power() + if(active) + toggle_power() stability -= rand(15,30) if(2) - if(active) toggle_power() + if(active) + toggle_power() stability -= rand(10,20) ..() - return 0 - /obj/machinery/power/am_control_unit/ex_act(severity) switch(severity) @@ -112,55 +129,50 @@ check_stability() return - -/obj/machinery/power/am_control_unit/bullet_act(var/obj/item/projectile/Proj) - if(Proj.check_armour != "bullet") - stability -= Proj.force - return 0 - - /obj/machinery/power/am_control_unit/power_change() ..() if(stat & NOPOWER && active) toggle_power() return - /obj/machinery/power/am_control_unit/update_icon() - if(active) icon_state = "control_on" - else icon_state = "control" + if(active) + icon_state = "control_[icon_mod]" + else + icon_state = "control" //No other icons for it atm - /obj/machinery/power/am_control_unit/attackby(obj/item/W, mob/user) - if(!istype(W) || !user) return - if(istype(W, /obj/item/weapon/wrench)) + if(!istype(W) || !user) + return + if(iswrench(W)) if(!anchored) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + playsound(get_turf(src), 'sound/items/Ratchet.ogg', 75, 1) user.visible_message("[user.name] secures the [src.name] to the floor.", \ "You secure the anchor bolts to the floor.", \ "You hear a ratchet") src.anchored = 1 + update_shield_icons = 2 + check_shield_icons() connect_to_network() else if(!linked_shielding.len > 0) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + playsound(get_turf(src), 'sound/items/Ratchet.ogg', 75, 1) user.visible_message("[user.name] unsecures the [src.name].", \ "You remove the anchor bolts.", \ "You hear a ratchet") src.anchored = 0 disconnect_from_network() else - user << "\red Once bolted and linked to a shielding unit it the [src.name] is unable to be moved!" + to_chat(user, "Once bolted and linked to a shielding unit it the [src.name] is unable to be moved!") return if(istype(W, /obj/item/weapon/am_containment)) if(fueljar) - user << "\red There is already a [fueljar] inside!" + to_chat(user, "There is already a [fueljar] inside!") return fueljar = W - user.remove_from_mob(W) - W.loc = src - user.update_icons() + user.drop_from_inventory(W, src) + message_admins("AME loaded with fuel by [user.real_name] ([user.key]) at ([x],[y],[z] - JMP)",0,1) user.visible_message("[user.name] loads an [W.name] into the [src.name].", \ "You load an [W.name].", \ "You hear a thunk.") @@ -180,19 +192,25 @@ /obj/machinery/power/am_control_unit/proc/add_shielding(var/obj/machinery/am_shielding/AMS, var/AMS_linking = 0) - if(!istype(AMS)) return 0 - if(!anchored) return 0 - if(!AMS_linking && !AMS.link_control(src)) return 0 - linked_shielding.Add(AMS) + if(!istype(AMS)) + return 0 + if(!anchored) + return 0 + if(!AMS_linking && !AMS.link_control(src)) + return 0 + if(!(AMS in linked_shielding)) + linked_shielding.Add(AMS) update_shield_icons = 1 return 1 /obj/machinery/power/am_control_unit/proc/remove_shielding(var/obj/machinery/am_shielding/AMS) - if(!istype(AMS)) return 0 + if(!istype(AMS)) + return 0 linked_shielding.Remove(AMS) update_shield_icons = 2 - if(active) toggle_power() + if(active) + toggle_power() return 1 @@ -210,40 +228,63 @@ else use_power = 1 visible_message("The [src.name] shuts down.") + for(var/obj/machinery/am_shielding/AMS in linked_cores) + AMS.update_icon() update_icon() return /obj/machinery/power/am_control_unit/proc/check_shield_icons()//Forces icon_update for all shields - if(shield_icon_delay) return + if(shield_icon_delay) + return shield_icon_delay = 1 if(update_shield_icons == 2)//2 means to clear everything and rebuild + for(var/obj/machinery/am_shielding/neighbor in cardinalrange(loc)) + if(!neighbor.control_unit) + linked_shielding += neighbor for(var/obj/machinery/am_shielding/AMS in linked_shielding) - if(AMS.processing) AMS.shutdown_core() + if(AMS.processing) + AMS.shutdown_core() AMS.control_unit = null spawn(10) AMS.controllerscan() + AMS.assimilate() linked_shielding = list() else for(var/obj/machinery/am_shielding/AMS in linked_shielding) AMS.update_icon() - spawn(20) - shield_icon_delay = 0 - return + sleep(20) + shield_icon_delay = 0 /obj/machinery/power/am_control_unit/proc/check_core_stability() - if(stored_core_stability_delay || linked_cores.len <= 0) return - stored_core_stability_delay = 1 + //if(stored_core_stability_delay || linked_cores.len <= 0) return + if(linked_cores.len <= 0) + return + //stored_core_stability_delay = 1 stored_core_stability = 0 - for(var/obj/machinery/am_shielding/AMS in linked_cores) - stored_core_stability += AMS.stability - stored_core_stability/=linked_cores.len - spawn(40) - stored_core_stability_delay = 0 - return + for(var/thing in linked_cores) + var/obj/machinery/am_shielding/AMS = thing + if (!AMS || AMS.gcDestroyed) + continue + stored_core_stability += AMS.stability + stored_core_stability /= linked_cores.len + switch(stored_core_stability) + if(0 to 24) + icon_mod = "fuck" + if(25 to 49) + icon_mod = "critical" + if(50 to INFINITY) + icon_mod = "on" + + if(icon_mod != old_icon_mod) + old_icon_mod = icon_mod + update_icon() + + //spawn(40) + // stored_core_stability_delay = 0 /obj/machinery/power/am_control_unit/interact(mob/user) if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER))) @@ -251,43 +292,56 @@ user.unset_machine() user << browse(null, "window=AMcontrol") return - user.set_machine(src) + return ui_interact(user) - var/dat = "" - dat += "AntiMatter Control Panel
" - dat += "Close
" - dat += "Refresh
" - dat += "Force Shielding Update

" - dat += "Status: [(active?"Injecting":"Standby")]
" - dat += "Toggle Status
" +/obj/machinery/power/am_control_unit/ui_interact(mob/user, ui_key = "main") + if(!user) + return - dat += "Instability: [stability]%
" - dat += "Reactor parts: [linked_shielding.len]
"//TODO: perhaps add some sort of stability check - dat += "Cores: [linked_cores.len]

" - dat += "-Current Efficiency: [reported_core_efficiency]
" - dat += "-Average Stability: [stored_core_stability] (update)
" - dat += "Last Produced: [stored_power]
" + var/list/fueljar_data=null + if(fueljar) + fueljar_data=list( + "fuel"=fueljar.fuel, + "fuel_max"=fueljar.fuel_max, + "injecting"=fuel_injection + ) - dat += "Fuel: " - if(!fueljar) - dat += "
No fuel receptacle detected." + var/list/data = list( + "active" = active, + //"stability" = stability, + "linked_shields" = linked_shielding.len, + "linked_cores" = linked_cores.len, + "efficiency" = reported_core_efficiency, + "stability" = stored_core_stability, + "stored_power" = stored_power, + "fueljar" = fueljar_data, + "siliconUser" = istype(user, /mob/living/silicon) + ) + + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key) + if (!ui) + // the ui does not exist, so we'll create a new one + ui = new(user, src, ui_key, "ame.tmpl", "Antimatter Control Unit", 500, data["siliconUser"] ? 465 : 390) + // When the UI is first opened this is the data it will use + ui.set_initial_data(data) + ui.open() + // Auto update every Master Controller tick + ui.set_auto_update(1) else - dat += "Eject
" - dat += "- [fueljar.fuel]/[fueljar.fuel_max] Units
" - - dat += "- Injecting: [fuel_injection] units
" - dat += "- --|++

" - - - user << browse(dat, "window=AMcontrol;size=420x500") - onclose(user, "AMcontrol") - return + // The UI is already open so push the new data to it + ui.push_data(data) + return /obj/machinery/power/am_control_unit/Topic(href, href_list) - ..() + if(..()) + return 1 + if(href_list["close"]) + if(usr.machine == src) + usr.unset_machine() + return 1 //Ignore input if we are broken or guy is not touching us, AI can control from a ways away - if(stat & (BROKEN|NOPOWER) || (get_dist(src, usr) > 1 && !istype(usr, /mob/living/silicon/ai))) + if(stat & (BROKEN|NOPOWER)) usr.unset_machine() usr << browse(null, "window=AMcontrol") return @@ -299,26 +353,34 @@ if(href_list["togglestatus"]) toggle_power() + message_admins("AME toggled [active?"on":"off"] by [usr.real_name] ([usr.key]) at ([x],[y],[z] - JMP)",0,1) + return 1 if(href_list["refreshicons"]) - update_shield_icons = 1 + update_shield_icons = 2 // Fuck it + return 1 if(href_list["ejectjar"]) if(fueljar) - fueljar.loc = src.loc + message_admins("AME fuel jar ejected by [usr.real_name] ([usr.key]) at ([x],[y],[z] - JMP)",0,1) + fueljar.forceMove(src.loc) fueljar = null //fueljar.control_unit = null currently it does not care where it is //update_icon() when we have the icon for it + return 1 - if(href_list["strengthup"]) - fuel_injection++ - - if(href_list["strengthdown"]) - fuel_injection-- - if(fuel_injection < 0) fuel_injection = 0 + if(href_list["set_strength"]) + var/newval = input("Enter new injection strength") as num|null + if(isnull(newval)) + return + fuel_injection=newval + fuel_injection=max(1,fuel_injection) + message_admins("AME injection strength set to [fuel_injection] by [usr.real_name] ([usr.key]) at ([x],[y],[z] - JMP)",0,1) + return 1 if(href_list["refreshstability"]) check_core_stability() + return 1 updateDialog() - return \ No newline at end of file + return 1 diff --git a/code/modules/power/antimatter/engine.dm b/code/modules/power/antimatter/engine.dm index a2d4a38ca04..a1ff0845c98 100644 --- a/code/modules/power/antimatter/engine.dm +++ b/code/modules/power/antimatter/engine.dm @@ -38,16 +38,18 @@ /obj/machinery/power/am_engine/injector/attackby(obj/item/weapon/fuel/F, mob/user) - if( (stat & BROKEN) || !connected) return + if( (stat & BROKEN) || !connected) + return if(istype(F, /obj/item/weapon/fuel/H)) if(injecting) - user << "Theres already a fuel rod in the injector!" + to_chat(user, "There's already a fuel rod in the injector!") return - user << "You insert the rod into the injector" + to_chat(user, "You insert the rod into the injector.") injecting = 1 var/fuel = F.fuel qdel(F) + F = null spawn( 300 ) injecting = 0 new/obj/item/weapon/fuel(src.loc) @@ -55,12 +57,13 @@ if(istype(F, /obj/item/weapon/fuel/antiH)) if(injecting) - user << "Theres already a fuel rod in the injector!" + to_chat(user, "There's already a fuel rod in the injector!") return - user << "You insert the rod into the injector" + to_chat(user, "You insert the rod into the injector.") injecting = 1 var/fuel = F.fuel qdel(F) + F = null spawn( 300 ) injecting = 0 new /obj/item/weapon/fuel(src.loc) @@ -83,6 +86,7 @@ /obj/machinery/power/am_engine/engine/proc/engine_go() + if( (!src.connected) || (stat & BROKEN) ) return @@ -109,7 +113,7 @@ antiH_fuel = residual_matter for(var/mob/M in hearers(src, null)) - M.show_message(text("\red You hear a loud bang!")) + M.show_message(text("You hear a loud bang!")) //Q = k x (delta T) @@ -123,6 +127,7 @@ /obj/machinery/power/am_engine/engine/proc/engine_process() + do if( (!src.connected) || (stat & BROKEN) ) return @@ -161,7 +166,7 @@ if(energy > convert2energy(8e-12)) //TOO MUCH ENERGY for(var/mob/M in hearers(src, null)) - M.show_message(text("\red You hear a loud whirring!")) + M.show_message(text("You hear a loud whirring!")) sleep(20) //Q = k x (delta T) @@ -180,7 +185,7 @@ if(energy > convert2energy(8e-12)) //FAR TOO MUCH ENERGY STILL for(var/mob/M in hearers(src, null)) - M.show_message(text("\red BANG!")) + M.show_message(text("BANG!")) new /obj/effect/bhole(src.loc) else //this amount of energy is okay so it does the proper output thing @@ -204,4 +209,4 @@ stopping = 0 - return \ No newline at end of file + return diff --git a/code/modules/power/antimatter/fuel.dm b/code/modules/power/antimatter/fuel.dm index 56098a0b56d..b700253c5cf 100644 --- a/code/modules/power/antimatter/fuel.dm +++ b/code/modules/power/antimatter/fuel.dm @@ -1,5 +1,5 @@ /obj/item/weapon/fuel - name = "Magnetic Storage Ring" + name = "nagnetic storage ring" desc = "A magnetic storage ring." icon = 'icons/obj/items.dmi' icon_state = "rcdammo" @@ -11,12 +11,12 @@ var/content = null /obj/item/weapon/fuel/H - name = "Hydrogen storage ring" + name = "hydrogen storage ring" content = "Hydrogen" fuel = 1e-12 //pico-kilogram /obj/item/weapon/fuel/antiH - name = "Anti-Hydrogen storage ring" + name = "anti-hydrogen storage ring" content = "Anti-Hydrogen" fuel = 1e-12 //pico-kilogram @@ -26,16 +26,17 @@ if(istype(F, /obj/item/weapon/fuel/antiH)) src.fuel += F.fuel F.fuel = 0 - user << "You have added the anti-Hydrogen to the storage ring, it now contains [src.fuel]kg" + to_chat(user, "You add the anti-Hydrogen to the storage ring. It now contains [src.fuel]kg.") if(istype(F, /obj/item/weapon/fuel/H)) src.fuel += F.fuel qdel(F) + F = null src:annihilation(src.fuel) if(istype(src, /obj/item/weapon/fuel/H)) if(istype(F, /obj/item/weapon/fuel/H)) src.fuel += F.fuel F.fuel = 0 - user << "You have added the Hydrogen to the storage ring, it now contains [src.fuel]kg" + to_chat(user, "You add the Hydrogen to the storage ring. It now contains [src.fuel]kg") if(istype(F, /obj/item/weapon/fuel/antiH)) src.fuel += F.fuel qdel(src) @@ -43,6 +44,7 @@ /obj/item/weapon/fuel/antiH/proc/annihilation(var/mass) + var/strength = convert2energy(mass) if (strength < 773.0) @@ -67,21 +69,23 @@ return -/obj/item/weapon/fuel/examine(mob/user) - if(get_dist(src, user) <= 1) - user << "A magnetic storage ring, it contains [fuel]kg of [content ? content : "nothing"]." +/obj/item/weapon/fuel/examine() + ..() + to_chat(user, "A magnetic storage ring containing [fuel]kg of [content ? content : "nothing"].") /obj/item/weapon/fuel/proc/injest(mob/M as mob) switch(content) if("Anti-Hydrogen") + mob << span("notice", "That was not a very bright idea.") M.gib() if("Hydrogen") - M << "\blue You feel very light, as if you might just float away..." + to_chat(M, "You feel very light, as if you might just float away...") qdel(src) return /obj/item/weapon/fuel/attack(mob/M as mob, mob/user as mob) if (user != M) + //If you come from the distant future and happen to find this unincluded and derelict file, you may be wondering what this is. In truth, it's better that you don't know. var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( ) O.source = user O.target = M @@ -95,5 +99,5 @@ return else for(var/mob/O in viewers(M, null)) - O.show_message(text("\red [M] ate the [content ? content : "empty canister"]!"), 1) + O.show_message(text("\The [M] eats the [content ? content : "empty canister"]!"), 1) src.injest(M) diff --git a/code/modules/power/antimatter/shielding.dm b/code/modules/power/antimatter/shielding.dm index 4f89687fb4e..ece15f20691 100644 --- a/code/modules/power/antimatter/shielding.dm +++ b/code/modules/power/antimatter/shielding.dm @@ -3,15 +3,19 @@ proc/cardinalrange(var/center) var/list/things = list() for(var/direction in cardinal) var/turf/T = get_step(center, direction) - if(!T) continue + if(!T) + continue things += T.contents return things /obj/machinery/am_shielding name = "antimatter reactor section" - desc = "This device was built using a phoron life-form that seems to increase phoron's natural ability to react with neutrinos while reducing the combustibility." + desc = "A shielding component for an antimatter reactor. Looks delicate." + description_info = "Antimatter shielding sections must be beside an anchored control unit or another shielding section. If either are destroyed, the section will disappear." + description_antag = "Antimatter shielding sections are delicate. Attacking the shielding unit with a damaging object will reduce its stability, as will explosions. If the stability hits zero, the reactor may explode." - icon = 'icons/obj/machines/antimatter.dmi' + //icon = 'icons/obj/machines/antimatter.dmi' + icon = 'icons/obj/machines/new_ame.dmi' icon_state = "shield" anchored = 1 density = 1 @@ -24,14 +28,42 @@ proc/cardinalrange(var/center) var/processing = 0//To track if we are in the update list or not, we need to be when we are damaged and if we ever var/stability = 100//If this gets low bad things tend to happen var/efficiency = 1//How many cores this core counts for when doing power processing, phoron in the air and stability could affect this + var/coredirs = 0 + var/dirs = 0 + var/mapped = 0 //Set to 1 to ignore usual suicide if it doesn't immediately find a control_unit +// Stupidly easy way to use it in maps +/obj/machinery/am_shielding/map + mapped = 1 -/obj/machinery/am_shielding/New(loc) - ..(loc) - spawn(10) +/obj/machinery/am_shielding/New(loc, var/obj/machinery/power/am_control_unit/AMC) + ..() + if(!AMC) + if (!mapped) + WARNING("AME sector somehow created without a parent control unit!") controllerscan() - return + return + link_control(AMC) + remove_machine(src) + spawn (10) + update_icon() +/obj/machinery/am_shielding/proc/link_control(var/obj/machinery/power/am_control_unit/AMC) + if(!istype(AMC)) + return 0 + if(control_unit && control_unit != AMC) + return 0//Already have one + control_unit = AMC + return control_unit.add_shielding(src,1) + +/obj/machinery/am_shielding/Destroy() + if(control_unit) + control_unit.remove_shielding(src) + if(processing) + shutdown_core() + visible_message("\The [src.name] melts!") + //Might want to have it leave a mess on the floor but no sprites for now + ..() /obj/machinery/am_shielding/proc/controllerscan(var/priorscan = 0) //Make sure we are the only one here @@ -39,9 +71,9 @@ proc/cardinalrange(var/center) qdel(src) return for(var/obj/machinery/am_shielding/AMS in loc.contents) - if(AMS == src) continue - spawn(0) - qdel(src) + if(AMS == src) + continue + qdel(src) return //Search for shielding first @@ -49,41 +81,37 @@ proc/cardinalrange(var/center) if(AMS && AMS.control_unit && link_control(AMS.control_unit)) break - if(!control_unit)//No other guys nearby look for a control unit - for(var/direction in cardinal) + if(!control_unit)//No other guys nearby, look for a control unit for(var/obj/machinery/power/am_control_unit/AMC in cardinalrange(src)) if(AMC.add_shielding(src)) break - - if(!control_unit) - if(!priorscan) - spawn(20) + if(!mapped) // Prevent rescanning and suicide if it's part of the map + if(!priorscan) + sleep(20) controllerscan(1)//Last chance - return - spawn(0) + return qdel(src) - return +// Find surrounding unconnected shielding and add them to our controller +/obj/machinery/am_shielding/proc/assimilate() + if(!control_unit) + return // nothing to share :'^( + for(var/obj/machinery/am_shielding/neighbor in cardinalrange(src)) + if(neighbor && !neighbor.control_unit) + neighbor.link_control(control_unit) + neighbor.assimilate() // recursion is fun, right? -/obj/machinery/am_shielding/Destroy() - if(control_unit) control_unit.remove_shielding(src) - if(processing) shutdown_core() - visible_message("\red The [src.name] melts!") - //Might want to have it leave a mess on the floor but no sprites for now - ..() - return - - -/obj/machinery/am_shielding/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 +/obj/machinery/am_shielding/Cross(atom/movable/mover, turf/target, height=1.5, air_group = 0) + if(air_group || (height==0)) + return 1 return 0 /obj/machinery/am_shielding/process() - if(!processing) . = PROCESS_KILL + if(!processing) + . = PROCESS_KILL //TODO: core functions and stability //TODO: think about checking the airmix for phoron and increasing power output - return /obj/machinery/am_shielding/emp_act()//Immune due to not really much in the way of electronics. @@ -98,110 +126,130 @@ proc/cardinalrange(var/center) stability -= 40 if(3.0) stability -= 20 - check_stability() - return - - -/obj/machinery/am_shielding/bullet_act(var/obj/item/projectile/Proj) - if(Proj.check_armour != "bullet") - stability -= Proj.force/2 - return 0 - /obj/machinery/am_shielding/update_icon() - overlays.Cut() + overlays.len = 0 + coredirs = 0 + dirs = 0 for(var/direction in alldirs) - var/machine = locate(/obj/machinery, get_step(loc, direction)) - if((istype(machine, /obj/machinery/am_shielding) && machine:control_unit == control_unit)||(istype(machine, /obj/machinery/power/am_control_unit) && machine == control_unit)) - overlays += "shield_[direction]" + var/turf/T = get_step(loc, direction) + for(var/obj/machinery/machine in T) + // Detect cores + if((istype(machine, /obj/machinery/am_shielding) && machine:control_unit == control_unit && machine:processing)) + coredirs |= direction + + // Detect cores, shielding, and control boxen. + if(direction in cardinal) + if((istype(machine, /obj/machinery/am_shielding) && machine:control_unit == control_unit) || (istype(machine, /obj/machinery/power/am_control_unit) && machine == control_unit)) + dirs |= direction + + // If we're next to a core, set the prefix. + var/prefix = "" + var/icondirs = dirs + + if(coredirs) + prefix="core" + + // Set our overlay + icon_state = "[prefix]shield_[icondirs]" if(core_check()) - overlays += "core" - if(!processing) setup_core() - else if(processing) shutdown_core() + icon_state = "core[control_unit && control_unit.active]" + if(!processing) + setup_core() + else if(processing) + shutdown_core() /obj/machinery/am_shielding/attackby(obj/item/W, mob/user) - if(!istype(W) || !user) return + if(!istype(W) || !user) + return if(W.force > 10) stability -= W.force/2 check_stability() ..() return - - -//Call this to link a detected shilding unit to the controller -/obj/machinery/am_shielding/proc/link_control(var/obj/machinery/power/am_control_unit/AMC) - if(!istype(AMC)) return 0 - if(control_unit && control_unit != AMC) return 0//Already have one - control_unit = AMC - control_unit.add_shielding(src,1) - return 1 - - //Scans cards for shields or the control unit and if all there it /obj/machinery/am_shielding/proc/core_check() for(var/direction in alldirs) - var/machine = locate(/obj/machinery, get_step(loc, direction)) - if(!machine) return 0//Need all for a core - if(!istype(machine, /obj/machinery/am_shielding) && !istype(machine, /obj/machinery/power/am_control_unit)) return 0 + var/found_am_device=0 + for(var/obj/machinery/machine in get_step(loc, direction)) + if(!machine) + continue + if(istype(machine, /obj/machinery/am_shielding) || istype(machine, /obj/machinery/power/am_control_unit)) + found_am_device=1 + break + if(!found_am_device) + return 0 return 1 /obj/machinery/am_shielding/proc/setup_core() processing = 1 - machines.Add(src) - if(!control_unit) return + if(!control_unit) + return control_unit.linked_cores.Add(src) control_unit.reported_core_efficiency += efficiency - return /obj/machinery/am_shielding/proc/shutdown_core() processing = 0 - if(!control_unit) return + if(!control_unit) + return control_unit.linked_cores.Remove(src) control_unit.reported_core_efficiency -= efficiency - return /obj/machinery/am_shielding/proc/check_stability(var/injecting_fuel = 0) - if(stability > 0) return + if(stability > 0) + return if(injecting_fuel && control_unit) control_unit.exploding = 1 - if(src) - qdel(src) - return - + qdel(src) /obj/machinery/am_shielding/proc/recalc_efficiency(var/new_efficiency)//tbh still not 100% sure how I want to deal with efficiency so this is likely temp - if(!control_unit || !processing) return + if(!control_unit || !processing) + return if(stability < 50) new_efficiency /= 2 control_unit.reported_core_efficiency += (new_efficiency - efficiency) efficiency = new_efficiency - return /obj/item/device/am_shielding_container name = "packaged antimatter reactor section" - desc = "A small storage unit containing an antimatter reactor section. To use place near an antimatter control unit or deployed antimatter reactor section and use a multitool to activate this package." + desc = "A section of antimatter reactor shielding. Do not eat." + description_info = "To deploy, drop near an antimatter control unit or an existing deployed section and use your multitool on it." icon = 'icons/obj/machines/antimatter.dmi' icon_state = "box" item_state = "electronic" - w_class = 4.0 - flags = CONDUCT + siemens_coefficient = 1 throwforce = 5 throw_speed = 1 throw_range = 2 - matter = list(DEFAULT_WALL_MATERIAL = 100, "waste" = 2000) /obj/item/device/am_shielding_container/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/device/multitool) && istype(src.loc,/turf)) - new/obj/machinery/am_shielding(src.loc) - qdel(src) - return + if(ismultitool(I) && isturf(loc)) + if(locate(/obj/machinery/am_shielding/) in loc) + to_chat(user, "\icon[src]There is already an antimatter reactor section there.") + return + + //Search for shielding first + for(var/obj/machinery/am_shielding/AMS in cardinalrange(src)) + if(AMS.control_unit) + new/obj/machinery/am_shielding(src.loc, AMS.control_unit) + qdel(src) + return + + //No other guys nearby, look for a control unit + var/obj/machinery/power/am_control_unit/AMC = locate() in cardinalrange(src) + if(AMC && AMC.anchored) + new/obj/machinery/am_shielding(src.loc, AMC) + qdel(src) + else //Stranded & Alone + to_chat(user, "\icon[src]Couldn't connect to an Antimatter Control Unit.") + return + ..() - return \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7363f909624..fb81b76cbcb 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -195,6 +195,8 @@ cell.forceMove(loc) cell = null + QDEL_NULL(spark_system) + // Malf AI, removes the APC from AI's hacked APCs list. if((hacker) && (hacker.hacked_apcs) && (src in hacker.hacked_apcs)) hacker.hacked_apcs -= src @@ -276,27 +278,27 @@ status_overlays_lighting.len = 4 status_overlays_environ.len = 4 - status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red - status_overlays_lock[2] = image(icon, "apcox-1") + status_overlays_lock[1] = make_screen_overlay(icon, "apcox-0") // 0=blue 1=red + status_overlays_lock[2] = make_screen_overlay(icon, "apcox-1") - status_overlays_charging[1] = image(icon, "apco3-0") - status_overlays_charging[2] = image(icon, "apco3-1") - status_overlays_charging[3] = image(icon, "apco3-2") + status_overlays_charging[1] = make_screen_overlay(icon, "apco3-0") + status_overlays_charging[2] = make_screen_overlay(icon, "apco3-1") + status_overlays_charging[3] = make_screen_overlay(icon, "apco3-2") - status_overlays_equipment[1] = image(icon, "apco0-0") - status_overlays_equipment[2] = image(icon, "apco0-1") - status_overlays_equipment[3] = image(icon, "apco0-2") - status_overlays_equipment[4] = image(icon, "apco0-3") + status_overlays_equipment[1] = make_screen_overlay(icon, "apco0-0") + status_overlays_equipment[2] = make_screen_overlay(icon, "apco0-1") + status_overlays_equipment[3] = make_screen_overlay(icon, "apco0-2") + status_overlays_equipment[4] = make_screen_overlay(icon, "apco0-3") - status_overlays_lighting[1] = image(icon, "apco1-0") - status_overlays_lighting[2] = image(icon, "apco1-1") - status_overlays_lighting[3] = image(icon, "apco1-2") - status_overlays_lighting[4] = image(icon, "apco1-3") + status_overlays_lighting[1] = make_screen_overlay(icon, "apco1-0") + status_overlays_lighting[2] = make_screen_overlay(icon, "apco1-1") + status_overlays_lighting[3] = make_screen_overlay(icon, "apco1-2") + status_overlays_lighting[4] = make_screen_overlay(icon, "apco1-3") - status_overlays_environ[1] = image(icon, "apco2-0") - status_overlays_environ[2] = image(icon, "apco2-1") - status_overlays_environ[3] = image(icon, "apco2-2") - status_overlays_environ[4] = image(icon, "apco2-3") + status_overlays_environ[1] = make_screen_overlay(icon, "apco2-0") + status_overlays_environ[2] = make_screen_overlay(icon, "apco2-1") + status_overlays_environ[3] = make_screen_overlay(icon, "apco2-2") + status_overlays_environ[4] = make_screen_overlay(icon, "apco2-3") var/update = check_updates() //returns 0 if no need to update icons. // 1 if we need to update the icon_state diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 9c82dd32286..50dba504ebb 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -873,3 +873,202 @@ obj/structure/cable/proc/cableColor(var/colorC) /obj/item/stack/cable_coil/random/New() color = pick(COLOR_RED, COLOR_BLUE, COLOR_LIME, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN) ..() + +//nooses - all catbeast/ligger/squiggers/synths must hang + +/obj/item/stack/cable_coil/verb/make_noose() + set name = "Make Noose" + set category = "Object" + var/mob/M = usr + + if(ishuman(M) && !M.restrained() && !M.stat && !M.paralysis && ! M.stunned) + if(!istype(usr.loc,/turf)) return + if(!(locate(/obj/item/weapon/stool) in usr.loc) && !(locate(/obj/structure/bed) in usr.loc) && !(locate(/obj/structure/table) in usr.loc) && !(locate(/obj/structure/toilet) in usr.loc)) + usr << "You have to be standing on top of a chair/table/bed to make a noose!" + return 0 + if(src.amount <= 24) + usr << " You need at least 25 lengths to make a noose!" + return + new /obj/structure/noose(usr.loc) + usr << "You wind some cable together to make a noose, tying it to the ceiling." + src.use(25) + else + usr << "You cannot do that." + ..() + +/obj/structure/noose + name = "noose" + desc = "A morbid apparatus." + icon_state = "noose" + buckle_lying = 0 + icon = 'icons/obj/noose.dmi' + anchored = 1 + can_buckle = 1 + layer = 5 + var/image/over = null + var/ticks = 0 + +/obj/structure/noose/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/weapon/wirecutters)) + user.visible_message("[user] cuts the noose.", "You cut the noose.") + if(buckled_mob) + buckled_mob.visible_message("[buckled_mob] falls over and hits the ground!",\ + "You fall over and hit the ground!") + buckled_mob.adjustBruteLoss(10) + var/obj/item/stack/cable_coil/C = new(get_turf(src)) + C.amount = 25 + qdel(src) + return + ..() + +/obj/structure/noose/New() + ..() + pixel_y += 16 //Noose looks like it's "hanging" in the air + over = image(icon, "noose_overlay") + over.layer = MOB_LAYER + 0.1 + +/obj/structure/noose/Destroy() + processing_objects -= src + return ..() + +/obj/structure/noose/post_buckle_mob(mob/living/M) + if(M == buckled_mob) + layer = MOB_LAYER + overlays += over + processing_objects |= src + M.pixel_y = initial(M.pixel_y) + 8 //rise them up a bit + M.dir = SOUTH + else + layer = initial(layer) + overlays -= over + processing_objects -= src + pixel_x = initial(pixel_x) + M.pixel_x = initial(M.pixel_x) + M.pixel_y = initial(M.pixel_y) + +/obj/structure/noose/user_unbuckle_mob(mob/living/user) + + if(!user.IsAdvancedToolUser()) + return + + if(buckled_mob && buckled_mob.buckled == src) + var/mob/living/M = buckled_mob + if(M != user) + user.visible_message("[user] begins to untie the noose over [M]'s neck...",\ + "You begin to untie the noose over [M]'s neck...") + if(do_mob(user, M, 100)) + user.visible_message("[user] unties the noose over [M]'s neck!",\ + "You untie the noose over [M]'s neck!") + else + return + else + M.visible_message(\ + "[M] struggles to untie the noose over their neck!",\ + "You struggle to untie the noose over your neck.") + if(!do_after(M, 150)) + if(M && M.buckled) + M << "You fail to untie yourself!" + return + if(!M.buckled) + return + M.visible_message(\ + "[M] unties the noose over their neck!",\ + "You untie the noose over your neck!") + M.Weaken(3) + unbuckle_mob() + add_fingerprint(user) + +/obj/structure/noose/user_buckle_mob(mob/living/carbon/human/M, mob/user) + if(!in_range(user, src) || user.stat || user.restrained() || !istype(M)) + return 0 + + if(!user.IsAdvancedToolUser()) + return + + if (ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ("head") + if(!affecting) + user << "They don't have a head." + return + + if(M.loc != src.loc) return 0 //Can only noose someone if they're on the same tile as noose + + add_fingerprint(user) + + if(M == user && buckle_mob(M)) + M.visible_message(\ + "[M] ties \the [src] over their neck!",\ + "You tie \the [src] over your neck!") + playsound(user.loc, 'sound/effects/noosed.ogg', 50, 1, -1) + return 1 + else + M.visible_message(\ + "[user] attempts to tie \the [src] over [M]'s neck!",\ + "[user] ties \the [src] over your neck!") + user << "It will take 20 seconds and you have to stand still." + if(do_after(user, 200)) + if(buckle_mob(M)) + M.visible_message(\ + "[user] ties \the [src] over [M]'s neck!",\ + "[user] ties \the [src] over your neck!") + playsound(user.loc, 'sound/effects/noosed.ogg', 50, 1, -1) + return 1 + else + user.visible_message(\ + "[user] fails to tie \the [src] over [M]'s neck!",\ + "You fail to tie \the [src] over [M]'s neck!") + return 0 + else + user.visible_message(\ + "[user] fails to tie \the [src] over [M]'s neck!",\ + "You fail to tie \the [src] over [M]'s neck!") + return 0 + +/obj/structure/noose/process(mob/living/carbon/human/M, mob/user) + if(!buckled_mob) + processing_objects -= src + buckled_mob.pixel_x = initial(buckled_mob.pixel_x) + pixel_x = initial(pixel_x) + return + + ticks++ + switch(ticks) + if(1) + pixel_x -= 1 + buckled_mob.pixel_x -= 1 + if(2) + pixel_x = initial(pixel_x) + buckled_mob.pixel_x = initial(buckled_mob.pixel_x) + if(3) //Every third tick it plays a sound and RNG's a flavor text + pixel_x += 1 + buckled_mob.pixel_x += 1 + if(buckled_mob) + if (ishuman(buckled_mob)) + var/mob/living/carbon/human/H = buckled_mob + if (H.species && (H.species.flags & NO_BREATHE)) + return + if(prob(15)) + var/flavor_text = list("[buckled_mob]'s legs flail for anything to stand on.",\ + "[buckled_mob]'s hands are desperately clutching the noose.",\ + "[buckled_mob]'s limbs sway back and forth with diminishing strength.") + if(buckled_mob.stat == DEAD) + flavor_text = list("[buckled_mob]'s limbs lifelessly sway back and forth.",\ + "[buckled_mob]'s eyes stare straight ahead.") + buckled_mob.visible_message(pick(flavor_text)) + playsound(buckled_mob.loc, 'sound/effects/noose_idle.ogg', 50, 1, -3) + if(4) + pixel_x = initial(pixel_x) + buckled_mob.pixel_x = initial(buckled_mob.pixel_x) + ticks = 0 + + if(buckled_mob) + if (ishuman(buckled_mob)) + var/mob/living/carbon/human/H = buckled_mob + if (H.species && (H.species.flags & NO_BREATHE)) + return + buckled_mob.adjustOxyLoss(5) + buckled_mob.adjustBrainLoss(1) + buckled_mob.silent = max(buckled_mob.silent, 10) + if(prob(25)) //to reduce gasp spam + buckled_mob.emote("gasp") diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 8411e9c06dd..637f4aaefe6 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -229,13 +229,13 @@ ..() /obj/machinery/light/update_icon() - switch(status) // set icon_states if(LIGHT_OK) - if (supports_nightmode && nightmode) - icon_state = "[base_state][on]_night" + icon_state = "[base_state][on]" + if (supports_nightmode && nightmode && on) + color = "#d2d2d2" else - icon_state = "[base_state][on]" + color = null if(LIGHT_EMPTY) icon_state = "[base_state]-empty" @@ -246,7 +246,9 @@ if(LIGHT_BROKEN) icon_state = "[base_state]-broken" on = 0 - return + + if (!on) + color = null // update the icon_state and luminosity of the light depending on its state /obj/machinery/light/proc/update(var/trigger = 1) diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 9dfede5a99e..36bc0afd9ec 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -33,6 +33,10 @@ ..() spark_system = bind_spark(src, 5, alldirs) +/obj/machinery/power/emitter/Destroy() + QDEL_NULL(spark_system) + return ..() + /obj/machinery/power/emitter/verb/rotate() set name = "Rotate" set category = "Object" @@ -56,6 +60,7 @@ log_game("Emitter deleted at ([x],[y],[z])") investigate_log("deleted at ([x],[y],[z])","singulo") qdel(wifi_receiver) + qdel(spark_system) wifi_receiver = null return ..() diff --git a/code/modules/projectiles/effects.dm b/code/modules/projectiles/effects.dm index 087c1ccecc3..69c49ff662b 100644 --- a/code/modules/projectiles/effects.dm +++ b/code/modules/projectiles/effects.dm @@ -165,3 +165,29 @@ //---------------------------- /obj/effect/projectile/pulse_bullet/muzzle icon_state = "muzzle_pulse" + + +//---------------------------- +// Demonic Beam +//---------------------------- +/obj/effect/projectile/cult/tracer + icon_state = "cult" + +/obj/effect/projectile/cult/muzzle + icon_state = "muzzle_cult" + +/obj/effect/projectile/cult/impact + icon_state = "impact_cult" + + +//---------------------------- +// Empowered Demonic Beam +//---------------------------- +/obj/effect/projectile/cult/heavy/tracer + icon_state = "hcult" + +/obj/effect/projectile/cult/heavy/muzzle + icon_state = "muzzle_hcult" + +/obj/effect/projectile/cult/heavy/impact + icon_state = "impact_hcult" \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index fc70ee5a541..9334c770e78 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -374,7 +374,7 @@ icon = 'icons/obj/vaurca_items.dmi' icon_state = "thermaldrill" item_state = "thermaldrill" - origin_tech = "combat=6;phorontech=8," + origin_tech = list(TECH_COMBAT = 6, TECH_PHORON = 8) fire_sound = 'sound/magic/lightningbolt.ogg' slot_flags = SLOT_BACK w_class = 4 diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index c3a58213419..1ab63632c97 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -77,7 +77,7 @@ magazine_type = /obj/item/ammo_magazine/t40 allowed_magazines = list(/obj/item/ammo_magazine/t40) caliber = "10mm" - origin_tech = "combat=3;materials=2" + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 2) fire_sound = 'sound/weapons/Gunshot_light.ogg' load_method = MAGAZINE sel_mode = 1 diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index c425a61cfea..46766b09159 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -282,3 +282,39 @@ var/mob/living/M = A M.apply_effect(1, INCINERATE, 0) ..() + + + +//Beams of magical veil energy fired by empowered pylons. Some inbuilt armor penetration cuz magic. +//Ablative armor is still overwhelmingly useful +//These beams are very weak but rapid firing, ~twice per second. +/obj/item/projectile/beam/cult + name = "energy bolt" + //For projectiles name is only shown in onhit messages, so its more of a layman's description + //of what the projectile looks like + damage = 4 //Very weak + armor_penetration = 10 + accuracy = 4 //Guided by magic, unlikely to miss + var/mob/living/ignore + + muzzle_type = /obj/effect/projectile/cult/muzzle + tracer_type = /obj/effect/projectile/cult/tracer + impact_type = /obj/effect/projectile/cult/impact + +/obj/item/projectile/beam/cult/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0) + //Harmlessly passes through cultists and constructs + if (target_mob == ignore) + return 0 + if (iscult(target_mob)) + return 0 + + return ..() + +/obj/item/projectile/beam/cult/heavy + name = "glowing energy bolt" + damage = 12 //Stronger and better armor penetration, though still much weaker than a typical laser + armor_penetration = 15 + + muzzle_type = /obj/effect/projectile/cult/heavy/muzzle + tracer_type = /obj/effect/projectile/cult/heavy/tracer + impact_type = /obj/effect/projectile/cult/heavy/impact \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 4f8b7304b6f..54007df2d6d 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -184,9 +184,7 @@ P.icon_state = "pill"+pillsprite reagents.trans_to_obj(P,amount_per_pill) if(src.loaded_pill_bottle) - if(loaded_pill_bottle.contents.len < loaded_pill_bottle.max_storage_space) - P.loc = loaded_pill_bottle - src.updateUsrDialog() + loaded_pill_bottle.insert_into_storage(P) else if (href_list["createbottle"]) if(!condi) @@ -243,7 +241,7 @@ if(!beaker) dat = "Please insert beaker.
" if(src.loaded_pill_bottle) - dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.storage_slots]\]

" + dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.max_storage_space]\]

" else dat += "No pill bottle inserted.

" dat += "Close" @@ -251,7 +249,7 @@ var/datum/reagents/R = beaker:reagents dat += "Eject beaker and Clear Buffer
" if(src.loaded_pill_bottle) - dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.storage_slots]\]

" + dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.max_storage_space]\]

" else dat += "No pill bottle inserted.

" if(!R.total_volume) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm index d66a6a96c6d..032c7470ee6 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm @@ -117,7 +117,9 @@ if(alien == IS_DIONA) return //Diona can gain nutrients, but don't get drunk or suffer other effects - + + if(isunathi(M))//unathi are poisoned by alcohol as well + M.adjustToxLoss(2.5 * removed * (strength / 100)) var/quantity = (strength / 100) * removed M.intoxication += quantity diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm index 36eb5e15b18..02328b537b9 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm @@ -543,7 +543,7 @@ else if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) data = world.time - if(prob(90)) + if(prob(96)) M << "Your mind feels much more stable." else M << "Your mind breaks apart..." diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index 8f7d494e6b0..69495a4bd43 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -176,6 +176,13 @@ strength = 0.5 // It's not THAT poisonous. color = "#664330" +/datum/reagent/toxin/fertilizer/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + M.nutrition += removed*3 + //Fertilizer is good for plants + else + ..() + /datum/reagent/toxin/fertilizer/eznutrient name = "EZ Nutrient" id = "eznutrient" @@ -195,7 +202,7 @@ reagent_state = LIQUID color = "#49002E" strength = 4 - metabolism = REM * 0.35 + metabolism = REM*1.5 /datum/reagent/toxin/plantbgone/touch_turf(var/turf/T) if(istype(T, /turf/simulated/wall)) @@ -212,12 +219,12 @@ /datum/reagent/toxin/plantbgone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) ..() if(alien == IS_DIONA) - M.adjustToxLoss(50 * removed) + M.adjustToxLoss(8 * removed) +//Affect touch automatically transfers to affect_blood, so we'll apply the damage there, after accounting for permeability /datum/reagent/toxin/plantbgone/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) - ..() - if(alien == IS_DIONA) - M.adjustToxLoss(50 * removed) + removed *= M.reagent_permeability() + affect_blood(M, alien, removed*0.5) /datum/reagent/acid/polyacid name = "Polytrinic acid" diff --git a/code/modules/reagents/dispenser/cartridge.dm b/code/modules/reagents/dispenser/cartridge.dm index 2f7369cba0d..570fb0b0742 100644 --- a/code/modules/reagents/dispenser/cartridge.dm +++ b/code/modules/reagents/dispenser/cartridge.dm @@ -36,6 +36,13 @@ set category = "Object" set src in view(usr, 1) + if (!ishuman(usr)) + return + + if (usr.stat) + usr << "You cannot do that in your current state." + return + setLabel(L, usr) /obj/item/weapon/reagent_containers/chem_disp_cartridge/proc/setLabel(L, mob/user = null) diff --git a/code/modules/reagents/reagent_containers/food/cans.dm b/code/modules/reagents/reagent_containers/food/cans.dm index 7d72b8bf51f..5b19b671409 100644 --- a/code/modules/reagents/reagent_containers/food/cans.dm +++ b/code/modules/reagents/reagent_containers/food/cans.dm @@ -6,7 +6,7 @@ //DRINKS /obj/item/weapon/reagent_containers/food/drinks/cans/cola - name = "\improper Space Cola" + name = "space cola" desc = "Cola. in space." icon_state = "cola" center_of_mass = list("x"=16, "y"=10) @@ -33,7 +33,7 @@ reagents.add_reagent("spacemountainwind", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko - name = "\improper Thirteen Loko" + name = "thirteen loko" desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsibly." icon_state = "thirteen_loko" center_of_mass = list("x"=16, "y"=8) @@ -78,7 +78,7 @@ reagents.add_reagent("lemon_lime", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea - name = "\improper Vrisk Serket Iced Tea" + name = "\improper Vrisk Serket iced tea" desc = "That sweet, refreshing southern earthy flavor. That's where it's from, right? South Earth?" icon_state = "ice_tea_can" center_of_mass = list("x"=16, "y"=10) @@ -87,7 +87,7 @@ reagents.add_reagent("icetea", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice - name = "\improper Grapel Juice" + name = "\improper Grapel juice" desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" icon_state = "purple_can" center_of_mass = list("x"=16, "y"=10) @@ -96,7 +96,7 @@ reagents.add_reagent("grapejuice", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/tonic - name = "\improper T-Borg's Tonic Water" + name = "\improper T-Borg's tonic water" desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." icon_state = "tonic" center_of_mass = list("x"=16, "y"=10) diff --git a/code/modules/reagents/reagent_containers/food/condiment.dm b/code/modules/reagents/reagent_containers/food/condiment.dm index c6300a15628..e320c66b52a 100644 --- a/code/modules/reagents/reagent_containers/food/condiment.dm +++ b/code/modules/reagents/reagent_containers/food/condiment.dm @@ -6,7 +6,7 @@ //Food items that aren't eaten normally and leave an empty container behind. /obj/item/weapon/reagent_containers/food/condiment - name = "Condiment Container" + name = "condiment container" desc = "Just your average condiment container." icon = 'icons/obj/food.dmi' icon_state = "emptycondiment" @@ -58,51 +58,51 @@ if(reagents.reagent_list.len > 0) switch(reagents.get_master_reagent_id()) if("ketchup") - name = "Ketchup" + name = "ketchup" desc = "You feel more American already." icon_state = "ketchup" center_of_mass = list("x"=16, "y"=6) if("capsaicin") - name = "Hotsauce" + name = "hotsauce" desc = "You can almost TASTE the stomach ulcers now!" icon_state = "hotsauce" center_of_mass = list("x"=16, "y"=6) if("enzyme") - name = "Universal Enzyme" + name = "universal enzyme" desc = "Used in cooking various dishes." icon_state = "enzyme" center_of_mass = list("x"=16, "y"=6) if("soysauce") - name = "Soy Sauce" + name = "soy sauce" desc = "A salty soy-based flavoring." icon_state = "soysauce" center_of_mass = list("x"=16, "y"=6) if("frostoil") - name = "Coldsauce" + name = "coldsauce" desc = "Leaves the tongue numb in its passage." icon_state = "coldsauce" center_of_mass = list("x"=16, "y"=6) if("sodiumchloride") - name = "Salt Shaker" + name = "salt shaker" desc = "Salt. From space oceans, presumably." icon_state = "saltshaker" center_of_mass = list("x"=16, "y"=10) if("blackpepper") - name = "Pepper Mill" + name = "pepper mill" desc = "Often used to flavor food or make people sneeze." icon_state = "peppermillsmall" center_of_mass = list("x"=16, "y"=10) if("cornoil") - name = "Corn Oil" + name = "corn oil" desc = "A delicious oil used in cooking. Made from corn." icon_state = "oliveoil" center_of_mass = list("x"=16, "y"=6) if("sugar") - name = "Sugar" + name = "sugar" desc = "Tastey space sugar!" center_of_mass = list("x"=16, "y"=6) else - name = "Misc Condiment Bottle" + name = "misc condiment bottle" if (reagents.reagent_list.len==1) desc = "Looks like it is [reagents.get_master_reagent_name()], but you are not sure." else @@ -111,13 +111,13 @@ center_of_mass = list("x"=16, "y"=6) else icon_state = "emptycondiment" - name = "Condiment Bottle" + name = "condiment bottle" desc = "An empty condiment bottle." center_of_mass = list("x"=16, "y"=6) return /obj/item/weapon/reagent_containers/food/condiment/enzyme - name = "Universal Enzyme" + name = "universal enzyme" desc = "Used in cooking various dishes." icon_state = "enzyme" New() @@ -130,7 +130,7 @@ reagents.add_reagent("sugar", 50) /obj/item/weapon/reagent_containers/food/condiment/saltshaker //Seperate from above since it's a small shaker rather then - name = "Salt Shaker" // a large one. + name = "salt shaker" // a large one. desc = "Salt. From space oceans, presumably." icon_state = "saltshakersmall" possible_transfer_amounts = list(1,20) //for clown turning the lid off @@ -141,7 +141,7 @@ reagents.add_reagent("sodiumchloride", 20) /obj/item/weapon/reagent_containers/food/condiment/peppermill - name = "Pepper Mill" + name = "pepper mill" desc = "Often used to flavor food or make people sneeze." icon_state = "peppermillsmall" possible_transfer_amounts = list(1,20) //for clown turning the lid off diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index 0820f4445d1..f92818a48e7 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -102,7 +102,7 @@ // Formatting is the same as food. /obj/item/weapon/reagent_containers/food/drinks/milk - name = "Space Milk" + name = "space milk" desc = "It's milk. White and nutritious goodness!" icon_state = "milk" item_state = "carton" @@ -112,7 +112,7 @@ reagents.add_reagent("milk", 50) /obj/item/weapon/reagent_containers/food/drinks/soymilk - name = "SoyMilk" + name = "soymilk" desc = "It's soy milk. White and nutritious goodness!" icon_state = "soymilk" item_state = "carton" @@ -122,7 +122,7 @@ reagents.add_reagent("soymilk", 50) /obj/item/weapon/reagent_containers/food/drinks/coffee - name = "Robust Coffee" + name = "Robust coffee" desc = "Careful, the beverage you're about to enjoy is extremely hot." icon_state = "coffee" center_of_mass = list("x"=15, "y"=10) @@ -131,7 +131,7 @@ reagents.add_reagent("coffee", 30) /obj/item/weapon/reagent_containers/food/drinks/tea - name = "Duke Purple Tea" + name = "Duke purple tea" desc = "An insult to Duke Purple is an insult to the Space Queen! Any proper gentleman will fight you, if you sully this tea." icon_state = "teacup" item_state = "coffee" @@ -141,7 +141,7 @@ reagents.add_reagent("tea", 30) /obj/item/weapon/reagent_containers/food/drinks/ice - name = "Ice Cup" + name = "ice cup" desc = "Careful, cold ice, do not chew." icon_state = "coffee" center_of_mass = list("x"=15, "y"=10) @@ -150,7 +150,7 @@ reagents.add_reagent("ice", 30) /obj/item/weapon/reagent_containers/food/drinks/h_chocolate - name = "Dutch Hot Coco" + name = "dutch hot coco" desc = "Made in Space South America." icon_state = "hot_coco" item_state = "coffee" @@ -160,7 +160,7 @@ reagents.add_reagent("hot_coco", 30) /obj/item/weapon/reagent_containers/food/drinks/dry_ramen - name = "Cup Ramen" + name = "cup ramen" desc = "Just add 10ml water, self heats! A taste that reminds you of your school years." icon_state = "ramen" center_of_mass = list("x"=16, "y"=11) @@ -170,7 +170,7 @@ /obj/item/weapon/reagent_containers/food/drinks/sillycup - name = "Paper Cup" + name = "paper cup" desc = "A paper water cup." icon_state = "water_cup_e" possible_transfer_amounts = null @@ -191,7 +191,7 @@ // icon states. /obj/item/weapon/reagent_containers/food/drinks/shaker - name = "Shaker" + name = "shaker" desc = "A metal shaker to mix drinks in." icon_state = "shaker" amount_per_transfer_from_this = 10 @@ -208,7 +208,7 @@ center_of_mass = list("x"=17, "y"=7) /obj/item/weapon/reagent_containers/food/drinks/flask - name = "Captain's Flask" + name = "captain's flask" desc = "A metal flask belonging to the captain" icon_state = "flask" volume = 60 @@ -225,7 +225,7 @@ icon_state = "lithiumflask" /obj/item/weapon/reagent_containers/food/drinks/flask/detflask - name = "Detective's Flask" + name = "detective's flask" desc = "A metal flask with a leather band and golden badge belonging to the detective." icon_state = "detflask" volume = 60 diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index 87f88c8e8e1..b3a44f0a5e9 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -151,7 +151,7 @@ //Keeping this here for now, I'll ask if I should keep it here. /obj/item/weapon/broken_bottle - name = "Broken Bottle" + name = "broken bottle" desc = "A bottle with a sharp broken bottom." icon = 'icons/obj/drinks.dmi' icon_state = "broken_bottle" @@ -171,7 +171,7 @@ /obj/item/weapon/reagent_containers/food/drinks/bottle/gin - name = "Griffeater Gin" + name = "Griffeater gin" desc = "A bottle of high quality gin, produced in the New London Space Station." icon_state = "ginbottle" center_of_mass = list("x"=16, "y"=4) @@ -198,7 +198,7 @@ reagents.add_reagent("vodka", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla - name = "Caccavo Guaranteed Quality Tequilla" + name = "Caccavo Guaranteed Quality tequilla" desc = "Made from premium petroleum distillates, pure thalidomide and other fine quality ingredients!" icon_state = "tequillabottle" center_of_mass = list("x"=16, "y"=3) @@ -207,7 +207,7 @@ reagents.add_reagent("tequilla", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing - name = "Bottle of Nothing" + name = "bottle of nothing" desc = "A bottle filled with nothing" icon_state = "bottleofnothing" center_of_mass = list("x"=17, "y"=5) @@ -216,7 +216,7 @@ reagents.add_reagent("nothing", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/patron - name = "Wrapp Artiste Patron" + name = "Wrapp Artiste patron" desc = "Silver laced tequilla, served in space night clubs across the galaxy." icon_state = "patronbottle" center_of_mass = list("x"=16, "y"=6) @@ -225,7 +225,7 @@ reagents.add_reagent("patron", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/rum - name = "Captain Pete's Cuban Spiced Rum" + name = "Captain Pete's Cuban Spiced rum" desc = "This isn't just rum, oh no. It's practically GRIFF in a bottle." icon_state = "rumbottle" center_of_mass = list("x"=16, "y"=8) @@ -234,7 +234,7 @@ reagents.add_reagent("rum", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater - name = "Flask of Holy Water" + name = "flask of holy water" desc = "A flask of the chaplain's holy water." icon_state = "holyflask" center_of_mass = list("x"=17, "y"=10) @@ -243,7 +243,7 @@ reagents.add_reagent("holywater", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth - name = "Goldeneye Vermouth" + name = "Goldeneye vermouth" desc = "Sweet, sweet dryness~" icon_state = "vermouthbottle" center_of_mass = list("x"=17, "y"=3) @@ -252,7 +252,7 @@ reagents.add_reagent("vermouth", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua - name = "Robert Robust's Coffee Liqueur" + name = "Robert Robust's coffee liqueur" desc = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936, HONK" icon_state = "kahluabottle" center_of_mass = list("x"=17, "y"=3) @@ -261,7 +261,7 @@ reagents.add_reagent("kahlua", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager - name = "College Girl Goldschlager" + name = "College Girl goldschlager" desc = "Because they are the only ones who will drink 100 proof cinnamon schnapps." icon_state = "goldschlagerbottle" center_of_mass = list("x"=15, "y"=3) @@ -270,7 +270,7 @@ reagents.add_reagent("goldschlager", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/cognac - name = "Chateau De Baton Premium Cognac" + name = "Chateau De Baton Premium cognac" desc = "A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. You might as well not scream 'SHITCURITY' this time." icon_state = "cognacbottle" center_of_mass = list("x"=16, "y"=6) @@ -279,7 +279,7 @@ reagents.add_reagent("cognac", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/wine - name = "Doublebeard Bearded Special Wine" + name = "Doublebeard Bearded Special wine" desc = "A faint aura of unease and asspainery surrounds the bottle." icon_state = "winebottle" center_of_mass = list("x"=16, "y"=4) @@ -297,7 +297,7 @@ reagents.add_reagent("absinthe", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor - name = "Emeraldine Melon Liquor" + name = "Emeraldine melon liquor" desc = "A bottle of 46 proof Emeraldine Melon Liquor. Sweet and light." icon_state = "alco-green" //Placeholder. center_of_mass = list("x"=16, "y"=6) @@ -306,7 +306,7 @@ reagents.add_reagent("melonliquor", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao - name = "Miss Blue Curacao" + name = "Miss blue curacao" desc = "A fruity, exceptionally azure drink. Does not allow the imbiber to use the fifth magic." icon_state = "alco-blue" //Placeholder. center_of_mass = list("x"=16, "y"=6) @@ -315,7 +315,7 @@ reagents.add_reagent("bluecuracao", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine - name = "Briar Rose Grenadine Syrup" + name = "Briar Rose grenadine syrup" desc = "Sweet and tangy, a bar syrup used to add color or flavor to drinks." icon_state = "grenadinebottle" center_of_mass = list("x"=16, "y"=6) @@ -324,7 +324,7 @@ reagents.add_reagent("grenadine", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/cola - name = "\improper Space Cola" + name = "space cola" desc = "Cola. in space" icon_state = "colabottle" center_of_mass = list("x"=16, "y"=6) @@ -362,7 +362,7 @@ //////////////////////////JUICES AND STUFF /////////////////////// /obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice - name = "Orange Juice" + name = "orange juice" desc = "Full of vitamins and deliciousness!" icon_state = "orangejuice" item_state = "carton" @@ -373,7 +373,7 @@ reagents.add_reagent("orangejuice", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/cream - name = "Milk Cream" + name = "milk cream" desc = "It's cream. Made from milk. What else did you think you'd find in there?" icon_state = "cream" item_state = "carton" @@ -384,7 +384,7 @@ reagents.add_reagent("cream", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/tomatojuice - name = "Tomato Juice" + name = "tomato juice" desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness." icon_state = "tomatojuice" item_state = "carton" @@ -395,7 +395,7 @@ reagents.add_reagent("tomatojuice", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/limejuice - name = "Lime Juice" + name = "lime juice" desc = "Sweet-sour goodness." icon_state = "limejuice" item_state = "carton" @@ -425,7 +425,7 @@ reagents.add_reagent("beer", 30) /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale - name = "\improper Magm-Ale" + name = "\improper Magm-ale" desc = "A true dorf's drink of choice." icon_state = "alebottle" item_state = "beer" @@ -437,7 +437,7 @@ //aurora's drinks /obj/item/weapon/reagent_containers/food/drinks/bottle/chartreusegreen - name = "Green Chartreuse" + name = "green chartreuse" desc = "A green, strong liqueur." icon_state = "chartreusegreenbottle" New() @@ -445,7 +445,7 @@ reagents.add_reagent("chartreusegreen", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/chartreuseyellow - name = "Yellow Chartreuse" + name = "yellow chartreuse" desc = "A yellow, strong liqueur." icon_state = "chartreuseyellowbottle" New() @@ -453,7 +453,7 @@ reagents.add_reagent("chartreuseyellow", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/cremewhite - name = "White Creme de Menthe" + name = "white creme de menthe" desc = "Mint-flavoured alcohol, in a bottle." icon_state = "whitecremebottle" New() @@ -469,7 +469,7 @@ reagents.add_reagent("cremeyvette", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/brandy - name = "Brandy" + name = "brandy" desc = "Cheap knock off for cognac." icon_state = "brandybottle" New() @@ -493,7 +493,7 @@ reagents.add_reagent("drambuie", 100) /obj/item/weapon/reagent_containers/food/drinks/bottle/sbiten - name = "Sbiten" + name = "sbiten" desc = "A bottle full of sweet sbiten." icon_state = "sbitenbottle" New() diff --git a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm index c7f0f0a9fee..e722e791a8b 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm @@ -28,7 +28,7 @@ if(R.glass_name) name = R.glass_name else - name = "Glass of.. what?" + name = "glass of.. what?" if(R.glass_desc) desc = R.glass_desc diff --git a/code/modules/reagents/reagent_containers/food/lunch.dm b/code/modules/reagents/reagent_containers/food/lunch.dm index 6392213adae..8c9a7ded478 100644 --- a/code/modules/reagents/reagent_containers/food/lunch.dm +++ b/code/modules/reagents/reagent_containers/food/lunch.dm @@ -10,7 +10,9 @@ var/list/lunchables_lunches_ = list(/obj/item/weapon/reagent_containers/food/sna /obj/item/weapon/reagent_containers/food/snacks/liquidfood, /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry, /obj/item/weapon/reagent_containers/food/snacks/tossedsalad, - /obj/item/weapon/reagent_containers/food/snacks/koiswaffles) + /obj/item/weapon/reagent_containers/food/snacks/koiswaffles, + /obj/item/weapon/reagent_containers/food/snacks/funnelcake, + /obj/item/weapon/reagent_containers/food/snacks/hotdog) var/list/lunchables_snacks_ = list(/obj/item/weapon/reagent_containers/food/snacks/donut/jelly, /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly, diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 46ea5d35e91..c0b2e1d23f9 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -401,7 +401,7 @@ //Here is an example of the new formatting for anyone who wants to add more food items. ///obj/item/weapon/reagent_containers/food/snacks/xenoburger //Identification path for the object. -// name = "Xenoburger" //Name that displays in the UI. +// name = "xenoburger" //Name that displays in the UI. // desc = "Smells caustic. Tastes like heresy." //Duh // icon_state = "xburger" //Refers to an icon in food.dmi // New() //Don't mess with this. @@ -413,7 +413,7 @@ /obj/item/weapon/reagent_containers/food/snacks/koisbar - name = "K'ois Bar" + name = "k'ois bar" desc = "Bland NanoTrasen produced K'ois bars, rich in syrup." icon_state = "koisbar" trash = /obj/item/trash/koisbar @@ -425,7 +425,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/aesirsalad - name = "Aesir salad" + name = "aesir salad" desc = "Probably too incredible for mortal men to fully enjoy." icon_state = "aesirsalad" trash = /obj/item/trash/snack_bowl @@ -454,7 +454,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/candy/donor - name = "Donor Candy" + name = "donor candy" desc = "A little treat for blood donors." trash = /obj/item/trash/candy @@ -503,7 +503,7 @@ bitesize = 1 /obj/item/weapon/reagent_containers/food/snacks/chocolatebar - name = "Chocolate Bar" + name = "chocolate bar" desc = "Such sweet, fattening food." icon_state = "chocolatebar" filling_color = "#7D5F46" @@ -517,7 +517,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/chocolateegg - name = "Chocolate Egg" + name = "chocolate egg" desc = "Such sweet, fattening food." icon_state = "chocolateegg" filling_color = "#7D5F46" @@ -555,7 +555,7 @@ center_of_mass = list("x"=19, "y"=16) /obj/item/weapon/reagent_containers/food/snacks/donut/chaos - name = "Chaos Donut" + name = "chaos donut" desc = "Like life, it never quite tastes the same." icon_state = "donut1" filling_color = "#ED11E6" @@ -595,7 +595,7 @@ /obj/item/weapon/reagent_containers/food/snacks/donut/jelly - name = "Jelly Donut" + name = "jelly donut" desc = "You jelly?" icon_state = "jdonut1" filling_color = "#ED1169" @@ -614,7 +614,7 @@ reagents.add_reagent("sprinkles", 2) /obj/item/weapon/reagent_containers/food/snacks/donut/slimejelly - name = "Jelly Donut" + name = "jelly donut" desc = "You jelly?" icon_state = "jdonut1" filling_color = "#ED1169" @@ -633,7 +633,7 @@ reagents.add_reagent("sprinkles", 2) /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly - name = "Jelly Donut" + name = "jelly donut" desc = "You jelly?" icon_state = "jdonut1" filling_color = "#ED1169" @@ -652,7 +652,7 @@ reagents.add_reagent("sprinkles", 2) /obj/item/weapon/reagent_containers/food/snacks/funnelcake - name = "Funnel cake" + name = "funnel cake" desc = "Funnel cakes rule!" icon_state = "funnelcake" filling_color = "#Ef1479" @@ -733,7 +733,7 @@ icon_state = "egg-yellow" /obj/item/weapon/reagent_containers/food/snacks/friedegg - name = "Fried egg" + name = "fried egg" desc = "A fried egg, with a touch of salt and pepper." icon_state = "friedegg" filling_color = "#FFDF78" @@ -747,7 +747,7 @@ bitesize = 1 /obj/item/weapon/reagent_containers/food/snacks/boiledegg - name = "Boiled egg" + name = "boiled egg" desc = "A hard boiled egg." icon_state = "egg" filling_color = "#FFFFFF" @@ -771,7 +771,7 @@ src.bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/tofu - name = "Tofu" + name = "tofu" icon_state = "tofu" desc = "We all love tofu." filling_color = "#FFFEE0" @@ -783,7 +783,7 @@ src.bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/tofurkey - name = "Tofurkey" + name = "tofurkey" desc = "A fake turkey made from tofu." icon_state = "tofurkey" filling_color = "#FFFEE0" @@ -796,7 +796,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/stuffing - name = "Stuffing" + name = "stuffing" desc = "Moist, peppery breadcrumbs for filling the body cavities of dead birds. Dig in!" icon_state = "stuffing" filling_color = "#C9AC83" @@ -821,7 +821,7 @@ src.bitesize = 6 /obj/item/weapon/reagent_containers/food/snacks/fishfingers - name = "Fish Fingers" + name = "fish Fingers" desc = "A finger of fish." icon_state = "fishfingers" filling_color = "#FFDEFE" @@ -897,7 +897,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sausage - name = "Sausage" + name = "sausage" desc = "A piece of mixed, long meat." icon_state = "sausage" filling_color = "#DB0000" @@ -909,7 +909,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sausage/battered - name = "Battered Sausage" + name = "battered sausage" desc = "A piece of mixed, long meat, battered and then deepfried" icon_state = "batteredsausage" filling_color = "#DB0000" @@ -923,7 +923,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/jalapeno_poppers - name = "Jalapeno Popper" + name = "jalapeno popper" desc = "A battered, deep-fried chilli pepper" icon_state = "popper" filling_color = "#00AA00" @@ -979,12 +979,18 @@ proc/cooltime() if (src.warm) spawn(4200) - src.warm = 0 - for(var/reagent in heated_reagents) - src.reagents.del_reagent(reagent) - src.name = initial(name) + if(src) + src.warm = 0 + for(var/reagent in heated_reagents) + src.reagents.del_reagent(reagent) + src.name = initial(name) return +/obj/item/weapon/reagent_containers/food/snacks/donkpocket/cook() + ..() + if (!warm) + heat() + /obj/item/weapon/reagent_containers/food/snacks/brainburger name = "brainburger" desc = "A strange looking burger. It looks almost sentient." @@ -999,7 +1005,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/ghostburger - name = "Ghost Burger" + name = "ghost burger" desc = "Spooky! It doesn't look very filling." icon_state = "ghostburger" filling_color = "#FFF2FF" @@ -1051,7 +1057,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/fishburger - name = "Fillet -o- Carp Sandwich" + name = "fillet -o- carp sandwich" desc = "Almost like a carp is yelling somewhere... Give me back that fillet -o- carp, give me that carp." icon_state = "fishburger" filling_color = "#FFDEFE" @@ -1064,7 +1070,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/tofuburger - name = "Tofu Burger" + name = "tofu burger" desc = "What.. is that meat?" icon_state = "tofuburger" filling_color = "#FFFEE0" @@ -1115,7 +1121,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/clownburger - name = "Clown Burger" + name = "clown burger" desc = "This tastes funny..." icon_state = "clownburger" filling_color = "#FF00FF" @@ -1127,7 +1133,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/mimeburger - name = "Mime Burger" + name = "mime burger" desc = "Its taste defies language." icon_state = "mimeburger" filling_color = "#FFFFFF" @@ -1139,7 +1145,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/mouseburger - name = "Mouse Burger" + name = "mouse burger" desc = "Squeaky and a little furry." icon_state = "ratburger" center_of_mass = list("x"=16, "y"=11) @@ -1150,7 +1156,7 @@ /obj/item/weapon/reagent_containers/food/snacks/omelette - name = "Omelette Du Fromage" + name = "omelette du fromage" desc = "That's all you can say!" icon_state = "omelette" trash = /obj/item/trash/plate @@ -1176,7 +1182,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/pie - name = "Banana Cream Pie" + name = "banana cream pie" desc = "Just like back home, on clown planet! HONK!" icon_state = "pie" trash = /obj/item/trash/plate @@ -1196,7 +1202,7 @@ qdel(src) /obj/item/weapon/reagent_containers/food/snacks/berryclafoutis - name = "Berry Clafoutis" + name = "berry clafoutis" desc = "No black birds, this is a good sign." icon_state = "berryclafoutis" trash = /obj/item/trash/plate @@ -1222,7 +1228,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/eggplantparm - name = "Eggplant Parmigiana" + name = "eggplant parmigiana" desc = "The only good recipe for eggplant." icon_state = "eggplantparm" trash = /obj/item/trash/plate @@ -1235,7 +1241,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/soylentgreen - name = "Soylent Green" + name = "soylent green" desc = "Not made of people. Honest." //Totally people. icon_state = "soylent_green" trash = /obj/item/trash/waffles @@ -1248,7 +1254,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/soylenviridians - name = "Soylen Virdians" + name = "soylen virdians" desc = "Not made of people. Honest." //Actually honest for once. icon_state = "soylent_yellow" trash = /obj/item/trash/waffles @@ -1262,7 +1268,7 @@ /obj/item/weapon/reagent_containers/food/snacks/meatpie - name = "Meat-pie" + name = "meat-pie" icon_state = "meatpie" desc = "An old barber recipe, very delicious!" trash = /obj/item/trash/plate @@ -1275,7 +1281,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/tofupie - name = "Tofu-pie" + name = "tofu-pie" icon_state = "meatpie" desc = "A delicious tofu pie." trash = /obj/item/trash/plate @@ -1321,7 +1327,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/xemeatpie - name = "Xeno-pie" + name = "xeno-pie" icon_state = "xenomeatpie" desc = "A delicious meatpie. Probably heretical." trash = /obj/item/trash/plate @@ -1334,7 +1340,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/wingfangchu - name = "Wing Fang Chu" + name = "wing fang chu" desc = "A savory dish of alien wing wang in soy." icon_state = "wingfangchu" trash = /obj/item/trash/snack_bowl @@ -1361,7 +1367,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/monkeykabob - name = "Meat-kabob" + name = "meat-kabob" icon_state = "kabob" desc = "Delicious meat, on a stick." trash = /obj/item/stack/rods @@ -1374,7 +1380,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/tofukabob - name = "Tofu-kabob" + name = "tofu-kabob" icon_state = "kabob" desc = "Vegan meat, on a stick." trash = /obj/item/stack/rods @@ -1387,7 +1393,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/cubancarp - name = "Cuban Carp" + name = "cuban carp" desc = "A sandwich that burns your tongue and then leaves it numb!" icon_state = "cubancarp" trash = /obj/item/trash/plate @@ -1402,7 +1408,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/chickenkatsu - name = "Chicken Katsu" + name = "chicken katsu" desc = "A terran delicacy consisting of chicken fried in a light beer batter" icon_state = "katsu" trash = /obj/item/trash/plate @@ -1417,7 +1423,7 @@ bitesize = 1.5 /obj/item/weapon/reagent_containers/food/snacks/popcorn - name = "Popcorn" + name = "popcorn" desc = "Now let's find some cinema." icon_state = "popcorn" trash = /obj/item/trash/popcorn @@ -1438,7 +1444,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sosjerky - name = "Scaredy's Private Reserve Beef Jerky" + name = "Scaredy's Private Reserve beef jerky" icon_state = "sosjerky" desc = "Beef jerky made from the finest space cows." trash = /obj/item/trash/sosjerky @@ -1463,7 +1469,7 @@ reagents.add_reagent("nutriment", 6) /obj/item/weapon/reagent_containers/food/snacks/spacetwinkie - name = "Space Twinkie" + name = "space twinkie" icon_state = "space_twinkie" desc = "Guaranteed to survive longer then you will." filling_color = "#FFE591" @@ -1502,7 +1508,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/loadedbakedpotato - name = "Loaded Baked Potato" + name = "loaded baked potato" desc = "Totally baked." icon_state = "loadedbakedpotato" filling_color = "#9C7A68" @@ -1515,7 +1521,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/fries - name = "Space Fries" + name = "space fries" desc = "AKA: French Fries, Freedom Fries, etc." icon_state = "fries" trash = /obj/item/trash/plate @@ -1529,7 +1535,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/microchips - name = "Micro Chips" + name = "micro chips" desc = "Soft and rubbery. should have fried them" icon_state = "microchips" trash = /obj/item/trash/plate @@ -1542,7 +1548,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/ovenchips - name = "Ovem Chips" + name = "ovem chips" desc = "Dark and crispy, but a bit dry" icon_state = "ovenchips" trash = /obj/item/trash/plate @@ -1555,7 +1561,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/soydope - name = "Soy Dope" + name = "soy dope" desc = "Dope from a soy." icon_state = "soydope" trash = /obj/item/trash/plate @@ -1568,7 +1574,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/spagetti - name = "Spaghetti" + name = "spaghetti" desc = "A bundle of raw spaghetti." icon_state = "spagetti" filling_color = "#EDDD00" @@ -1580,7 +1586,7 @@ bitesize = 1 /obj/item/weapon/reagent_containers/food/snacks/cheesyfries - name = "Cheesy Fries" + name = "cheesy fries" desc = "Fries. Covered in cheese. Duh." icon_state = "cheesyfries" trash = /obj/item/trash/plate @@ -1594,7 +1600,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/fortunecookie - name = "Fortune cookie" + name = "fortune cookie" desc = "A true prophecy in each cookie!" icon_state = "fortune_cookie" filling_color = "#E8E79E" @@ -1606,7 +1612,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/badrecipe - name = "Burned mess" + name = "burned mess" desc = "Someone should be demoted from chef for this." icon_state = "badrecipe" filling_color = "#211F02" @@ -1619,7 +1625,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/meatsteak - name = "Meat steak" + name = "meat steak" desc = "A piece of hot spicy meat." icon_state = "meatstake" trash = /obj/item/trash/plate @@ -1635,7 +1641,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/spacylibertyduff - name = "Spacy Liberty Duff" + name = "spacy liberty duff" desc = "Jello gelatin, from Alfred Hubbard's cookbook" icon_state = "spacylibertyduff" trash = /obj/item/trash/snack_bowl @@ -1649,7 +1655,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/amanitajelly - name = "Amanita Jelly" + name = "amanita jelly" desc = "Looks curiously toxic" icon_state = "amanitajelly" trash = /obj/item/trash/snack_bowl @@ -1664,7 +1670,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/poppypretzel - name = "Poppy pretzel" + name = "poppy pretzel" desc = "It's all twisted up!" icon_state = "poppypretzel" bitesize = 2 @@ -1678,7 +1684,7 @@ /obj/item/weapon/reagent_containers/food/snacks/meatballsoup - name = "Meatball soup" + name = "meatball soup" desc = "You've got balls kid, BALLS!" icon_state = "meatballsoup" trash = /obj/item/trash/snack_bowl @@ -1704,7 +1710,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/bloodsoup - name = "Tomato soup" + name = "tomato soup" desc = "Smells like copper." icon_state = "tomatosoup" filling_color = "#FF0000" @@ -1718,7 +1724,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/clownstears - name = "Clown's Tears" + name = "clown's tears" desc = "Not very funny." icon_state = "clownstears" filling_color = "#C4FBFF" @@ -1732,7 +1738,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/vegetablesoup - name = "Vegetable soup" + name = "vegetable soup" desc = "A true vegan meal" //TODO icon_state = "vegetablesoup" trash = /obj/item/trash/snack_bowl @@ -1746,7 +1752,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/nettlesoup - name = "Nettle soup" + name = "nettle soup" desc = "To think, the botanist would've beat you to death with one of these." icon_state = "nettlesoup" trash = /obj/item/trash/snack_bowl @@ -1761,7 +1767,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/mysterysoup - name = "Mystery soup" + name = "mystery soup" desc = "The mystery is, why aren't you eating it?" icon_state = "mysterysoup" trash = /obj/item/trash/snack_bowl @@ -1809,7 +1815,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/wishsoup - name = "Wish Soup" + name = "wish soup" desc = "I wish this was soup." icon_state = "wishsoup" trash = /obj/item/trash/snack_bowl @@ -1825,7 +1831,7 @@ reagents.add_reagent("nutriment", 8) /obj/item/weapon/reagent_containers/food/snacks/hotchili - name = "Hot Chili" + name = "hot chili" desc = "A five alarm Texan Chili!" icon_state = "hotchili" trash = /obj/item/trash/snack_bowl @@ -1842,7 +1848,7 @@ /obj/item/weapon/reagent_containers/food/snacks/coldchili - name = "Cold Chili" + name = "cold chili" desc = "This slush is barely a liquid!" icon_state = "coldchili" filling_color = "#2B00FF" @@ -1859,7 +1865,7 @@ /* No more of this /obj/item/weapon/reagent_containers/food/snacks/telebacon - name = "Tele Bacon" + name = "tele bacon" desc = "It tastes a little odd but it is still delicious." icon_state = "bacon" var/obj/item/device/radio/beacon/bacon/baconbeacon @@ -1991,7 +1997,7 @@ /obj/item/weapon/reagent_containers/food/snacks/spellburger - name = "Spell Burger" + name = "spell burger" desc = "This is absolutely Ei Nath." icon_state = "spellburger" filling_color = "#D505FF" @@ -2002,7 +2008,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/bigbiteburger - name = "Big Bite Burger" + name = "big bite burger" desc = "Forget the Big Mac. THIS is the future!" icon_state = "bigbiteburger" filling_color = "#E3D681" @@ -2015,7 +2021,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/enchiladas - name = "Enchiladas" + name = "enchiladas" desc = "Viva La Mexico!" icon_state = "enchiladas" trash = /obj/item/trash/tray @@ -2030,7 +2036,7 @@ bitesize = 4 /obj/item/weapon/reagent_containers/food/snacks/monkeysdelight - name = "monkey's Delight" + name = "monkey's delight" desc = "Eeee Eee!" icon_state = "monkeysdelight" trash = /obj/item/trash/tray @@ -2046,7 +2052,7 @@ bitesize = 6 /obj/item/weapon/reagent_containers/food/snacks/baguette - name = "Baguette" + name = "baguette" desc = "Bon appetit!" icon_state = "baguette" filling_color = "#E3D796" @@ -2060,7 +2066,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/fishandchips - name = "Fish and Chips" + name = "fish and chips" desc = "I do say so myself chap." icon_state = "fishandchips" filling_color = "#E3D796" @@ -2074,7 +2080,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/sandwich - name = "Sandwich" + name = "sandwich" desc = "A grand creation of meat, cheese, bread, and several leaves of lettuce! Arthur Dent would be proud." icon_state = "sandwich" trash = /obj/item/trash/plate @@ -2088,7 +2094,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/toastedsandwich - name = "Toasted Sandwich" + name = "toasted sandwich" desc = "Now if you only had a pepper bar." icon_state = "toastedsandwich" trash = /obj/item/trash/plate @@ -2103,7 +2109,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/grilledcheese - name = "Grilled Cheese Sandwich" + name = "grilled cheese sandwich" desc = "Goes great with Tomato soup!" icon_state = "toastedsandwich" trash = /obj/item/trash/plate @@ -2116,7 +2122,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/tomatosoup - name = "Tomato Soup" + name = "tomato soup" desc = "Drinking this feels like being a vampire! A tomato vampire..." icon_state = "tomatosoup" trash = /obj/item/trash/snack_bowl @@ -2130,7 +2136,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/rofflewaffles - name = "Roffle Waffles" + name = "roffle waffles" desc = "Waffles from Roffle. Co." icon_state = "rofflewaffles" trash = /obj/item/trash/waffles @@ -2160,7 +2166,7 @@ bitesize = 10 /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast - name = "Jellied Toast" + name = "jellied toast" desc = "A slice of bread covered with delicious jam." icon_state = "jellytoast" trash = /obj/item/trash/plate @@ -2183,7 +2189,7 @@ reagents.add_reagent("slimejelly", 5) /obj/item/weapon/reagent_containers/food/snacks/jellyburger - name = "Jelly Burger" + name = "jelly burger" desc = "Culinary delight..?" icon_state = "jellyburger" filling_color = "#B572AB" @@ -2205,7 +2211,7 @@ reagents.add_reagent("cherryjelly", 5) /obj/item/weapon/reagent_containers/food/snacks/milosoup - name = "Milosoup" + name = "milosoup" desc = "The universes best soup! Yum!!!" icon_state = "milosoup" trash = /obj/item/trash/snack_bowl @@ -2218,7 +2224,7 @@ bitesize = 4 /obj/item/weapon/reagent_containers/food/snacks/stewedsoymeat - name = "Stewed Soy Meat" + name = "stewed soy meat" desc = "Even non-vegetarians will LOVE this!" icon_state = "stewedsoymeat" trash = /obj/item/trash/plate @@ -2230,7 +2236,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/boiledspagetti - name = "Boiled Spaghetti" + name = "boiled spaghetti" desc = "A plain dish of noodles, this sucks." icon_state = "spagettiboiled" trash = /obj/item/trash/plate @@ -2243,7 +2249,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/boiledrice - name = "Boiled Rice" + name = "boiled rice" desc = "A boring dish of boring rice." icon_state = "boiledrice" trash = /obj/item/trash/snack_bowl @@ -2256,7 +2262,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/ricepudding - name = "Rice Pudding" + name = "rice pudding" desc = "Where's the jam?" icon_state = "rpudding" trash = /obj/item/trash/snack_bowl @@ -2269,7 +2275,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/pudding - name = "Figgy pudding" + name = "figgy pudding" icon_state = "pudding" desc = "Bring it to me." trash = /obj/item/trash/plate @@ -2281,7 +2287,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/pastatomato - name = "Spaghetti" + name = "spaghetti" desc = "Spaghetti and crushed tomatoes. Just like your abusive father used to make!" icon_state = "pastatomato" trash = /obj/item/trash/plate @@ -2295,7 +2301,7 @@ bitesize = 4 /obj/item/weapon/reagent_containers/food/snacks/meatballspagetti - name = "Spaghetti & Meatballs" + name = "spaghetti & meatballs" desc = "Now thats a nic'e meatball!" icon_state = "meatballspagetti" trash = /obj/item/trash/plate @@ -2309,7 +2315,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/spesslaw - name = "Spesslaw" + name = "spesslaw" desc = "A lawyers favourite" icon_state = "spesslaw" filling_color = "#DE4545" @@ -2336,7 +2342,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/superbiteburger - name = "Super Bite Burger" + name = "super bite burger" desc = "This is a mountain of a burger. FOOD!" icon_state = "superbiteburger" filling_color = "#CCA26A" @@ -2349,7 +2355,7 @@ bitesize = 10 /obj/item/weapon/reagent_containers/food/snacks/candiedapple - name = "Candied Apple" + name = "candied apple" desc = "An apple coated in sugary sweetness." icon_state = "candiedapple" filling_color = "#F21873" @@ -2361,7 +2367,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/applepie - name = "Apple Pie" + name = "apple pie" desc = "A pie containing sweet sweet love... or apple." icon_state = "applepie" filling_color = "#E0EDC5" @@ -2374,7 +2380,7 @@ /obj/item/weapon/reagent_containers/food/snacks/cherrypie - name = "Cherry Pie" + name = "cherry pie" desc = "Taste so good, make a grown man cry." icon_state = "cherrypie" filling_color = "#FF525A" @@ -2386,7 +2392,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/twobread - name = "Two Bread" + name = "two bread" desc = "It is very bitter and winy." icon_state = "twobread" filling_color = "#DBCC9A" @@ -2398,7 +2404,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/jellysandwich - name = "Jelly Sandwich" + name = "jelly sandwich" desc = "You wish you had some peanut butter to go with this..." icon_state = "jellysandwich" trash = /obj/item/trash/plate @@ -2421,7 +2427,7 @@ reagents.add_reagent("cherryjelly", 5) /obj/item/weapon/reagent_containers/food/snacks/boiledslimecore - name = "Boiled slime Core" + name = "boiled slime core" desc = "A boiled red thing." icon_state = "boiledslimecore" //nonexistant? New() @@ -2597,7 +2603,7 @@ center_of_mass = list("x"=16, "y"=13) /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread - name = "Banana-nut bread" + name = "banana-nut bread" desc = "A heavenly and filling treat." icon_state = "bananabread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/bananabreadslice @@ -2612,7 +2618,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/bananabreadslice - name = "Banana-nut bread slice" + name = "banana-nut bread slice" desc = "A slice of delicious banana bread." icon_state = "bananabreadslice" trash = /obj/item/trash/plate @@ -2621,7 +2627,7 @@ center_of_mass = list("x"=16, "y"=8) /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread - name = "Tofubread" + name = "tofubread" icon_state = "Like meatbread but for vegetarians. Not guaranteed to give superpowers." icon_state = "tofubread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/tofubreadslice @@ -2635,7 +2641,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/tofubreadslice - name = "Tofubread slice" + name = "tofubread slice" desc = "A slice of delicious tofubread." icon_state = "tofubreadslice" trash = /obj/item/trash/plate @@ -2645,7 +2651,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake - name = "Carrot Cake" + name = "carrot cake" desc = "A favorite desert of a certain wascally wabbit. Not a lie." icon_state = "carrotcake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice @@ -2660,7 +2666,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice - name = "Carrot Cake slice" + name = "carrot cake slice" desc = "Carrotty slice of Carrot Cake, carrots are good for your eyes! Also not a lie." icon_state = "carrotcake_slice" trash = /obj/item/trash/plate @@ -2669,7 +2675,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake - name = "Brain Cake" + name = "brain cake" desc = "A squishy cake-thing." icon_state = "braincake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/braincakeslice @@ -2685,7 +2691,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/braincakeslice - name = "Brain Cake slice" + name = "brain cake slice" desc = "Lemme tell you something about prions. THEY'RE DELICIOUS." icon_state = "braincakeslice" trash = /obj/item/trash/plate @@ -2694,7 +2700,7 @@ center_of_mass = list("x"=16, "y"=12) /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake - name = "Cheese Cake" + name = "cheese cake" desc = "DANGEROUSLY cheesy." icon_state = "cheesecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice @@ -2709,7 +2715,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice - name = "Cheese Cake slice" + name = "cheese cake slice" desc = "Slice of pure cheestisfaction" icon_state = "cheesecake_slice" trash = /obj/item/trash/plate @@ -2718,7 +2724,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake - name = "Vanilla Cake" + name = "vanilla cake" desc = "A plain cake, not a lie." icon_state = "plaincake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/plaincakeslice @@ -2731,7 +2737,7 @@ reagents.add_reagent("nutriment", 20) /obj/item/weapon/reagent_containers/food/snacks/plaincakeslice - name = "Vanilla Cake slice" + name = "vanilla cake slice" desc = "Just a slice of cake, it is enough for everyone." icon_state = "plaincake_slice" trash = /obj/item/trash/plate @@ -2740,7 +2746,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake - name = "Orange Cake" + name = "orange cake" desc = "A cake with added orange." icon_state = "orangecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/orangecakeslice @@ -2753,7 +2759,7 @@ reagents.add_reagent("nutriment", 20) /obj/item/weapon/reagent_containers/food/snacks/orangecakeslice - name = "Orange Cake slice" + name = "orange cake slice" desc = "Just a slice of cake, it is enough for everyone." icon_state = "orangecake_slice" trash = /obj/item/trash/plate @@ -2762,7 +2768,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake - name = "Lime Cake" + name = "lime cake" desc = "A cake with added lime." icon_state = "limecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/limecakeslice @@ -2775,7 +2781,7 @@ reagents.add_reagent("nutriment", 20) /obj/item/weapon/reagent_containers/food/snacks/limecakeslice - name = "Lime Cake slice" + name = "lime cake slice" desc = "Just a slice of cake, it is enough for everyone." icon_state = "limecake_slice" trash = /obj/item/trash/plate @@ -2784,7 +2790,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake - name = "Lemon Cake" + name = "lemon cake" desc = "A cake with added lemon." icon_state = "lemoncake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice @@ -2797,7 +2803,7 @@ reagents.add_reagent("nutriment", 20) /obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice - name = "Lemon Cake slice" + name = "lemon cake slice" desc = "Just a slice of cake, it is enough for everyone." icon_state = "lemoncake_slice" trash = /obj/item/trash/plate @@ -2806,7 +2812,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake - name = "Chocolate Cake" + name = "chocolate cake" desc = "A cake with added chocolate" icon_state = "chocolatecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice @@ -2819,7 +2825,7 @@ reagents.add_reagent("nutriment", 20) /obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice - name = "Chocolate Cake slice" + name = "chocolate cake slice" desc = "Just a slice of cake, it is enough for everyone." icon_state = "chocolatecake_slice" trash = /obj/item/trash/plate @@ -2828,7 +2834,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel - name = "Cheese wheel" + name = "cheese wheel" desc = "A big wheel of delcious Cheddar." icon_state = "cheesewheel" slice_path = /obj/item/weapon/reagent_containers/food/snacks/cheesewedge @@ -2842,7 +2848,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/cheesewedge - name = "Cheese wedge" + name = "cheese wedge" desc = "A wedge of delicious Cheddar. The cheese wheel it was cut from can't have gone far." icon_state = "cheesewedge" filling_color = "#FFF700" @@ -2850,7 +2856,7 @@ center_of_mass = list("x"=16, "y"=10) /obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake - name = "Birthday Cake" + name = "birthday cake" desc = "Happy Birthday..." icon_state = "birthdaycake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice @@ -2865,7 +2871,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice - name = "Birthday Cake slice" + name = "birthday cake slice" desc = "A slice of your birthday." icon_state = "birthdaycakeslice" trash = /obj/item/trash/plate @@ -2874,7 +2880,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread - name = "Bread" + name = "bread" icon_state = "Some plain old Earthen bread." icon_state = "bread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/breadslice @@ -2888,7 +2894,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/breadslice - name = "Bread slice" + name = "bread slice" desc = "A slice of home." icon_state = "breadslice" trash = /obj/item/trash/plate @@ -2898,7 +2904,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread - name = "Cream Cheese Bread" + name = "cream cheese bread" desc = "Yum yum yum!" icon_state = "creamcheesebread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice @@ -2913,7 +2919,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice - name = "Cream Cheese Bread slice" + name = "cream cheese bread slice" desc = "A slice of yum!" icon_state = "creamcheesebreadslice" trash = /obj/item/trash/plate @@ -2923,7 +2929,7 @@ /obj/item/weapon/reagent_containers/food/snacks/watermelonslice - name = "Watermelon Slice" + name = "watermelon slice" desc = "A slice of watery goodness." icon_state = "watermelonslice" filling_color = "#FF3867" @@ -2932,7 +2938,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake - name = "Apple Cake" + name = "apple cake" desc = "A cake centred with Apple" icon_state = "applecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/applecakeslice @@ -2945,7 +2951,7 @@ reagents.add_reagent("nutriment", 15) /obj/item/weapon/reagent_containers/food/snacks/applecakeslice - name = "Apple Cake slice" + name = "apple cake slice" desc = "A slice of heavenly cake." icon_state = "applecakeslice" trash = /obj/item/trash/plate @@ -2954,7 +2960,7 @@ center_of_mass = list("x"=16, "y"=14) /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie - name = "Pumpkin Pie" + name = "pumpkin pie" desc = "A delicious treat for the autumn months." icon_state = "pumpkinpie" slice_path = /obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice @@ -2967,7 +2973,7 @@ reagents.add_reagent("nutriment", 15) /obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice - name = "Pumpkin Pie slice" + name = "pumpkin pie slice" desc = "A slice of pumpkin pie, with whipped cream on top. Perfection." icon_state = "pumpkinpieslice" trash = /obj/item/trash/plate @@ -2976,7 +2982,7 @@ center_of_mass = list("x"=16, "y"=12) /obj/item/weapon/reagent_containers/food/snacks/cracker - name = "Cracker" + name = "cracker" desc = "It's a salted cracker." icon_state = "cracker" filling_color = "#F5DEB8" @@ -2995,7 +3001,7 @@ filling_color = "#BAA14C" /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita - name = "Margherita" + name = "margherita" desc = "The golden standard of pizzas." icon_state = "pizzamargherita" slice_path = /obj/item/weapon/reagent_containers/food/snacks/margheritaslice @@ -3010,7 +3016,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/margheritaslice - name = "Margherita slice" + name = "margherita slice" desc = "A slice of the classic pizza." icon_state = "pizzamargheritaslice" filling_color = "#BAA14C" @@ -3018,7 +3024,7 @@ center_of_mass = list("x"=18, "y"=13) /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza - name = "Meatpizza" + name = "meatpizza" desc = "A pizza with meat topping." icon_state = "meatpizza" slice_path = /obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice @@ -3032,7 +3038,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice - name = "Meatpizza slice" + name = "meatpizza slice" desc = "A slice of a meaty pizza." icon_state = "meatpizzaslice" filling_color = "#BAA14C" @@ -3040,7 +3046,7 @@ center_of_mass = list("x"=18, "y"=13) /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza - name = "Mushroompizza" + name = "mushroompizza" desc = "Very special pizza" icon_state = "mushroompizza" slice_path = /obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice @@ -3054,7 +3060,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice - name = "Mushroompizza slice" + name = "mushroompizza slice" desc = "Maybe it is the last slice of pizza in your life." icon_state = "mushroompizzaslice" filling_color = "#BAA14C" @@ -3062,7 +3068,7 @@ center_of_mass = list("x"=18, "y"=13) /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza - name = "Vegetable pizza" + name = "vegetable pizza" desc = "No one of Tomato Sapiens were harmed during making this pizza" icon_state = "vegetablepizza" slice_path = /obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice @@ -3078,7 +3084,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice - name = "Vegetable pizza slice" + name = "vegetable pizza slice" desc = "A slice of the most green pizza of all pizzas not containing green ingredients " icon_state = "vegetablepizzaslice" filling_color = "#BAA14C" @@ -3087,7 +3093,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/crunch - name = "Pizza Crunch" + name = "pizza crunch" desc = "This was once a normal pizza, but it has been coated in batter and deep-fried. Whatever toppings it once had are a mystery, but they're still under there, somewhere..." icon_state = "pizzacrunch" slice_path = /obj/item/weapon/reagent_containers/food/snacks/pizzacrunchslice @@ -3103,7 +3109,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/pizzacrunchslice - name = "Pizza Crunch" + name = "pizza crunch" desc = "A little piece of a heart attack. It's toppings are a mystery, hidden under batter" icon_state = "pizzacrunchslice" filling_color = "#BAA14C" @@ -3524,7 +3530,7 @@ reagents.add_reagent("nutriment", 3) /obj/item/weapon/reagent_containers/food/snacks/liquidfood - name = "\improper LiquidFood Ration" + name = "\improper LiquidFood ration" desc = "A prepackaged grey slurry of all the essential nutrients for a spacefarer on the go. Should this be crunchy?" icon_state = "liquidfood" trash = /obj/item/trash/liquidfood @@ -3564,7 +3570,7 @@ bitesize = 3 /obj/item/weapon/reagent_containers/food/snacks/friedkois - name = "Fried K'ois" + name = "fried k'ois" desc = "K'ois, freshly bathed in the radiation of a microwave." icon_state = "friedkois" filling_color = "#E6E600" @@ -3587,7 +3593,7 @@ qdel(src) /obj/item/weapon/reagent_containers/food/snacks/koiskebab1 - name = "K'ois on a Stick" + name = "k'ois on a stick" desc = "It's K'ois. On a stick. It looks like you could fit more." icon_state = "koisbab1" trash = /obj/item/stack/rods @@ -3608,7 +3614,7 @@ /obj/item/weapon/reagent_containers/food/snacks/koiskebab2 - name = "K'ois on a Stick" + name = "k'ois on a stick" desc = "It's K'ois. On a stick. It looks like you could fit more." icon_state = "koisbab2" trash = /obj/item/stack/rods @@ -3628,7 +3634,7 @@ qdel(W) /obj/item/weapon/reagent_containers/food/snacks/koiskebab3 - name = "K'ois on a Stick" + name = "k'ois on a stick" desc = "It's K'ois. On a stick. It doesn't look like you can fit anymore." icon_state = "koisbab3" trash = /obj/item/stack/rods @@ -3641,7 +3647,7 @@ bitesize = 9 /obj/item/weapon/reagent_containers/food/snacks/koissoup - name = "K'ois Paste" + name = "k'ois paste" desc = "A thick K'ois goop, piled into a bowl." icon_state = "koissoup" trash = /obj/item/trash/snack_bowl @@ -3654,7 +3660,7 @@ bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/koiswaffles - name = "K'ois Waffles" + name = "k'ois waffles" desc = "Rock-hard 'waffles' composed entirely of microwaved K'ois goop." icon_state = "koiswaffles" trash = /obj/item/trash/waffles @@ -3667,7 +3673,7 @@ bitesize = 5 /obj/item/weapon/reagent_containers/food/snacks/koisjelly - name = "K'ois Jelly" + name = "k'ois jelly" desc = "Enriched K'ois paste, filled to the brim with the good stuff." icon_state = "koisjelly" filling_color = "#E6E600" diff --git a/code/modules/reagents/reagent_containers/food/snacks/meat.dm b/code/modules/reagents/reagent_containers/food/snacks/meat.dm index 58e773b0e0c..832070fb934 100644 --- a/code/modules/reagents/reagent_containers/food/snacks/meat.dm +++ b/code/modules/reagents/reagent_containers/food/snacks/meat.dm @@ -26,6 +26,7 @@ if (!isnull(cooked_icon)) icon_state = cooked_icon + flat_icon = null //Force regenating the flat icon for coatings, since we've changed the icon of the thing being coated ..() if (name == initial(name)) @@ -50,7 +51,7 @@ //same as plain meat /obj/item/weapon/reagent_containers/food/snacks/meat/corgi - name = "Corgi meat" + name = "corgi meat" desc = "Tastes like... well, you know." @@ -62,4 +63,4 @@ New() ..() reagents.remove_reagent("triglyceride", INFINITY) - //Chicken is low fat. Less total calories than other meats \ No newline at end of file + //Chicken is low fat. Less total calories than other meats diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index ebb346dc6e8..06c6bd648ac 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -33,6 +33,11 @@ if(istype(A, /obj/item/weapon/storage) || istype(A, /obj/structure/table) || istype(A, /obj/structure/closet) || istype(A, /obj/item/weapon/reagent_containers) || istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart)) return + if(istype(A, /mob)) + user.setClickCooldown(25) + else + user.setClickCooldown(4) + if(istype(A, /spell)) return @@ -53,7 +58,7 @@ playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) - user.setClickCooldown(4) + if(reagents.has_reagent("sacid")) message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].") diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index 501d168ab62..f867ef6077f 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -766,7 +766,7 @@ datum/design/item/experimental_welder name = "Experimental Welding Tool" desc = "A scientifically-enhanced welding tool that uses fuel-producing microbes to gradually replenish its fuel supply" id = "experimental_welder" - req_tech = list(ENGINEERING = 4, TECH_MATERIAL = 4) + req_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4) materials = list(DEFAULT_WALL_MATERIAL = 500) build_path =/obj/item/weapon/weldingtool/experimental sort_string = "VABAJ" diff --git a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm index 67ac1bd867f..232213c7ee6 100644 --- a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm +++ b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm @@ -1,21 +1,21 @@ //changes: rad protection up to 100 from 20/50 respectively /obj/item/clothing/suit/bio_suit/anomaly - name = "Anomaly suit" + name = "anomaly suit" desc = "A sealed bio suit capable of insulating against exotic alien energies." icon_state = "engspace_suit" item_state = "engspace_suit" armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 100) /obj/item/clothing/head/bio_hood/anomaly - name = "Anomaly hood" + name = "anomaly hood" desc = "A sealed bio hood capable of insulating against exotic alien energies." icon_state = "engspace_helmet" item_state = "engspace_helmet" armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 100) /obj/item/clothing/suit/space/anomaly - name = "Excavation suit" + name = "excavation suit" desc = "A pressure resistant excavation suit partially capable of insulating against exotic alien energies." icon_state = "cespace_suit" item_state = "cespace_suit" @@ -23,7 +23,7 @@ allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit) /obj/item/clothing/head/helmet/space/anomaly - name = "Excavation hood" + name = "excavation hood" desc = "A pressure resistant excavation hood partially capable of insulating against exotic alien energies." icon_state = "cespace_helmet" item_state = "cespace_helmet" diff --git a/code/modules/spells/artifacts.dm b/code/modules/spells/artifacts.dm index 6ef000cbe03..b2a59d86517 100644 --- a/code/modules/spells/artifacts.dm +++ b/code/modules/spells/artifacts.dm @@ -54,13 +54,16 @@ throw_speed = 5 throw_range = 10 w_class = 5 - flags = NOBLOODY + slot_flags = SLOT_BELT origin_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 8) attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") hitsound = 'sound/weapons/bladeslice.ogg' sharp = 1 edge = 1 - slot_flags = SLOT_BELT + base_reflectchance = 60 + base_block_chance = 60 + can_block_bullets = 1 + shield_power = 150 /obj/item/weapon/melee/energy/wizard/activate(mob/living/user) ..() @@ -90,23 +93,9 @@ return 1 -/* //commented until issues with sparks and sword blocking updates are merged -/obj/item/weapon/melee/energy/wizard/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - if(active && default_parry_check(user, attacker, damage_source) && prob(50)) - user.visible_message("\The [user] parries [attack_text] with \the [src]!") - - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, user.loc) - spark_system.start() - playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) - return 1 - - return 0 - */ - //skeleton weapons and armor -/obj/item/clothing/suit/bone +/obj/item/clothing/suit/armor/bone name = "bone armor" desc = "A rudimentary armor made of bones of several creatures." icon = 'icons/obj/necromancer.dmi' diff --git a/code/modules/spells/monster_manual.dm b/code/modules/spells/monster_manual.dm index 9d21d6c3fd6..59c53d1d6b1 100644 --- a/code/modules/spells/monster_manual.dm +++ b/code/modules/spells/monster_manual.dm @@ -9,17 +9,17 @@ var/uses = 1 var/temp = null var/list/monster = list(/mob/living/simple_animal/familiar/pet/cat, - /mob/living/simple_animal/familiar/pet/mouse, + /mob/living/simple_animal/mouse/familiar, /mob/living/simple_animal/familiar/carcinus, /mob/living/simple_animal/familiar/horror, /mob/living/simple_animal/familiar/goat, /mob/living/simple_animal/familiar/pike ) var/list/monster_info = list( "It is well known that the blackest of cats make good familiars.", - "Mice are full of mischief and magic. A simple animal, yes, but one of the wizard's finest.", + "Mice are small but fragile creatures. This one is gifted with unending life, and the ability to renew others.", "A mortal decendant of the original Carcinus, it is said their shells are near impenetrable and their claws as sharp as knives.", "A creature from other plane, its very own presence is enough to shatter the sanity of men.", - "A magical goat known for its healing powers and nearly-pacifist ways.", + "A stubborn and mischievous creature, this goat delights in stirring trouble.", "The more carnivorous and knowledge hungry cousin of the space carp. Keep away from books." ) diff --git a/code/modules/spells/targeted/necromancer_spells.dm b/code/modules/spells/targeted/necromancer_spells.dm index 54940aabb18..ab807ed024c 100644 --- a/code/modules/spells/targeted/necromancer_spells.dm +++ b/code/modules/spells/targeted/necromancer_spells.dm @@ -111,14 +111,14 @@ F.faction = usr.faction if(C.mob && C.mob.mind) C.mob.mind.transfer_to(F) - F << "You are skeleton minion to [usr], he is your master. Aid your master don't matter what, you have no free will." + F << "You are a skeleton minion to [usr], they are your master. Obey and protect your master at all costs, you have no free will." //equips the skeleton war gear F.equip_to_slot_or_del(new /obj/item/clothing/under/gladiator(F), slot_w_uniform) F.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(F), slot_shoes) F.equip_to_slot_or_del(new /obj/item/weapon/material/twohanded/spear/bone(F), slot_back) F.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/bone(F), slot_head) - F.equip_to_slot_or_del(new /obj/item/clothing/suit/bone(F), slot_wear_suit) + F.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/bone(F), slot_wear_suit) /spell/targeted/raise_dead/proc/get_player() for(var/mob/O in dead_mob_list) diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm index 131cca980ef..bf08fa1d8c3 100644 --- a/code/modules/supermatter/supermatter.dm +++ b/code/modules/supermatter/supermatter.dm @@ -98,7 +98,7 @@ /obj/machinery/power/supermatter/Destroy() - qdel(radio) + QDEL_NULL(radio) . = ..() /obj/machinery/power/supermatter/proc/explode() diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm index 25addbd40a4..1ba5179fd88 100644 --- a/code/modules/surgery/bones.dm +++ b/code/modules/surgery/bones.dm @@ -6,7 +6,7 @@ /datum/surgery_step/glue_bone allowed_tools = list( /obj/item/weapon/bonegel = 100, \ - /obj/item/weapon/screwdriver = 75 + /obj/item/weapon/tape_roll = 60 ) can_infect = 1 blood_level = 1 @@ -18,7 +18,7 @@ if (!hasorgans(target)) return 0 var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && !(affected.status & ORGAN_ROBOT) && affected.open >= 2 && affected.stage == 0 + return affected && !(affected.status & ORGAN_ROBOT) && affected.open >= 2 && affected.open < 3 && affected.stage == 0 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) @@ -115,7 +115,7 @@ /datum/surgery_step/finish_bone allowed_tools = list( /obj/item/weapon/bonegel = 100, \ - /obj/item/weapon/screwdriver = 75 + /obj/item/weapon/tape_roll = 60 ) can_infect = 1 blood_level = 1 @@ -127,7 +127,7 @@ if (!hasorgans(target)) return 0 var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.open >= 2 && !(affected.status & ORGAN_ROBOT) && affected.stage == 2 + return affected && affected.open >= 2 && affected.open < 3 && !(affected.status & ORGAN_ROBOT) && affected.stage == 2 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index 762c2b71c46..fbd1e8b8d89 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -17,7 +17,9 @@ /datum/surgery_step/open_encased/saw allowed_tools = list( - /obj/item/weapon/circular_saw = 100, \ + /obj/item/weapon/circular_saw = 100, + /obj/item/weapon/melee/energy = 100, + /obj/item/weapon/melee/chainsword = 70, /obj/item/weapon/material/hatchet = 75 ) @@ -172,7 +174,7 @@ affected.createwound(BRUISE, 20) affected.fracture() - + if(affected.internal_organs && affected.internal_organs.len) if(prob(40)) var/obj/item/organ/O = pick(affected.internal_organs) //TODO weight by organ size @@ -182,7 +184,7 @@ /datum/surgery_step/open_encased/mend allowed_tools = list( /obj/item/weapon/bonegel = 100, \ - /obj/item/weapon/screwdriver = 75 + /obj/item/weapon/tape_roll = 60 ) min_duration = 20 diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index 70c40a002bc..31caab1822e 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -78,7 +78,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] opens the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ "You open the maintenance hatch on [target]'s [affected.name] with \the [tool].") - affected.open = 2 + affected.open = 3 fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) @@ -134,7 +134,7 @@ var/obj/item/weapon/weldingtool/welder = tool if(!welder.isOn() || !welder.remove_fuel(1,user)) return 0 - return affected && affected.open == 2 && affected.brute_dam > 0 && target_zone != "mouth" + return affected && affected.open == 3 && affected.brute_dam > 0 && target_zone != "mouth" begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) @@ -166,7 +166,7 @@ if(..()) var/obj/item/stack/cable_coil/C = tool var/obj/item/organ/external/affected = target.get_organ(target_zone) - var/limb_can_operate = (affected && affected.open == 2 && affected.burn_dam > 0 && target_zone != "mouth") + var/limb_can_operate = (affected && affected.open == 3 && affected.burn_dam > 0 && target_zone != "mouth") if(limb_can_operate) if(istype(C)) if(!C.get_amount() >= 3) @@ -205,17 +205,17 @@ max_duration = 90 can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if (!hasorgans(target)) return var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(!affected) return + if(!affected) + return var/is_organ_damaged = 0 for(var/obj/item/organ/I in affected.internal_organs) if(I.damage > 0 && I.robotic >= 2) is_organ_damaged = 1 break - return affected.open == 2 && is_organ_damaged + return affected.open == 3 && is_organ_damaged begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -375,7 +375,7 @@ var/obj/item/device/mmi/M = tool var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(!(affected && affected.open == 2)) + if(!(affected && affected.open == 3)) return 0 if(!istype(M)) diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index e582d1222f7..30d9e86f8a1 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -110,6 +110,7 @@ proc/do_surgery(mob/living/carbon/M, mob/living/user, obj/item/tool) if (user.a_intent == I_HELP) user << "You can't see any useful way to use [tool] on [M]." + return 1 //Prevents attacking your patient on help intent return 0 proc/sort_surgeries() diff --git a/code/modules/telesci/bscrystal.dm b/code/modules/telesci/bscrystal.dm index 2f06ac3c1bc..e9de80093c6 100644 --- a/code/modules/telesci/bscrystal.dm +++ b/code/modules/telesci/bscrystal.dm @@ -6,7 +6,7 @@ icon = 'icons/obj/telescience.dmi' icon_state = "bluespace_crystal" w_class = 1 - origin_tech = "bluespace=4;materials=3" + origin_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 3) var/blink_range = 8 // The teleport range when crushed/thrown at someone. @@ -42,5 +42,5 @@ /obj/item/bluespace_crystal/artificial name = "artificial bluespace crystal" desc = "An artificially made bluespace crystal, it looks delicate." - origin_tech = "bluespace=2" + origin_tech = list(TECH_BLUESPACE = 2) blink_range = 4 // Not as good as the organic stuff! diff --git a/code/modules/telesci/gps.dm b/code/modules/telesci/gps.dm index 6271a79a6dd..3ea12461f42 100644 --- a/code/modules/telesci/gps.dm +++ b/code/modules/telesci/gps.dm @@ -6,7 +6,7 @@ var/list/GPS_list = list() icon_state = "gps-c" w_class = 2 slot_flags = SLOT_BELT - origin_tech = "programming=2;engineering=2" + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) var/gpstag = "COM0" var/emped = 0 var/turf/locked_location diff --git a/code/modules/telesci/telepad.dm b/code/modules/telesci/telepad.dm index 2317c4775b9..565a67f6f4b 100644 --- a/code/modules/telesci/telepad.dm +++ b/code/modules/telesci/telepad.dm @@ -94,7 +94,7 @@ icon = 'icons/obj/radio.dmi' icon_state = "beacon" item_state = "signaler" - origin_tech = "bluespace=3" + origin_tech = list(TECH_BLUESPACE = 3) /obj/item/device/telepad_beacon/attack_self(mob/user) if(user) diff --git a/config/example/config.txt b/config/example/config.txt index 7f730bef569..6082e8703e9 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -162,7 +162,8 @@ VOTE_AUTOGAMEMODE_TIMELEFT 100 ## min delay (deciseconds) before a transfer vote can be called (default 120 minutes) TRANSFER_TIMEOUT 72000 -## prevents dead players from voting or starting votes +## Prevets lobby-sitters and ghosts who went straight from the lobby to observing from voting. +## Ghosts who died will still be able to vote. #NO_DEAD_VOTE ## players' votes default to "No vote" (otherwise, default to "No change") diff --git a/config/example/discord.txt b/config/example/discord.txt index c7725c4f755..ea66b2cc9ab 100644 --- a/config/example/discord.txt +++ b/config/example/discord.txt @@ -7,3 +7,6 @@ ## Uncomment this to enable robust debugging. ## This results in more messages being sent via log_debug() during bot operations. # ROBUST_DEBUG + +## The subscriber role ID goes here. +# SUBSCRIBER diff --git a/config/example/tips.txt b/config/example/tips.txt index 1291e1d4240..5683ad344bc 100644 --- a/config/example/tips.txt +++ b/config/example/tips.txt @@ -12,11 +12,11 @@ You can grab someone by clicking on them with the grab intent, then upgrade the Holding alt and left clicking a tile will allow you to see its contents in the top right window pane, which is much faster than right clicking. The resist button will allow you to resist out of handcuffs, being buckled to a chair or bed, out of locked lockers and more. Whenever you're stuck, try resisting! You can move an item out of the way by dragging it and then clicking on an adjacent tile with an empty hand. -Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using.There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more! +Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using. There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more! As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your unique lasgun or your life are things to worry about. As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban. As the Chief Medical Officer, your hypospray is like an instant injection syringe that can hold 30 units as opposed to the standard 15. -As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and EMTs during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting. +As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and EMTs during a pirate raid, blob infestation, or some other crisis to keep people alive and fighting. As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, it was caused by something unnatural. As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva. As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone. @@ -24,8 +24,8 @@ As a Chemist, there are dozens of chemicals that can heal, and even more that ca As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently. As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, and then from there into an AI system integrity restorer computer to revive and/or repair them. As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled. -As a Xenoscientist, you can inject yourself with the mutation toxin extracted from green slimes to become a slime person, who will never be attacked by slimes! -As a Xenoscientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract. +As a Xenobiologist, you can inject yourself with the mutation toxin extracted from green slimes to become a slime person, who will never be attacked by slimes! +As a Xenobiologist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract. As a Scientist, researchable machine parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions. As a Scientist, the teleporter in Misc research can be set-up to teleport across the whole station! All you need to do is crack the formula. As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil. @@ -40,8 +40,6 @@ As the Chief Engineer, you can rename areas or create entirely new ones using yo As the Research Director, you can spy on and even forge PDA communications with the message monitor console! The key is in your office. As an Engineer, the supermatter shard is an extremely dangerous piece of equipment: touching it will disintegrate you. As an Engineer, you can electrify grilles by placing wire "nodes" beneath them: the big seemingly unconnected bulges from a half completed wiring job. -As an Engineer, you can power the station solely with the solar arrays. While uninteresting, it is a much safer alternative to most other engines. -As an Engineer, you can repair windows by using a welding tool on them while on any intent other than harm. As an Engineer, you can lock emitters using your ID card to prevent others from disabling them. As an Atmospheric Technician, you can't unwrench a pipe if the pressure within is too high. As the Head of Security, you are expected to coordinate your security force to handle any threat that comes to the station. Sometimes it means making use of the armory to handle a blob, sometimes it means being ruthless during a revolution or cult. @@ -80,11 +78,11 @@ As a Traitor, the Captain and the Head of Security are two of the most difficult As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool. As a Traitor, you may sometimes hunt other traitors, and in turn be hunted by them. As a Traitor, the syndicate encryption key is very useful for coordinating plans with your fellow traitors -- or, of course, betraying them. -As a Nuclear Operative, communication is key! Use your radio to speak to your fellow operatives and coordinate an attack plan. -As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, are immune to conventional stuns, and can easily take down the AI. -As a Nuclear Operative, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire. -As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life. -As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however. +As a Mercenary, communication is key! Use your radio to speak to your fellow operatives and coordinate an attack plan. +As a Mercenary, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, are immune to conventional stuns, and can easily take down the AI. +As a Mercenary, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire. +As a Mercenary, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life. +As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however. As a Monkey, you can still wear a few human items, such as backpacks, gas masks and hats, and still have two free hands. As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them. Make sure to hunt down all those laptops too! As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation! @@ -134,38 +132,44 @@ Remember the cheesy line! Toolboxes do more damage if they are full of things, but their contents will spill when you use them as a weapon. Heads of Staff will be more willing to help you if you bring paperwork that's already filled out. See no evil, hear no evil, speak no evil. -Auto-Hiss, despite the name, can be used for Unathi, Tajara, and Vaurca. +Despite the name, Auto-Hiss can be used for Unathi, Tajara, and Vaurca. Service borgs can use the special maidborg sprite if they pray hard enough. -Chainswords and energy weapons can slice walls and people. +Chainswords and energy weapons can slice both walls and people. If you see this message something has gone seriously wrong. If you're having trouble as an antagonist, consider a Dionaea whitelist. As a Medical Doctor, you can attach limbs from one species to the torso of another species. You too can make your own Frankenstein monster! The second antag contest is still running, you know. Killing mice on sight is not and never will be gank, no matter how much people complain. -As an Unathi, you are the only species capable of wearing the rare Breacher hardsuits. +Unathi are the only species capable of wearing the rare Breacher hardsuits. As an Unathi, you can devour small mobs after some time. -As a Tajaran, you move pretty fast. Zoom zoom, kitty. -As a Tajaran, your resistance to cold probably doesn't actually help you in space. Feel free to try, though. -As a Skrell you can look pretty and...uhh...not slip? -As a Skrell you have free reign to validhunt synthetics. (Not really, please don't do this oh God what have I done). -As a Human you are the best. Why do you care about your mechanics? -As a Human you are really very great. -As an IPC you are immune to most chemicals and gasses. -As an IPC you can survive longer than most species in space, despite your supposed "weakness". -As a Dionaea you can survive pretty much anything except a tiny little bottle of weedkiller. -As a Dionaea you will die in darkness. Find the light at the end of the tunnel, and quick. -As a Vaurca you can remotely speak to any other Vaurca on board. Not that there are any. -As a Vaurca you can wade freely through phoron gas. Avoid phoron fires though. Somehow a species that breathes phoron gas is really weak to fire. +As a Tajara, you move pretty fast. Zoom zoom, kitty. +As a Tajara, your resistance to cold probably doesn't actually help you in space. Feel free to try, though. +As a Skrell, you can look pretty and...uhh...not slip? +As a Skrell, you have free reign to validhunt synthetics. (Not really, please don't do this oh God what have I done). +As a Human, you are the best. Why do you care about your mechanics? +As a Human, you are really very great. +Due to IPCs' synthetic nature, they're immune to most chemicals and gasses. +IPCs can survive longer than most species in space, despite their supposed "weakness". +As a Dionaea, you can survive pretty much anything except a tiny little bottle of weedkiller. +Dionae die in darkness. Find the light at the end of the tunnel, and quick. +All Vaurca can remotely speak to any other Vaurca on board. Not that there are any. +Vaurca can wade freely through phoron gas. Avoid phoron fires though. Somehow a species that breathes phoron gas is really weak to fire. As an ERT trooper, your most powerful weapons are your team mates. Your second most powerful weapon is your bigass gun. -As an ERT trooper you're still expected to roleplay and progress the round. +ERT troopers are still expected to roleplay and progress the round. Try not to wordlessly gun down everyone you see. As a Ninja, you should learn the difference between invisibility and invulnerability. As a Ninja, you have a pretty badass sword. Use it. -As a Cortical Borer, you a limp feather can kill you if you're outside of a host. -As a NanoTrasen Actor you can't do anything. Thank Bay. +A Ninja's sword can cut through many objects. Experiment! +As a Cortical Borer, a limp feather can kill you if you're outside of a host. +NanoTrasen Actors can't do anything. Thank Bay. As a Syndicate Commando you are a Nuke Operative with bigger and better guns. Use them. As a Death Commando you have only one course of action: RIP AND TEAR. As a Highlander, there can be only one. As a Loyalist, remember that you are an antagonist too! As a Renegade, consider playing a better gamemode. As a Vampire, you can create new vampires out of willing and less than willing crew. Mind that new vampires may decide to turn their powers against you. -As a Vampire, if you start going hungry for blood don't expect to stay hidden for long. \ No newline at end of file +As a Vampire, if you start going hungry for blood don't expect to stay hidden for long. +You can use . (period) instead of : to speak into a radio. +The radio key .i will allow you to speak into a nearby intercom, .r will speak into a radio in your right hand, and .l will speak into your left. The microphone does not need to be enabled for this to work. +Your ID card's access determines what departmental channels you can set intercoms to. +You can fax papers between request consoles by attacking the console with a paper. Make sure the paper tray is closed first! +No wall or window is 100% impervious to heat. diff --git a/html/changelog.html b/html/changelog.html index 7fff4929a01..b3abe25e263 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -1,7 +1,7 @@ - + - Baystation 12 Changelog + Aurorastation Changelog