diff --git a/code/__defines/_compile_options.dm b/code/___compile_options.dm similarity index 61% rename from code/__defines/_compile_options.dm rename to code/___compile_options.dm index 0c60ba0a5ddb..a4f54bc99b94 100644 --- a/code/__defines/_compile_options.dm +++ b/code/___compile_options.dm @@ -1,7 +1,3 @@ -// The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary. -// 1 will enable set background. 0 will disable set background. -#define BACKGROUND_ENABLED 0 - // If REFTRACK_IN_CI is defined, the reftracker will run in CI. #define REFTRACK_IN_CI #if defined(REFTRACK_IN_CI) && defined(UNIT_TEST) && !defined(SPACEMAN_DMM) diff --git a/code/__defines/ZAS.dm b/code/__defines/ZAS.dm index 59466d88b53d..6734ee68ffb1 100644 --- a/code/__defines/ZAS.dm +++ b/code/__defines/ZAS.dm @@ -57,29 +57,25 @@ } #ifdef MULTIZAS - -var/global/list/csrfz_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTHUP, EASTUP, WESTUP, SOUTHUP, NORTHDOWN, EASTDOWN, WESTDOWN, SOUTHDOWN) -var/global/list/gzn_check = list(NORTH, SOUTH, EAST, WEST, UP, DOWN) +#define ZAS_CSRFZ_CHECK global.cornerdirsz +#define ZAS_GZN_CHECK global.cardinalz #define ATMOS_CANPASS_TURF(ret, A, B) \ if (A.blocks_air & AIR_BLOCKED || B.blocks_air & AIR_BLOCKED) { \ ret = BLOCKED; \ } \ - else if (B.z != A.z) { \ - if (B.z < A.z) { \ - ret = (A.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \ - } \ - else { \ - ret = (B.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \ - } \ + else if (B.z < A.z) { \ + ret = (A.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \ } \ - else if (A.blocks_air & ZONE_BLOCKED || B.blocks_air & ZONE_BLOCKED) { \ - ret = (A.z == B.z) ? ZONE_BLOCKED : AIR_BLOCKED; \ + else if(B.z > A.z) { \ + ret = (B.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \ } \ - else if (A.contents.len) { \ + else if ((A.blocks_air & ZONE_BLOCKED) || (B.blocks_air & ZONE_BLOCKED)) { \ + ret = ZONE_BLOCKED; \ + } \ + else if (length(A.contents)) { \ ret = 0;\ - for (var/thing in A) { \ - var/atom/movable/AM = thing; \ + for (var/atom/movable/AM as anything in A) { \ ATMOS_CANPASS_MOVABLE(ret, AM, B); \ if (ret == BLOCKED) { \ break;\ @@ -88,8 +84,8 @@ var/global/list/gzn_check = list(NORTH, SOUTH, EAST, WEST, UP, DOWN) } #else -var/global/list/csrfz_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) -var/global/list/gzn_check = list(NORTH, SOUTH, EAST, WEST) +#define ZAS_CSRFZ_CHECK global.cornerdirs +#define ZAS_GZN_CHECK global.cardinal #define ATMOS_CANPASS_TURF(ret, A, B) \ if (A.blocks_air & AIR_BLOCKED || B.blocks_air & AIR_BLOCKED) { \ @@ -98,7 +94,7 @@ var/global/list/gzn_check = list(NORTH, SOUTH, EAST, WEST) else if (A.blocks_air & ZONE_BLOCKED || B.blocks_air & ZONE_BLOCKED) { \ ret = ZONE_BLOCKED; \ } \ - else if (A.contents.len) { \ + else if (length(A.contents)) { \ ret = 0;\ for (var/thing in A) { \ var/atom/movable/AM = thing; \ diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm index 97d331623d18..169309b2dfdc 100644 --- a/code/__defines/flags.dm +++ b/code/__defines/flags.dm @@ -84,7 +84,7 @@ The latter will result in a linter warning and will not work correctly. #define ITEM_FLAG_NOCUFFS BITFLAG(11) // Gloves that have this flag prevent cuffs being applied #define ITEM_FLAG_CAN_HIDE_IN_SHOES BITFLAG(12) // Items that can be hidden in shoes that permit it #define ITEM_FLAG_PADDED BITFLAG(13) // When set on gloves, will act like pulling punches in unarmed combat. -#define ITEM_FLAG_CAN_TAPE BITFLAG(14) // Whether the item can be be taped onto something using tape +#define ITEM_FLAG_CAN_TAPE BITFLAG(14) // Whether the item can be taped onto something using tape #define ITEM_FLAG_IS_WEAPON BITFLAG(15) // Item is considered a weapon. Currently only used for force-based worth calculation. // Flags for pass_flags (/atom/var/pass_flags) diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm index 680717a8e9ad..b14c47d5768c 100644 --- a/code/__defines/gamemode.dm +++ b/code/__defines/gamemode.dm @@ -3,7 +3,7 @@ #define CHOOSE_GAMEMODE_RETRY 2 // The gamemode could not be chosen; we will use the next most popular option voted in, or the default. #define CHOOSE_GAMEMODE_REVOTE 3 // The gamemode could not be chosen; we need to have a revote. #define CHOOSE_GAMEMODE_RESTART 4 // The gamemode could not be chosen; we will restart the server. -#define CHOOSE_GAMEMODE_SILENT_REDO 5 // The gamemode could not be chosen; we request to have the the proc rerun on the next tick. +#define CHOOSE_GAMEMODE_SILENT_REDO 5 // The gamemode could not be chosen; we request to have the proc rerun on the next tick. //End game state, to manage round end. #define END_GAME_NOT_OVER 1 diff --git a/code/__defines/item_effects.dm b/code/__defines/item_effects.dm new file mode 100644 index 000000000000..d5c79b402f9a --- /dev/null +++ b/code/__defines/item_effects.dm @@ -0,0 +1,15 @@ +// Identifiers for various categories of item effects. +#define IE_CAT_DAMAGE "weff_damage" +#define IE_CAT_STRIKE "weff_strike" +#define IE_CAT_PARRY "weff_parry" +#define IE_CAT_USED "weff_used" +#define IE_CAT_WIELDED "weff_wield" +#define IE_CAT_VISUAL "weff_visual" +#define IE_CAT_LISTENER "weff_listener" +#define IE_CAT_EXAMINE "weff_visible" +#define IE_CAT_RANGED "weff_ranged" +#define IE_CAT_PROCESS "weff_process" + +// Identifiers for parameters for item effects. +#define IE_PAR_USES "uses" +#define IE_PAR_MAX_USES "max_uses" diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm index fa9cf0a8debe..1d2654f16d2c 100644 --- a/code/__defines/qdel.dm +++ b/code/__defines/qdel.dm @@ -21,21 +21,25 @@ #define GC_QUEUE_ITEM_GCD_DESTROYED 3 //! Item's gc_destroyed var value. Used to detect ref reuse. #define GC_QUEUE_ITEM_INDEX_COUNT 3 //! Number of item indexes, used for allocating the nested lists. Don't forget to increase this if you add a new queue item index -#define GC_QUEUED_FOR_HARD_DEL -1 -#define GC_CURRENTLY_BEING_QDELETED -2 +// Defines for the time an item has to get its reference cleaned before it fails the queue and moves to the next. +#define GC_FILTER_QUEUE (1 SECONDS) +#define GC_CHECK_QUEUE (5 MINUTES) +#define GC_DEL_QUEUE (10 SECONDS) + +#define GC_CURRENTLY_BEING_QDELETED -1 #define QDELING(X) (X.gc_destroyed) #define QDELETED(X) (isnull(X) || QDELING(X)) #define QDESTROYING(X) (isnull(X) || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) //Qdel helper macros. -#define QDEL_IN(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, TYPE_PROC_REF(/datum, qdel_self)), time, TIMER_STOPPABLE)} -#define QDEL_IN_CLIENT_TIME(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, TYPE_PROC_REF(/datum, qdel_self)), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME)} +#define QDEL_IN(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, TYPE_PROC_REF(/datum, qdel_self)), time)} +#define QDEL_IN_CLIENT_TIME(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, TYPE_PROC_REF(/datum, qdel_self)), time, TIMER_CLIENT_TIME)} #define QDEL_NULL(item) if(item) {qdel(item); item = null} #define QDEL_NULL_SCREEN(item) if(client) { client.screen -= item; }; QDEL_NULL(item) #define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) }}; if(x) {x.Cut(); x = null } // Second x check to handle items that LAZYREMOVE on qdel. #define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); } -#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(______qdel_list_wrapper), L), time, TIMER_STOPPABLE) +#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(______qdel_list_wrapper), L), time) #define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); } #define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); } diff --git a/code/__defines/research.dm b/code/__defines/research.dm index 2fb5ac649e4c..3898d8dc2958 100644 --- a/code/__defines/research.dm +++ b/code/__defines/research.dm @@ -19,7 +19,8 @@ #define HOLLOW_OBJECT_MATTER_MULTIPLIER 0.05 #define BASE_OBJECT_MATTER_MULTPLIER 0.25 -#define GENERIC_SMELTING_HEAT_POINT 1350 CELSIUS +#define LOW_SMELTING_HEAT_POINT 1150 CELSIUS // Reachable with coal in a kiln on the medieval maps. +#define GENERIC_SMELTING_HEAT_POINT 1350 CELSIUS // Reachable with coal and a bellows in a kiln on medieval maps. #define HIGH_SMELTING_HEAT_POINT 4000 CELSIUS // must be at least 4074K (3800 C) to melt graphite #define TECH_MATERIAL "materials" diff --git a/code/__defines/species.dm b/code/__defines/species.dm index 0ff09486031d..791e81cd17d3 100644 --- a/code/__defines/species.dm +++ b/code/__defines/species.dm @@ -8,6 +8,7 @@ #define SPECIES_FLAG_NO_BLOCK BITFLAG(6) // Unable to block or defend itself from attackers. #define SPECIES_FLAG_NEED_DIRECT_ABSORB BITFLAG(7) // This species can only have their DNA taken by direct absorption. #define SPECIES_FLAG_LOW_GRAV_ADAPTED BITFLAG(8) // This species is used to lower than standard gravity, affecting stamina in high-grav +#define SPECIES_FLAG_ABSORB_ELECTRICITY BITFLAG(9) // This species can absorb electricity; snowflake flag for old slime people. // Species spawn flags #define SPECIES_IS_WHITELISTED BITFLAG(0) // Must be whitelisted to play. diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index c9880741fa9e..13861c4d9f5d 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -1,7 +1,6 @@ #define INITIALIZATION_INSSATOMS 0 //New should not call Initialize -#define INITIALIZATION_INSSATOMS_LATE 1 //New should not call Initialize; after the first pass is complete (handled differently) -#define INITIALIZATION_INNEW_MAPLOAD 2 //New should call Initialize(TRUE) -#define INITIALIZATION_INNEW_REGULAR 3 //New should call Initialize(FALSE) +#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE) +#define INITIALIZATION_INNEW_REGULAR 2 //New should call Initialize(FALSE) #define INITIALIZE_HINT_NORMAL 0 //Nothing happens #define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm index b665a162e7ba..c6d4b7ea49ff 100644 --- a/code/_helpers/files.dm +++ b/code/_helpers/files.dm @@ -1,7 +1,7 @@ //Sends resource files to client cache /client/proc/getFiles() for(var/file in args) - direct_output(src, browse_rsc(file)) + send_rsc(src, file, null) /client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm")) var/path = root diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index 5c78a7dd62f9..ee74c5f11efe 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -163,7 +163,7 @@ mob // Send the icon to src's local cache send_rsc(src, getFlatIcon(src), iconName) // Display the icon in their browser - direct_output(src, browse("

")) + show_browser(src, "

") Output_Icon() set name = "2. Output Icon" diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index b8cf7af8f123..5c1744b0178f 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -26,7 +26,7 @@ var/global/log_end= world.system_type == UNIX ? ascii2text(13) : "" to_world_log("## TESTING: [msg][log_end]") /proc/game_log(category, text) - direct_output(diary, "\[[time_stamp()]] [game_id] [category]: [text][log_end]") + to_file(diary, "\[[time_stamp()]] [game_id] [category]: [text][log_end]") /proc/log_admin(text) global.admin_log.Add(text) diff --git a/code/_helpers/profiling.dm b/code/_helpers/profiling.dm index ad16a2c2d279..0c4785568368 100644 --- a/code/_helpers/profiling.dm +++ b/code/_helpers/profiling.dm @@ -71,7 +71,7 @@ lines += "[entry] => [num2text(data[STAT_ENTRY_TIME], 10)]ms ([data[STAT_ENTRY_COUNT]]) (avg:[num2text(data[STAT_ENTRY_TIME]/(data[STAT_ENTRY_COUNT] || 1), 99)])" if (user) - direct_output(user, browse("
  1. [lines.Join("
  2. ")]
", "window=[url_encode("stats:[ref(stats)]")]")) + show_browser(user, "
  1. [lines.Join("
  2. ")]
", "window=[url_encode("stats:[ref(stats)]")]") . = lines.Join("\n") diff --git a/code/_helpers/sorts/__main.dm b/code/_helpers/sorts/__main.dm index 09bb861f6477..391630171eba 100644 --- a/code/_helpers/sorts/__main.dm +++ b/code/_helpers/sorts/__main.dm @@ -169,7 +169,7 @@ reverse a descending sequence without violating stability. var/r = 0 //becomes 1 if any bits are shifted off while(n >= MIN_MERGE) r |= (n & 1) - n >>= 1 + n = BITSHIFT_RIGHT(n, 1) return n + r //Examines the stack of runs waiting to be merged and merges adjacent runs until the stack invariants are reestablished: diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 32eac707ce72..88f8f402528e 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -692,23 +692,17 @@ Turf and target are seperate in case you want to teleport some distance from a t return zone_to_descriptor_mapping[zone] || zone //Whether or not the given item counts as sharp in terms of dealing damage -/proc/is_sharp(obj/O) - if (!O) return 0 - if (O.sharp) return 1 - if (O.edge) return 1 - return 0 +/obj/proc/is_sharp() + return FALSE //Whether or not the given item counts as cutting with an edge in terms of removing limbs -/proc/has_edge(obj/O) - if (!O) return 0 - if (O.edge) return 1 - return 0 - +/obj/proc/has_edge() + return FALSE //For items that can puncture e.g. thick plastic but aren't necessarily sharp //Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape. /obj/item/proc/can_puncture() - return sharp + return is_sharp() /obj/item/screwdriver/can_puncture() return 1 diff --git a/code/_macros.dm b/code/_macros.dm index 5cba5893825f..11e6c146b5d5 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -106,9 +106,12 @@ #define show_image(target, image) target << (image) #define send_rsc(target, rsc_content, rsc_name) target << browse_rsc(rsc_content, rsc_name) #define open_link(target, url) target << link(url) +#define ftp_to(target, file_entry, suggested_name) target << ftp(file_entry, suggested_name) +#define open_file_for(target, file) target << run(file) #define to_savefile(target, key, value) target[(key)] << (value) #define from_savefile(target, key, value) target[(key)] >> (value) #define to_output(target, output_content, output_args) target << output((output_content), (output_args)) +// Avoid using this where possible, prefer the other helpers instead. #define direct_output(target, value) target << (value) /proc/html_icon(var/thing) // Proc instead of macro to avoid precompiler problems. @@ -147,34 +150,35 @@ #define SPAN_STYLE(S, X) "[X]" #define SPAN_CLASS(C, X) "[X]" -#define SPAN_ITALIC(X) SPAN_CLASS("italic", X) -#define SPAN_BOLD(X) SPAN_CLASS("bold", X) -#define SPAN_NOTICE(X) SPAN_CLASS("notice", X) -#define SPAN_WARNING(X) SPAN_CLASS("warning", X) -#define SPAN_DANGER(X) SPAN_CLASS("danger", X) -#define SPAN_ROSE(X) SPAN_CLASS("rose", X) -#define SPAN_OCCULT(X) SPAN_CLASS("cult", X) -#define SPAN_MFAUNA(X) SPAN_CLASS("mfauna", X) -#define SPAN_SUBTLE(X) SPAN_CLASS("subtle", X) -#define SPAN_INFO(X) SPAN_CLASS("info", X) -#define SPAN_RED(X) SPAN_CLASS("font_red", X) -#define SPAN_ORANGE(X) SPAN_CLASS("font_orange", X) -#define SPAN_YELLOW(X) SPAN_CLASS("font_yellow", X) -#define SPAN_GREEN(X) SPAN_CLASS("font_green", X) -#define SPAN_BLUE(X) SPAN_CLASS("font_blue", X) -#define SPAN_VIOLET(X) SPAN_CLASS("font_violet", X) -#define SPAN_PURPLE(X) SPAN_CLASS("font_purple", X) -#define SPAN_GREY(X) SPAN_CLASS("font_grey", X) -#define SPAN_MAROON(X) SPAN_CLASS("font_maroon", X) -#define SPAN_PINK(X) SPAN_CLASS("font_pink", X) -#define SPAN_PALEPINK(X) SPAN_CLASS("font_palepink", X) -#define SPAN_SINISTER(X) SPAN_CLASS("sinister", X) -#define SPAN_MODERATE(X) SPAN_CLASS("moderate", X) +#define SPAN_ITALIC(X) SPAN_CLASS("italic", X) +#define SPAN_BOLD(X) SPAN_CLASS("bold", X) +#define SPAN_NOTICE(X) SPAN_CLASS("notice", X) +#define SPAN_WARNING(X) SPAN_CLASS("warning", X) +#define SPAN_DANGER(X) SPAN_CLASS("danger", X) +#define SPAN_ROSE(X) SPAN_CLASS("rose", X) +#define SPAN_OCCULT(X) SPAN_CLASS("cult", X) +#define SPAN_CULT_ANNOUNCE(X) SPAN_CLASS("cultannounce", X) +#define SPAN_MFAUNA(X) SPAN_CLASS("mfauna", X) +#define SPAN_SUBTLE(X) SPAN_CLASS("subtle", X) +#define SPAN_INFO(X) SPAN_CLASS("info", X) +#define SPAN_RED(X) SPAN_CLASS("font_red", X) +#define SPAN_ORANGE(X) SPAN_CLASS("font_orange", X) +#define SPAN_YELLOW(X) SPAN_CLASS("font_yellow", X) +#define SPAN_GREEN(X) SPAN_CLASS("font_green", X) +#define SPAN_BLUE(X) SPAN_CLASS("font_blue", X) +#define SPAN_VIOLET(X) SPAN_CLASS("font_violet", X) +#define SPAN_PURPLE(X) SPAN_CLASS("font_purple", X) +#define SPAN_GREY(X) SPAN_CLASS("font_grey", X) +#define SPAN_MAROON(X) SPAN_CLASS("font_maroon", X) +#define SPAN_PINK(X) SPAN_CLASS("font_pink", X) +#define SPAN_PALEPINK(X) SPAN_CLASS("font_palepink", X) +#define SPAN_SINISTER(X) SPAN_CLASS("sinister", X) +#define SPAN_MODERATE(X) SPAN_CLASS("moderate", X) // placeholders -#define SPAN_GOOD(X) SPAN_GREEN(X) -#define SPAN_NEUTRAL(X) SPAN_BLUE(X) -#define SPAN_BAD(X) SPAN_RED(X) -#define SPAN_HARDSUIT(X) SPAN_BLUE(X) +#define SPAN_GOOD(X) SPAN_GREEN(X) +#define SPAN_NEUTRAL(X) SPAN_BLUE(X) +#define SPAN_BAD(X) SPAN_RED(X) +#define SPAN_HARDSUIT(X) SPAN_BLUE(X) #define CSS_CLASS_RADIO "radio" @@ -194,4 +198,8 @@ #define FONT_GIANT(X) "[X]" -#define PRINT_STACK_TRACE(X) get_stack_trace(X, __FILE__, __LINE__) \ No newline at end of file +#define PRINT_STACK_TRACE(X) get_stack_trace(X, __FILE__, __LINE__) + +/// Checks if potential_weakref is a weakref of thing. +/// NOTE: These argments are the opposite order of TG's, because I think TG's are counterintuitive. +#define IS_WEAKREF_OF(potential_weakref, thing) (istype(thing, /datum) && !isnull(potential_weakref) && thing.weakref == potential_weakref) \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 6a254d2fa03a..90653cccc970 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -282,10 +282,10 @@ return A.CtrlClick(src) /atom/proc/CtrlClick(var/mob/user) - if(loc == user) + if(get_recursive_loc_of_type(/mob) == user) var/decl/interaction_handler/handler = get_quick_interaction_handler(user) if(handler) - var/using_item = user.get_active_held_item() || user.get_usable_hand_slot_organ() + var/using_item = user.get_active_held_item() if(handler.is_possible(src, user, using_item)) return handler.invoked(src, user, using_item) return FALSE diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 81f1abf89659..651c4d1e007f 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -1,6 +1,9 @@ /mob/living/silicon/ai hud_used = /datum/hud/ai +/datum/hud/ai + action_intent_type = null // no selector + /datum/hud/ai/FinalizeInstantiation() var/list/ai_hud_data = decls_repository.get_decls_of_subtype(/decl/ai_hud) for(var/elem_type in ai_hud_data) diff --git a/code/_onclick/hud/animal.dm b/code/_onclick/hud/animal.dm index 70b61dffe77b..8b372aabdcc6 100644 --- a/code/_onclick/hud/animal.dm +++ b/code/_onclick/hud/animal.dm @@ -11,6 +11,4 @@ move_intent = new(null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_MOVEMENT) move_intent.icon_state = mymob.move_intent.hud_icon_state adding += move_intent - action_intent = new(null, mymob, ui_style, ui_color, ui_alpha) - adding += action_intent ..() diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 34ee968ab77c..48829da57dda 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -30,10 +30,12 @@ var/list/hand_hud_objects var/list/swaphand_hud_objects - var/obj/screen/intent/action_intent var/obj/screen/movement/move_intent var/obj/screen/stamina/stamina_bar + var/action_intent_type = /obj/screen/intent + var/obj/screen/intent/action_intent + var/list/adding = list() var/list/other = list() var/list/hud_elements = list() @@ -118,9 +120,17 @@ return FALSE /datum/hud/proc/FinalizeInstantiation() + SHOULD_CALL_PARENT(TRUE) + + if(!action_intent && action_intent_type) // Everyone needs an intent selector. + action_intent = new action_intent_type(null, mymob) + adding |= action_intent + hud_elements |= action_intent + BuildInventoryUI() BuildHandsUI() + if(mymob.client) mymob.client.screen = list() if(length(hand_hud_objects)) @@ -133,6 +143,7 @@ mymob.client.screen |= adding if(length(hotkeybuttons)) mymob.client.screen |= hotkeybuttons + hide_inventory() /datum/hud/proc/get_ui_style_data() diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 44722373ecbd..7dc1d837d915 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -15,12 +15,6 @@ stamina_bar = new(null, mymob) adding += stamina_bar - // Draw the attack intent dialogue. - if(hud_data.show_intent_selector) - action_intent = new(null, mymob) - src.adding += action_intent - hud_elements |= action_intent - if(hud_data.has_m_intent) move_intent = new(null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_MOVEMENT) move_intent.icon_state = mymob.move_intent.hud_icon_state diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 2243f9e49232..b0680d9f047a 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -50,11 +50,6 @@ var/global/obj/screen/robot_inventory R.ui_drop_grab = new(null, mymob) adding += R.ui_drop_grab - //Intent - action_intent = new /obj/screen/intent/robot(null, mymob) - action_intent.icon_state = R.get_intent().icon_state - - adding += action_intent adding += new /obj/screen/robot_panel(null, mymob) adding += new /obj/screen/robot_store(null, mymob) diff --git a/code/_onclick/hud/screen/screen_credits.dm b/code/_onclick/hud/screen/screen_credits.dm index 5025cc7a87dc..2c04fffcf9a9 100644 --- a/code/_onclick/hud/screen/screen_credits.dm +++ b/code/_onclick/hud/screen/screen_credits.dm @@ -18,15 +18,17 @@ animate(src, transform = M, time = CREDIT_ROLL_SPEED) target = M animate(src, alpha = 255, time = CREDIT_EASE_DURATION, flags = ANIMATION_PARALLEL) - spawn(CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) - if(!QDELETED(src)) - animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) - sleep(CREDIT_EASE_DURATION) - qdel(src) + addtimer(CALLBACK(src, PROC_REF(ease_out)), CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) var/mob/owner = owner_ref?.resolve() if(istype(owner) && owner.client) owner.client.screen += src +/obj/screen/credit/proc/ease_out() + if(QDELETED(src)) + return + animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) + QDEL_IN_CLIENT_TIME(src, CREDIT_EASE_DURATION) + /obj/screen/credit/Destroy() var/client/P = parent if(istype(P)) diff --git a/code/_onclick/hud/screen/screen_inventory_hands.dm b/code/_onclick/hud/screen/screen_inventory_hands.dm index df5784067418..7dbdbf0b1525 100644 --- a/code/_onclick/hud/screen/screen_inventory_hands.dm +++ b/code/_onclick/hud/screen/screen_inventory_hands.dm @@ -1,7 +1,7 @@ /obj/screen/inventory/hand icon_state = "hand_base" -/obj/screen/inventory/hand/on_update_icon() +/obj/screen/inventory/hand/rebuild_screen_overlays() ..() diff --git a/code/_onclick/hud/screen/screen_robot_intent.dm b/code/_onclick/hud/screen/screen_robot_intent.dm deleted file mode 100644 index cff12b35ea97..000000000000 --- a/code/_onclick/hud/screen/screen_robot_intent.dm +++ /dev/null @@ -1,2 +0,0 @@ -/obj/screen/intent/robot - screen_loc = ui_acti diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 075995076d43..b92356b4a145 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -26,6 +26,8 @@ avoid code duplication. This includes items that may sometimes act as a standard // If TRUE, prevent afterattack from running. /obj/item/proc/resolve_attackby(atom/A, mob/user, var/click_params) + if(!user.check_dexterity(get_required_attack_dexterity(user, A))) + return TRUE if(!(item_flags & ITEM_FLAG_NO_PRINT)) add_fingerprint(user) return A.attackby(src, user, click_params) @@ -85,7 +87,7 @@ avoid code duplication. This includes items that may sometimes act as a standard if(milkable.handle_milked(used_item, user)) return TRUE - if(used_item.edge && has_extension(src, /datum/extension/shearable)) + if(used_item.has_edge() && has_extension(src, /datum/extension/shearable)) var/datum/extension/shearable/shearable = get_extension(src, /datum/extension/shearable) if(shearable.handle_sheared(used_item, user)) return TRUE @@ -170,12 +172,12 @@ avoid code duplication. This includes items that may sometimes act as a standard /obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) var/use_hitsound = hitsound if(!use_hitsound) - if(edge || sharp) + if(has_edge() || is_sharp()) use_hitsound = 'sound/weapons/bladeslice.ogg' else use_hitsound = "swing_hit" playsound(loc, use_hitsound, 50, 1, -1) - return target.hit_with_weapon(src, user, get_attack_force(user), hit_zone) + return target.hit_with_weapon(src, user, expend_attack_force(user), hit_zone) /obj/item/proc/handle_reflexive_fire(var/mob/user, var/atom/aiming_at) return istype(user) && istype(aiming_at) diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm index 4da8abb538d8..92e3271df809 100644 --- a/code/controllers/subsystems/air.dm +++ b/code/controllers/subsystems/air.dm @@ -138,7 +138,13 @@ SUBSYSTEM_DEF(air) if(!SHOULD_PARTICIPATE_IN_ZONES(T)) continue simulated_turf_count++ + // We also skip anything already queued, since it'll be settled when fire() runs anyway. + if(T.needs_air_update) + continue T.update_air_properties() + // air state is necessarily globally incomplete during this + // so we can't do T.post_update_air_properties(), which needs + // connections to have been settled already. CHECK_TICK report_progress({"Total Simulated Turfs: [simulated_turf_count] @@ -198,7 +204,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun T.update_air_properties() T.post_update_air_properties() - T.needs_air_update = 0 + T.needs_air_update = FALSE #ifdef ZASDBG T.remove_vis_contents(zasdbgovl_mark) #endif @@ -214,7 +220,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun T.update_air_properties() T.post_update_air_properties() - T.needs_air_update = 0 + T.needs_air_update = FALSE #ifdef ZASDBG T.remove_vis_contents(zasdbgovl_mark) #endif @@ -368,13 +374,15 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun #ifdef ZASDBG ASSERT(isturf(T)) #endif - if(T.needs_air_update) + // don't queue us if we've already been queued + // and if SSair hasn't run, every turf in the world will get updated soon anyway + if(T.needs_air_update || !SSair.initialized) return tiles_to_update += T #ifdef ZASDBG T.add_vis_contents(zasdbgovl_mark) #endif - T.needs_air_update = 1 + T.needs_air_update = TRUE /datum/controller/subsystem/air/proc/mark_zone_update(zone/Z) #ifdef ZASDBG diff --git a/code/controllers/subsystems/ambience.dm b/code/controllers/subsystems/ambience.dm index 757f846c6402..8f4b462e2050 100644 --- a/code/controllers/subsystems/ambience.dm +++ b/code/controllers/subsystems/ambience.dm @@ -33,6 +33,14 @@ SUBSYSTEM_DEF(ambience) /// Whether this turf has been queued for an ambient lighting update. var/ambience_queued = FALSE +/turf/proc/shows_outdoor_ambience() + return is_outside() + +// Starlight can't be blocked by stuff above a space turf. +// TODO: decide if open sky deserves the same treatment +/turf/space/shows_outdoor_ambience() + return TRUE + /turf/proc/update_ambient_light_from_z_or_area() // If we're not outside, we don't show ambient light. @@ -40,7 +48,7 @@ SUBSYSTEM_DEF(ambience) var/ambient_light_modifier // If we're indoors because of our area, OR we're outdoors and not exposed to the weather, get interior ambience. - var/outsideness = is_outside() + var/outsideness = shows_outdoor_ambience() if((!outsideness && is_outside == OUTSIDE_AREA) || (outsideness && get_weather_exposure() != WEATHER_EXPOSED)) var/area/A = get_area(src) if(isnull(A?.interior_ambient_light_modifier)) diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm index 6e45e5e274b9..baf065bd0fd3 100644 --- a/code/controllers/subsystems/atoms.dm +++ b/code/controllers/subsystems/atoms.dm @@ -11,8 +11,10 @@ SUBSYSTEM_DEF(atoms) var/atom_init_stage = INITIALIZATION_INSSATOMS var/old_init_stage - var/list/late_loaders + /// A non-associative list of lists, with the format list(list(atom, list(Initialize arguments))). var/list/created_atoms = list() + /// A non-associative list of lists, with the format list(list(atom, list(LateInitialize arguments))). + var/list/late_loaders = list() var/list/BadInitializeCalls = list() @@ -22,21 +24,25 @@ SUBSYSTEM_DEF(atoms) return ..() /datum/controller/subsystem/atoms/proc/InitializeAtoms() - if(atom_init_stage <= INITIALIZATION_INSSATOMS_LATE) + if(atom_init_stage <= INITIALIZATION_INSSATOMS) return atom_init_stage = INITIALIZATION_INNEW_MAPLOAD - LAZYINITLIST(late_loaders) - var/list/mapload_arg = list(TRUE) - var/count = created_atoms.len - while(created_atoms.len) - var/atom/A = created_atoms[created_atoms.len] - var/list/atom_args = created_atoms[A] - created_atoms.len-- - if(!QDELETED(A) && !(A.atom_flags & ATOM_FLAG_INITIALIZED)) + var/index = 1 + // Things can add to the end of this list while we iterate, so we can't use a for loop. + while(index <= length(created_atoms)) + // Don't remove from this list while we run, that's expensive. + // That would also make it harder to handle things added while we iterate. + var/list/creation_packet = created_atoms[index++] + var/atom/A = creation_packet[1] + var/list/atom_args = creation_packet[2] + // I sure hope nothing in this list is ever hard-deleted, or else QDELING will runtime. + // If you get a null reference runtime error, just change it back to QDELETED. + // The ATOM_FLAG_INITIALIZED check is because of INITIALIZE_IMMEDIATE(). + if(!QDELING(A) && !(A.atom_flags & ATOM_FLAG_INITIALIZED)) if(atom_args) atom_args.Insert(1, TRUE) InitAtom(A, atom_args) @@ -44,26 +50,19 @@ SUBSYSTEM_DEF(atoms) InitAtom(A, mapload_arg) CHECK_TICK - // If wondering why not just store all atoms in created_atoms and use the block above: that turns out unbearably expensive. - // Instead, atoms without extra arguments in New created on server start are fished out of world directly. - // We do this exactly once. - if(!initialized) - for(var/atom/A in world) - if(!QDELETED(A) && !(A.atom_flags & ATOM_FLAG_INITIALIZED)) - InitAtom(A, mapload_arg) - ++count - CHECK_TICK - - report_progress("Initialized [count] atom\s") + report_progress("Initialized [index] atom\s") + created_atoms.Cut() atom_init_stage = INITIALIZATION_INNEW_REGULAR - if(late_loaders.len) - for(var/I in late_loaders) - var/atom/A = I - A.LateInitialize(arglist(late_loaders[A])) + if(length(late_loaders)) + index = 1 + while(index <= length(late_loaders)) + var/list/creation_packet = late_loaders[index++] + var/atom/A = creation_packet[1] + A.LateInitialize(arglist(creation_packet[2])) CHECK_TICK - report_progress("Late initialized [late_loaders.len] atom\s") + report_progress("Late initialized [index] atom\s") late_loaders.Cut() /datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments) @@ -91,7 +90,7 @@ SUBSYSTEM_DEF(atoms) EMPTY_BLOCK_GUARD if(INITIALIZE_HINT_LATELOAD) if(arguments[1]) //mapload - late_loaders[A] = arguments + late_loaders[++late_loaders.len] = list(A, arguments) else A.LateInitialize(arglist(arguments)) if(INITIALIZE_HINT_QDEL) @@ -113,7 +112,7 @@ SUBSYSTEM_DEF(atoms) /datum/controller/subsystem/atoms/proc/map_loader_begin() old_init_stage = atom_init_stage - atom_init_stage = INITIALIZATION_INSSATOMS_LATE + atom_init_stage = INITIALIZATION_INSSATOMS /datum/controller/subsystem/atoms/proc/map_loader_stop() atom_init_stage = old_init_stage diff --git a/code/controllers/subsystems/fluids.dm b/code/controllers/subsystems/fluids.dm index 1e95a63bf463..0b9faea243ed 100644 --- a/code/controllers/subsystems/fluids.dm +++ b/code/controllers/subsystems/fluids.dm @@ -231,13 +231,21 @@ SUBSYSTEM_DEF(fluids) if(!istype(current_fluid_holder) || QDELETED(current_fluid_holder)) continue var/pushed_something = FALSE - if(current_fluid_holder.reagents?.total_volume > FLUID_SHALLOW && current_fluid_holder.last_flow_strength >= 10) - for(var/atom/movable/AM as anything in current_fluid_holder.get_contained_external_atoms()) - if(AM.is_fluid_pushable(current_fluid_holder.last_flow_strength)) - AM.pushed(current_fluid_holder.last_flow_dir) - pushed_something = TRUE - if(pushed_something && prob(1)) - playsound(current_fluid_holder, 'sound/effects/slosh.ogg', 25, 1) + + if(current_fluid_holder.last_flow_strength >= 10) + // Catwalks mean items will be above the turf; subtract the turf height from our volume. + // TODO: somehow handle stuff that is on a catwalk or on the turf within the same turf. + var/effective_volume = current_fluid_holder.reagents?.total_volume + if(current_fluid_holder.get_supporting_platform()) + // Depth is negative height, hence +=. TODO: positive heights? No idea how to handle that. + effective_volume += current_fluid_holder.get_physical_height() + if(effective_volume > FLUID_SHALLOW) + for(var/atom/movable/AM as anything in current_fluid_holder.get_contained_external_atoms()) + if(AM.try_fluid_push(effective_volume, current_fluid_holder.last_flow_strength)) + AM.pushed(current_fluid_holder.last_flow_dir) + pushed_something = TRUE + if(pushed_something && prob(1)) + playsound(current_fluid_holder, 'sound/effects/slosh.ogg', 25, 1) if(MC_TICK_CHECK) processing_flows.Cut(1, i+1) return diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index 18f925703957..ac728a55ea21 100644 --- a/code/controllers/subsystems/garbage.dm +++ b/code/controllers/subsystems/garbage.dm @@ -17,7 +17,7 @@ SUBSYSTEM_DEF(garbage) runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY init_order = SS_INIT_GARBAGE - var/list/collection_timeout = list(0, 3 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level + var/list/collection_timeout = list(GC_FILTER_QUEUE, GC_CHECK_QUEUE, GC_DEL_QUEUE) // deciseconds to wait before moving something up in the queue to the next level //Stat tracking var/delslasttick = 0 // number of del()'s we've done this tick @@ -173,10 +173,10 @@ SUBSYSTEM_DEF(garbage) var/remaining_refs = refcount(D) - REFS_WE_EXPECT var/refID = ref(D) if(reference_find_on_fail[refID]) - D.find_references(remaining_refs) + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references), remaining_refs) #ifdef GC_FAILURE_HARD_LOOKUP else - D.find_references(remaining_refs) + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references), remaining_refs) #endif reference_find_on_fail -= refID #endif @@ -204,8 +204,6 @@ SUBSYSTEM_DEF(garbage) /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_FILTER) if (isnull(D)) return - if (D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL) - level = GC_QUEUE_HARDDELETE if (level > GC_QUEUE_COUNT) HardDelete(D) return @@ -281,13 +279,13 @@ SUBSYSTEM_DEF(garbage) qdel(D, force) #endif -// Should be treated as a replacement for the 'del' keyword. -// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. +/// Should be treated as a replacement for the 'del' keyword. +/// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. +/// Non-datums passed to this will be hard-deleted. /proc/qdel(datum/D, force=FALSE) if(isnull(D)) return if(!istype(D)) - PRINT_STACK_TRACE("qdel() can only handle /datum (sub)types, was passed: [log_info_line(D)]") del(D) return var/datum/qdel_item/I = SSgarbage.items[D.type] @@ -474,6 +472,7 @@ SUBSYSTEM_DEF(garbage) if(usr && usr.client && !usr.client.running_find_references) return if (!recursive_limit) + testing("Recursion limit reached. [container_name]") return if(references_to_clear == 0) return @@ -541,6 +540,10 @@ SUBSYSTEM_DEF(garbage) else if (I && !isnum(I) && normal) if(X[I] == src) testing("Found [src.type] \ref[src] in list [container_name]\[[I]\]") + references_to_clear -= 1 + if(references_to_clear == 0) + testing("All references to [type] \ref[src] found, exiting.") + return else if(islist(X[I])) DoSearchVar(X[I], "[container_name]\[[I]\]", recursive_limit-1) diff --git a/code/controllers/subsystems/holomap.dm b/code/controllers/subsystems/holomap.dm index 566e9ccb2181..ac6662184f62 100644 --- a/code/controllers/subsystems/holomap.dm +++ b/code/controllers/subsystems/holomap.dm @@ -81,7 +81,7 @@ SUBSYSTEM_DEF(minimap) continue if((tile.turf_flags & TURF_IS_HOLOMAP_OBSTACLE) || (locate(/obj/structure/grille) in tile)) canvas.DrawBox(COLOR_HOLOMAP_OBSTACLE, tile.x + offset_x, tile.y + offset_y) - else if((tile.turf_flags & TURF_IS_HOLOMAP_PATH) || (locate(/obj/structure/catwalk) in tile)) + else if((tile.turf_flags & TURF_IS_HOLOMAP_PATH) || tile.get_supporting_platform()) canvas.DrawBox(COLOR_HOLOMAP_PATH, tile.x + offset_x, tile.y + offset_y) CHECK_TICK return canvas diff --git a/code/controllers/subsystems/initialization/character_info.dm b/code/controllers/subsystems/initialization/character_info.dm index cb09b69f3619..a874ddcb4f93 100644 --- a/code/controllers/subsystems/initialization/character_info.dm +++ b/code/controllers/subsystems/initialization/character_info.dm @@ -136,7 +136,7 @@ SUBSYSTEM_DEF(character_info) fdel(dump_file_name) text2file(JOINTEXT(SScharacter_info.get_character_manifest_html(apply_striping = FALSE)), dump_file_name) if(fexists(dump_file_name)) - direct_output(usr, ftp(dump_file_name, "dump_manifest.html")) + ftp_to(usr, dump_file_name, "dump_manifest.html") return TOPIC_HANDLED catch(var/exception/E) log_debug("Exception when dumping character relationship manifest: [E]") diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm index a7583ae1b2ff..61f8b083a33b 100644 --- a/code/controllers/subsystems/lighting.dm +++ b/code/controllers/subsystems/lighting.dm @@ -54,7 +54,12 @@ SUBSYSTEM_DEF(lighting) // Generate overlays. for (var/zlevel = 1 to world.maxz) - overlaycount += InitializeZlev(zlevel) + var/datum/level_data/level = SSmapping.levels_by_z[zlevel] + for (var/turf/tile as anything in block(1, 1, zlevel, level.level_max_width, level.level_max_height)) // include TRANSITIONEDGE turfs + if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(tile)) + tile.lighting_build_overlay() + overlaycount++ + CHECK_TICK admin_notice(SPAN_DANGER("Created [overlaycount] lighting overlays in [(REALTIMEOFDAY - starttime)/10] seconds."), R_DEBUG) @@ -71,26 +76,6 @@ SUBSYSTEM_DEF(lighting) ..() -/datum/controller/subsystem/lighting/proc/InitializeZlev(zlev) - for (var/thing in Z_ALL_TURFS(zlev)) - var/turf/T = thing - if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) && !T.lighting_overlay) // Can't assume that one hasn't already been created on bay/neb. - new /atom/movable/lighting_overlay(T) - . += 1 - if (T.ambient_light) - T.generate_missing_corners() // Forcibly generate corners. - - CHECK_TICK - -// It's safe to pass a list of non-turfs to this list - it'll only check turfs. -/datum/controller/subsystem/lighting/proc/InitializeTurfs(list/targets) - for (var/turf/T in (targets || world)) - if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T)) - T.lighting_build_overlay() - - // If this isn't here, BYOND will set-background us. - CHECK_TICK - /datum/controller/subsystem/lighting/fire(resumed = FALSE, no_mc_tick = FALSE) if (!resumed) processed_lights = 0 diff --git a/code/controllers/subsystems/machines.dm b/code/controllers/subsystems/machines.dm index 48d7b4250379..674ec094cc68 100644 --- a/code/controllers/subsystems/machines.dm +++ b/code/controllers/subsystems/machines.dm @@ -82,6 +82,12 @@ if(current_step == this_step || (check_resumed && !resumed)) {\ #undef INTERNAL_PROCESS_STEP +/datum/controller/subsystem/machines/StartLoadingMap() + suspend() + +/datum/controller/subsystem/machines/StopLoadingMap() + wake() + // rebuild all power networks from scratch - only called at world creation or by the admin verb // The above is a lie. Turbolifts also call this proc. /datum/controller/subsystem/machines/proc/makepowernets() diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm index 6e1061636ec6..cdba384cdf85 100644 --- a/code/controllers/subsystems/mapping.dm +++ b/code/controllers/subsystems/mapping.dm @@ -109,6 +109,8 @@ SUBSYSTEM_DEF(mapping) // Load any queued map template markers. for(var/obj/abstract/landmark/map_load_mark/queued_mark in queued_markers) queued_mark.load_subtemplate() + if(!QDELETED(queued_mark)) // for if the tile that lands on the landmark is a no-op tile + qdel(queued_mark) queued_markers.Cut() // Populate overmap. @@ -119,15 +121,9 @@ SUBSYSTEM_DEF(mapping) // This needs to be non-null even if the overmap isn't created for this map. overmap_event_handler = GET_DECL(/decl/overmap_event_handler) - var/old_maxz - for(var/z = 1 to world.maxz) - var/datum/level_data/level = levels_by_z[z] - if(!istype(level)) - level = new /datum/level_data/space(z) - PRINT_STACK_TRACE("Missing z-level data object for z[num2text(z)]!") - level.setup_level_data() + setup_data_for_levels() - old_maxz = world.maxz + var/old_maxz = world.maxz // Build away sites. global.using_map.build_away_sites() global.using_map.build_planets() @@ -150,13 +146,7 @@ SUBSYSTEM_DEF(mapping) test_load_map_templates() #endif - // Check/associated/setup our level data objects. - for(var/z = old_maxz + 1 to world.maxz) - var/datum/level_data/level = levels_by_z[z] - if(!istype(level)) - level = new /datum/level_data/space(z) - PRINT_STACK_TRACE("Missing z-level data object for z[num2text(z)]!") - level.setup_level_data() + setup_data_for_levels(min_z = old_maxz + 1) // Generate turbolifts last, since away sites may have elevators to generate too. for(var/obj/abstract/turbolift_spawner/turbolift as anything in turbolifts_to_initialize) @@ -166,6 +156,14 @@ SUBSYSTEM_DEF(mapping) . = ..() +/datum/controller/subsystem/mapping/proc/setup_data_for_levels(min_z = 1, max_z = world.maxz) + for(var/z = min_z to max_z) + var/datum/level_data/level = levels_by_z[z] + if(!istype(level)) + level = new /datum/level_data/space(z) + PRINT_STACK_TRACE("Missing z-level data object for z[num2text(z)]!") + level.setup_level_data() + /datum/controller/subsystem/mapping/Recover() flags |= SS_NO_INIT map_templates = SSmapping.map_templates @@ -198,7 +196,7 @@ SUBSYSTEM_DEF(mapping) . = list() for(var/template_type in subtypesof(/datum/map_template)) var/datum/map_template/template = template_type - if(!TYPE_IS_ABSTRACT(template) && initial(template.template_parent_type) != template_type && initial(template.name)) + if(!TYPE_IS_ABSTRACT(template)) . += new template_type(type) // send name as a param to catch people doing illegal ad hoc creation /datum/controller/subsystem/mapping/proc/get_template(var/template_name) diff --git a/code/controllers/subsystems/processing/overmap.dm b/code/controllers/subsystems/overmap.dm similarity index 100% rename from code/controllers/subsystems/processing/overmap.dm rename to code/controllers/subsystems/overmap.dm diff --git a/code/controllers/subsystems/plants.dm b/code/controllers/subsystems/processing/plants.dm similarity index 87% rename from code/controllers/subsystems/plants.dm rename to code/controllers/subsystems/processing/plants.dm index a6256b563317..c07b5e9c714e 100644 --- a/code/controllers/subsystems/plants.dm +++ b/code/controllers/subsystems/processing/plants.dm @@ -1,11 +1,15 @@ -PROCESSING_SUBSYSTEM_DEF(plants) - name = "Plants" - priority = SS_PRIORITY_PLANTS - runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME - flags = SS_BACKGROUND|SS_POST_FIRE_TIMING - init_order = SS_INIT_PLANTS - wait = 60 +/datum/proc/process_plants() + SHOULD_NOT_SLEEP(TRUE) + return PROCESS_KILL +PROCESSING_SUBSYSTEM_DEF(plants) + name = "Plants" + priority = SS_PRIORITY_PLANTS + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + flags = SS_BACKGROUND|SS_POST_FIRE_TIMING + init_order = SS_INIT_PLANTS + wait = 1 MINUTE + process_proc = TYPE_PROC_REF(/datum, process_plants) /// Stores generated fruit descs. var/list/product_descs = list() /// All seed data stored here. diff --git a/code/controllers/subsystems/shuttle.dm b/code/controllers/subsystems/shuttle.dm index 7c6b1a077114..77f0d4083cb2 100644 --- a/code/controllers/subsystems/shuttle.dm +++ b/code/controllers/subsystems/shuttle.dm @@ -125,13 +125,14 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/initialize_shuttle(var/shuttle_type, var/map_hash, var/list/add_args) var/datum/shuttle/shuttle = shuttle_type - if(initial(shuttle.category) != shuttle_type) - var/list/shuttle_args = list(map_hash) - if(length(add_args)) - shuttle_args += add_args - shuttle = new shuttle(arglist(shuttle_args)) - shuttle_areas |= shuttle.shuttle_area - return shuttle + if(TYPE_IS_ABSTRACT(shuttle)) + return null + var/list/shuttle_args = list(map_hash) + if(length(add_args)) + shuttle_args += add_args + shuttle = new shuttle(arglist(shuttle_args)) + shuttle_areas |= shuttle.shuttle_area + return shuttle /datum/controller/subsystem/shuttle/proc/hook_up_motherships(shuttles_list) for(var/datum/shuttle/S in shuttles_list) diff --git a/code/datums/extensions/holster/holster.dm b/code/datums/extensions/holster/holster.dm index 8792a616b5a6..569ca88bdb13 100644 --- a/code/datums/extensions/holster/holster.dm +++ b/code/datums/extensions/holster/holster.dm @@ -111,7 +111,7 @@ to_chat(user, "It is empty.") /datum/extension/holster/proc/check_holster() - if(holstered.loc != storage) + if(holstered.loc != storage.holder) clear_holster() /atom/proc/holster_verb(var/holster_name in get_holsters()) @@ -154,4 +154,63 @@ else for(var/i = 1 to holster_accessories.len) var/holster_name = "[accessory_name] [i]" - .[holster_name] = get_extension(holster_accessories[i], /datum/extension/holster) \ No newline at end of file + .[holster_name] = get_extension(holster_accessories[i], /datum/extension/holster) + +// Basic unholster for an item at the top level. +/decl/interaction_handler/unholster + name = "Unholster" + +/decl/interaction_handler/unholster/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && !prop + if(.) + var/datum/extension/holster/holster = get_extension(target, /datum/extension/holster) + return !!holster?.holstered + +/decl/interaction_handler/unholster/invoked(atom/target, mob/user, obj/item/prop) + var/datum/extension/holster/holster = get_extension(target, /datum/extension/holster) + return holster?.unholster(user, avoid_intent = TRUE) + +// Interaction procs for getting this interaction for basic items. +/obj/item/get_quick_interaction_handler(mob/user) + if(!(. = ..())) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster?.holstered) + return GET_DECL(/decl/interaction_handler/unholster) + +// More complex version of the above that iterates clothing accessories. +/decl/interaction_handler/unholster_accessory + name = "Unholster From Accessory" + expected_target_type = /obj/item/clothing + +/decl/interaction_handler/unholster_accessory/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && !prop + if(.) + var/obj/item/clothing/clothes = target + for(var/obj/item/thing in clothes.accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.holstered) + return TRUE + return FALSE + +/decl/interaction_handler/unholster_accessory/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/clothing/clothes = target + for(var/obj/item/thing in clothes.accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.unholster(user, avoid_intent = TRUE)) + return TRUE + return FALSE + +// Interaction procs for getting this interaction for clothing accessories. +/obj/item/clothing/get_alt_interactions(mob/user) + . = ..() + for(var/obj/item/thing in accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.holstered) + LAZYADD(., GET_DECL(/decl/interaction_handler/unholster_accessory)) + +/obj/item/clothing/get_quick_interaction_handler(mob/user) + if(!(. = ..())) + for(var/obj/item/thing in accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.holstered) + return GET_DECL(/decl/interaction_handler/unholster_accessory) diff --git a/code/datums/extensions/storage/subtypes_mre.dm b/code/datums/extensions/storage/subtypes_mre.dm index 5b7f49107160..b5045c1fc1b2 100644 --- a/code/datums/extensions/storage/subtypes_mre.dm +++ b/code/datums/extensions/storage/subtypes_mre.dm @@ -5,8 +5,11 @@ open_sound = 'sound/effects/rip1.ogg' /datum/storage/mre/open(mob/user) - if(!opened) - to_chat(user, "You tear open the bag, breaking the vacuum seal.") + var/obj/item/mre/mre = holder + if(istype(mre) && !mre.has_been_opened) + to_chat(user, SPAN_NOTICE("You tear open the bag, breaking the vacuum seal.")) + mre.has_been_opened = TRUE + mre.update_icon() . = ..() /datum/storage/mrebag diff --git a/code/datums/supplypacks/supplypack.dm b/code/datums/supplypacks/supplypack.dm index 159c8ae31e7a..1be6469edc51 100644 --- a/code/datums/supplypacks/supplypack.dm +++ b/code/datums/supplypacks/supplypack.dm @@ -24,9 +24,7 @@ var/global/list/cargoprices = list() cost = 0 for(var/entry in contains) cost += atom_info_repository.get_combined_worth_for(entry) * max(1, contains[entry]) - var/container_value = containertype ? atom_info_repository.get_single_worth_for(containertype) : 0 - if(container_value) - cost += atom_info_repository.get_single_worth_for(containertype) + cost += containertype ? atom_info_repository.get_single_worth_for(containertype) : 0 cost = max(1, NONUNIT_CEILING((cost * WORTH_TO_SUPPLY_POINTS_CONSTANT * SSsupply.price_markup), WORTH_TO_SUPPLY_POINTS_ROUND_CONSTANT)) global.cargoprices[name] = cost diff --git a/code/datums/traits/maluses/amputations.dm b/code/datums/traits/maluses/amputations.dm index 5cbd3ea7c77e..8ce9bc5d4186 100644 --- a/code/datums/traits/maluses/amputations.dm +++ b/code/datums/traits/maluses/amputations.dm @@ -15,8 +15,6 @@ if(trait_type == type) continue var/decl/trait/malus/amputation/trait = check_traits[trait_type] - if(!trait.name) - continue // remove when abstract decl handling from dev is merged for(var/limb in trait.apply_to_limbs) if(limb in ban_traits_relating_to_limbs) LAZYDISTINCTADD(incompatible_with, trait_type) diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm index 06c679edfd2c..c984ebbcb773 100644 --- a/code/datums/wires/nuclearbomb.dm +++ b/code/datums/wires/nuclearbomb.dm @@ -20,7 +20,7 @@ var/global/const/NUCLEARBOMB_WIRE_SAFETY = 4 var/obj/machinery/nuclearbomb/N = holder . += ..() . += "
The device is [N.timing ? "shaking!" : "still."]
" - . += "The device is is [N.safety ? "quiet" : "whirring"].
" + . += "The device is [N.safety ? "quiet" : "whirring"].
" . += "The lights are [N.lighthack ? "static" : "functional"].
" /datum/wires/nuclearbomb/proc/toggle_hacked() diff --git a/code/datums/wires/smes.dm b/code/datums/wires/smes.dm index 15eff146d156..7cc90b2d664a 100644 --- a/code/datums/wires/smes.dm +++ b/code/datums/wires/smes.dm @@ -9,68 +9,68 @@ new /datum/wire_description(SMES_WIRE_FAILSAFES, "This wire appears to connect to a failsafe mechanism.") ) -var/global/const/SMES_WIRE_RCON = 1 // Remote control (AI and consoles), cut to disable -var/global/const/SMES_WIRE_INPUT = 2 // Input wire, cut to disable input, pulse to disable for 60s -var/global/const/SMES_WIRE_OUTPUT = 4 // Output wire, cut to disable output, pulse to disable for 60s -var/global/const/SMES_WIRE_GROUNDING = 8 // Cut to quickly discharge causing sparks, pulse to only create few sparks -var/global/const/SMES_WIRE_FAILSAFES = 16 // Cut to disable failsafes, mend to reenable - - -/datum/wires/smes/CanUse(var/mob/living/L) - var/obj/machinery/power/smes/buildable/S = holder - if(!S.grounding && S.powernet && S.powernet.avail) - electrocute_mob(L, S.powernet, S, S.safeties_enabled? 0.1 : 1) - if(S.panel_open) - return 1 - return 0 +/// Remote control (AI and consoles), cut to disable +var/global/const/SMES_WIRE_RCON = BITFLAG(0) +/// Input wire, cut to disable input, pulse to disable for 60s +var/global/const/SMES_WIRE_INPUT = BITFLAG(1) +/// Output wire, cut to disable output, pulse to disable for 60s +var/global/const/SMES_WIRE_OUTPUT = BITFLAG(2) +/// Cut to quickly discharge causing sparks, pulse to only create few sparks +var/global/const/SMES_WIRE_GROUNDING = BITFLAG(3) +/// Cut to disable failsafes, mend to reenable +var/global/const/SMES_WIRE_FAILSAFES = BITFLAG(4) +/datum/wires/smes/CanUse(var/mob/living/user) + var/obj/machinery/power/smes/buildable/storage = holder + if(!storage.grounding && storage.powernet && storage.powernet.avail) + electrocute_mob(user, storage.powernet, storage, (storage.safeties_enabled? 0.1 : 1)) + return storage.panel_open /datum/wires/smes/GetInteractWindow(mob/user) - var/obj/machinery/power/smes/buildable/S = holder + var/obj/machinery/power/smes/buildable/storage = holder . += ..() - . += "The green light is [(S.input_cut || S.input_pulsed || S.output_cut || S.output_pulsed) ? "off" : "on"]
" - . += "The red light is [(S.safeties_enabled || S.grounding) ? "off" : "blinking"]
" - . += "The blue light is [S.RCon ? "on" : "off"]" - + . += "The green light is [(storage.input_cut || storage.input_pulsed || storage.output_cut || storage.output_pulsed) ? "off" : "on"]
" + . += "The red light is [(storage.safeties_enabled || storage.grounding) ? "off" : "blinking"]
" + . += "The blue light is [storage.RCon ? "on" : "off"]" /datum/wires/smes/UpdateCut(var/index, var/mended) - var/obj/machinery/power/smes/buildable/S = holder + var/obj/machinery/power/smes/buildable/storage = holder switch(index) if(SMES_WIRE_RCON) - S.RCon = mended + storage.RCon = mended if(SMES_WIRE_INPUT) - S.input_cut = !mended + storage.input_cut = !mended if(SMES_WIRE_OUTPUT) - S.output_cut = !mended + storage.output_cut = !mended if(SMES_WIRE_GROUNDING) - S.grounding = mended + storage.grounding = mended if(SMES_WIRE_FAILSAFES) - S.safeties_enabled = mended + storage.safeties_enabled = mended /datum/wires/smes/proc/reset_rcon() - var/obj/machinery/power/smes/buildable/S = holder - if(S) - S.RCon = TRUE + var/obj/machinery/power/smes/buildable/storage = holder + if(storage) + storage.RCon = TRUE /datum/wires/smes/proc/reset_safeties() - var/obj/machinery/power/smes/buildable/S = holder - if(S) - S.safeties_enabled = TRUE + var/obj/machinery/power/smes/buildable/storage = holder + if(storage) + storage.safeties_enabled = TRUE /datum/wires/smes/UpdatePulsed(var/index) - var/obj/machinery/power/smes/buildable/S = holder + var/obj/machinery/power/smes/buildable/storage = holder switch(index) if(SMES_WIRE_RCON) - if(S.RCon) - S.RCon = 0 + if(storage.RCon) + storage.RCon = 0 addtimer(CALLBACK(src, PROC_REF(reset_rcon)), 1 SECOND) if(SMES_WIRE_INPUT) - S.toggle_input() + storage.toggle_input() if(SMES_WIRE_OUTPUT) - S.toggle_output() + storage.toggle_output() if(SMES_WIRE_GROUNDING) - S.grounding = 0 + storage.grounding = 0 if(SMES_WIRE_FAILSAFES) - if(S.safeties_enabled) - S.safeties_enabled = 0 + if(storage.safeties_enabled) + storage.safeties_enabled = 0 addtimer(CALLBACK(src, PROC_REF(reset_safeties)), 1 SECOND) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index fc3e86a037a2..196f4cc44e5c 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -997,5 +997,11 @@ /atom/proc/can_drink_from(mob/user) return ATOM_IS_OPEN_CONTAINER(src) && reagents?.total_volume && user.check_has_mouth() +/atom/proc/adjust_required_attack_dexterity(mob/user, required_dexterity) + if(storage) // TODO: possibly check can_be_inserted() to avoid being able to shoot mirrors as a drake. + return DEXTERITY_HOLD_ITEM + return required_dexterity + /atom/proc/immune_to_floor_hazards() return !simulated + diff --git a/code/game/atoms_fluids.dm b/code/game/atoms_fluids.dm index 2984d5393f27..bf49a3469c05 100644 --- a/code/game/atoms_fluids.dm +++ b/code/game/atoms_fluids.dm @@ -16,7 +16,7 @@ /atom/proc/CanFluidPass(var/coming_from) return TRUE -/atom/movable/proc/is_fluid_pushable(var/amt) +/atom/movable/proc/try_fluid_push(volume, strength) return simulated && !anchored /atom/movable/is_flooded(var/lying_mob, var/absolute) @@ -47,7 +47,7 @@ // This override exists purely because throwing is movable-level and not atom-level, // for obvious reasons (that being that non-movable atoms cannot move). /atom/movable/submerged(depth, above_turf) - above_turf ||= !!throwing + above_turf ||= immune_to_floor_hazards() return ..() /obj/item/submerged(depth, above_turf) @@ -66,7 +66,7 @@ return ..() /mob/submerged(depth, above_turf) - above_turf ||= is_floating || !!throwing // check throwing here because of the table check coming before parent call + above_turf ||= immune_to_floor_hazards() // check throwing here because of the table check coming before parent call var/obj/structure/table/standing_on = locate(/obj/structure/table) in loc // can't stand on a table if we're floating if(!above_turf && standing_on && standing_on.mob_offset > 0) // standing atop a table that is a meaningful amount above the ground (not a bench) diff --git a/code/game/atoms_init.dm b/code/game/atoms_init.dm index d1cd533c7967..eb08297e2ab9 100644 --- a/code/game/atoms_init.dm +++ b/code/game/atoms_init.dm @@ -16,18 +16,15 @@ var/do_initialize = SSatoms.atom_init_stage var/list/created = SSatoms.created_atoms - if(do_initialize > INITIALIZATION_INSSATOMS_LATE) + if(do_initialize > INITIALIZATION_INSSATOMS) args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD if(SSatoms.InitAtom(src, args)) //we were deleted return - else if(created) - var/list/argument_list - if(length(args) > 1) - argument_list = args.Copy(2) - if(argument_list || do_initialize == INITIALIZATION_INSSATOMS_LATE) - created[src] = argument_list - + else if(length(args) > 1) + created[++created.len] = list(src, args.Copy(2)) + else + created[++created.len] = list(src, null) if(atom_flags & ATOM_FLAG_CLIMBABLE) verbs += /atom/proc/climb_on diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 7142d14c3828..9c481be8d469 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -593,7 +593,7 @@ return null /atom/movable/immune_to_floor_hazards() - return ..() || throwing + return ..() || !!throwing // TODO: make everything use this. /atom/movable/proc/set_anchored(new_anchored) @@ -603,3 +603,10 @@ return TRUE return FALSE +// updates pixel offsets, triggers fluids, etc. +/atom/movable/proc/on_turf_height_change(new_height) + if(simulated) + reset_offsets() + return TRUE + return FALSE + diff --git a/code/game/images.dm b/code/game/images.dm deleted file mode 100644 index e8b844937491..000000000000 --- a/code/game/images.dm +++ /dev/null @@ -1,3 +0,0 @@ -/image/Destroy() - ..() - return QDEL_HINT_HARDDEL diff --git a/code/game/machinery/_machines_base/machinery_damage.dm b/code/game/machinery/_machines_base/machinery_damage.dm index a434776abd88..bba75011ff7a 100644 --- a/code/game/machinery/_machines_base/machinery_damage.dm +++ b/code/game/machinery/_machines_base/machinery_damage.dm @@ -85,7 +85,7 @@ /obj/machinery/bash(obj/item/W, mob/user) if(!istype(W)) return FALSE - var/force = W.get_attack_force(user) + var/force = W.expend_attack_force(user) if(force <= 5) return FALSE . = ..() diff --git a/code/game/machinery/_machines_base/stock_parts/power/terminal.dm b/code/game/machinery/_machines_base/stock_parts/power/terminal.dm index 041e68950f93..732d90839c9f 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/terminal.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/terminal.dm @@ -135,7 +135,7 @@ if(!C.can_use(10)) to_chat(user, "You need ten lengths of cable for \the [machine].") return TRUE - user.visible_message("\The [user] adds cables to the \the [machine].", \ + user.visible_message("\The [user] adds cables to \the [machine].", \ "You start adding cables to \the [machine] frame...") playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 20, machine)) @@ -147,8 +147,8 @@ return TRUE C.use(10) user.visible_message(\ - "\The [user] has added cables to the \the [machine]!",\ - "You add cables to the \the [machine].") + "\The [user] has added cables to \the [machine]!",\ + "You add cables to \the [machine].") make_terminal(machine) return TRUE return FALSE diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 48e9178a8c70..52613f16121d 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -200,7 +200,7 @@ EMPTY_CANISTER(hydrogen, /obj/machinery/portable_atmospherics/canister/hydrogen) /obj/machinery/portable_atmospherics/canister/bash(var/obj/item/W, var/mob/user) . = ..() if(.) - current_health -= W.get_attack_force(user) + current_health -= W.expend_attack_force(user) healthcheck() /obj/machinery/portable_atmospherics/canister/attackby(var/obj/item/W, var/mob/user) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index ee9a28eee31d..3262bf5a4230 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -187,7 +187,7 @@ /obj/machinery/camera/physical_attack_hand(mob/living/human/user) if(!istype(user)) return TRUE - if(user.species.can_shred(user)) + if(user.can_shred()) user.do_attack_animation(src) visible_message(SPAN_WARNING("\The [user] slashes at [src]!")) playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 5b319d56bcb6..345a6b0359aa 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -52,9 +52,9 @@ else switch(W.atom_damage_type) if(BURN) - current_health -= W.get_attack_force(user) * 0.75 + current_health -= W.expend_attack_force(user) * 0.75 if(BRUTE) - current_health -= W.get_attack_force(user) * 0.5 + current_health -= W.expend_attack_force(user) * 0.5 if (current_health <= 0) explode() return TRUE diff --git a/code/game/machinery/doors/_door.dm b/code/game/machinery/doors/_door.dm index cc2a3c8adf4b..e76fe49edfef 100644 --- a/code/game/machinery/doors/_door.dm +++ b/code/game/machinery/doors/_door.dm @@ -335,7 +335,7 @@ return FALSE user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(src) - var/force = weapon.get_attack_force(user) + var/force = weapon.expend_attack_force(user) if(force < min_force) user.visible_message("\The [user] hits \the [src] with \the [weapon] with no visible effect.") else diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index aa341461f1c8..1be24240e750 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -802,7 +802,7 @@ About the new airlock wires panel: else if((stat & (BROKEN|NOPOWER)) && isanimal(user)) var/mob/living/simple_animal/A = user var/obj/item/I = A.get_natural_weapon() - if(I?.get_attack_force(user) >= 10) + if(I?.expend_attack_force(user) >= 10) if(density) visible_message(SPAN_DANGER("\The [A] forces \the [src] open!")) open(1) @@ -822,7 +822,7 @@ About the new airlock wires panel: var/obj/item/bladed/axe/fire/F = weapon if (F.is_held_twohanded()) playsound(src, 'sound/weapons/smash.ogg', 100, 1) - current_health -= F.get_attack_force(user) * 2 + current_health -= F.expend_attack_force(user) * 2 if(current_health <= 0) user.visible_message(SPAN_DANGER("[user] smashes \the [weapon] into the airlock's control panel! It explodes in a shower of sparks!"), SPAN_DANGER("You smash \the [weapon] into the airlock's control panel! It explodes in a shower of sparks!")) current_health = 0 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 6ec853d2eb83..e6366bcc0a0f 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -139,13 +139,11 @@ return /obj/machinery/door/window/physical_attack_hand(mob/user) - if(ishuman(user)) - var/mob/living/human/H = user - if(H.species.can_shred(H)) - playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) - visible_message("\The [user] smashes against \the [src].", 1) - take_damage(25) - return TRUE + if(user.can_shred()) + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + visible_message(SPAN_DANGER("\The [user] smashes against \the [src].")) + take_damage(25) + return TRUE return ..() /obj/machinery/door/window/emag_act(var/remaining_charges, var/mob/user) diff --git a/code/game/machinery/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm index 647e9c0b5720..fdc1b122ef33 100644 --- a/code/game/machinery/pipe/pipelayer.dm +++ b/code/game/machinery/pipe/pipelayer.dm @@ -73,7 +73,7 @@ if(m) use_metal(m) SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(src), m) - user.visible_message("[user] removes [m] sheet\s of metal from the \the [src].", "You remove [m] sheet\s of metal from \the [src]") + user.visible_message(SPAN_NOTICE("[user] removes [m] sheet\s of metal from \the [src]."), SPAN_NOTICE("You remove [m] sheet\s of metal from \the [src]")) else to_chat(user, "\The [src] is empty.") return TRUE diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 0124b95786e2..286ac6310cc4 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -290,7 +290,7 @@ var/global/list/turret_icons else //if the turret was attacked with the intention of harming it: - var/force = I.get_attack_force(user) * 0.5 + var/force = I.expend_attack_force(user) * 0.5 user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) take_damage(force, I.atom_damage_type) if(force > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off diff --git a/code/game/machinery/turrets/_turrets.dm b/code/game/machinery/turrets/_turrets.dm index 3030bc2bef9f..957c34078890 100644 --- a/code/game/machinery/turrets/_turrets.dm +++ b/code/game/machinery/turrets/_turrets.dm @@ -188,7 +188,7 @@ playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) reloading_progress = 0 - else if(stored_magazine && length(stored_magazine.stored_ammo) < stored_magazine.max_ammo) + else if(stored_magazine && stored_magazine.get_stored_ammo_count() < stored_magazine.max_ammo) var/obj/item/stock_parts/ammo_box/ammo_box = get_component_of_type(/obj/item/stock_parts/ammo_box) if(ammo_box?.is_functional() && ammo_box.stored_caliber == proj_gun.caliber) var/obj/item/ammo_casing/casing = ammo_box.remove_ammo(stored_magazine) @@ -366,7 +366,7 @@ // Only reload the magazine if we're completely out of ammo or we don't have a target. if(ammo_remaining == 0) return TRUE - if(!is_valid_target(target?.resolve()) && length(proj_gun.ammo_magazine.stored_ammo) != proj_gun.ammo_magazine.max_ammo) + if(!is_valid_target(target?.resolve()) && proj_gun.ammo_magazine.get_stored_ammo_count() != proj_gun.ammo_magazine.max_ammo) return TRUE else return FALSE diff --git a/code/game/machinery/turrets/turret_ammo.dm b/code/game/machinery/turrets/turret_ammo.dm index 52cf5825df0c..2ae590923072 100644 --- a/code/game/machinery/turrets/turret_ammo.dm +++ b/code/game/machinery/turrets/turret_ammo.dm @@ -50,7 +50,7 @@ if(stored_caliber && magazine.caliber != stored_caliber) to_chat(user, SPAN_WARNING("The caliber of \the [magazine] does not match the caliber stored in \the [src]!")) return TRUE - if(!length(magazine.stored_ammo)) + if(!magazine.get_stored_ammo_count()) to_chat(user, SPAN_WARNING("\The [magazine] is empty!")) return TRUE if(length(stored_ammo) >= max_ammo) @@ -58,7 +58,7 @@ return TRUE stored_caliber = magazine.caliber - for(var/obj/item/ammo_casing/casing in magazine.stored_ammo) + for(var/obj/item/ammo_casing/casing in magazine.get_stored_ammo_count()) // Just in case. if(casing.caliber != stored_caliber) continue diff --git a/code/game/machinery/wall_frames.dm b/code/game/machinery/wall_frames.dm index 7e7e27176125..f06099ed6e37 100644 --- a/code/game/machinery/wall_frames.dm +++ b/code/game/machinery/wall_frames.dm @@ -246,7 +246,7 @@ icon = 'icons/obj/airlock_machines.dmi' icon_state = "airlock_control_off" name = "airlock controller frame" - desc = "Used to build airlock controllers. Use a multitool on the circuit to determine which type you want, and then hit this with the the circuit." + desc = "Used to build airlock controllers. Use a multitool on the circuit to determine which type you want, and then hit this with the circuit." build_machine_type = null ///Used when configuring a dummy controller var/master_controller_id_tag diff --git a/code/game/objects/__objs.dm b/code/game/objects/__objs.dm index 8ab41e00a57f..812aaa9ddcad 100644 --- a/code/game/objects/__objs.dm +++ b/code/game/objects/__objs.dm @@ -14,8 +14,7 @@ var/list/req_access var/list/matter //Used to store information about the contents of the object. var/w_class // Size of the object. - var/sharp = 0 // whether this object cuts - var/edge = 0 // whether this object is more likely to dismember + var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! var/armor_penetration = 0 var/anchor_fall = FALSE @@ -119,12 +118,12 @@ /obj/proc/damage_flags() . = 0 - if(has_edge(src)) - . |= DAM_EDGE - if(is_sharp(src)) - . |= DAM_SHARP + if(is_sharp()) + . |= DAM_SHARP|DAM_EDGE if(atom_damage_type == BURN) . |= DAM_LASER + else if(has_edge()) + . |= DAM_EDGE /obj/attackby(obj/item/used_item, mob/user) // We need to call parent even if we lack dexterity, so that storage can work. @@ -156,8 +155,8 @@ add_fingerprint(user) return ..() -/obj/is_fluid_pushable(var/amt) - return ..() && w_class <= round(amt/20) +/obj/try_fluid_push(volume, strength) + return ..() && w_class <= round(strength/20) /obj/proc/can_embed() return FALSE diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm index 1e7a3685c90e..70d5c86bb2e0 100644 --- a/code/game/objects/effects/chem/foam.dm +++ b/code/game/objects/effects/chem/foam.dm @@ -171,7 +171,7 @@ return TRUE /obj/structure/foamedmetal/attackby(var/obj/item/I, var/mob/user) - if(prob(I.get_attack_force(user) * 20 - metal * 25)) + if(prob(I.expend_attack_force(user) * 20 - metal * 25)) user.visible_message( SPAN_WARNING("\The [user] smashes through the foamed metal."), SPAN_NOTICE("You smash through the foamed metal with \the [I].") diff --git a/code/game/objects/effects/chem/water.dm b/code/game/objects/effects/chem/water.dm index ef1d2ba60969..8f4dbce7bb75 100644 --- a/code/game/objects/effects/chem/water.dm +++ b/code/game/objects/effects/chem/water.dm @@ -45,8 +45,7 @@ break sleep(delay) - sleep(10) - qdel(src) + QDEL_IN(src, 1 SECOND) /obj/effect/effect/water/Move(turf/newloc) if(newloc.density) diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index cbd3f166ddbb..77bb9276f642 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -1,4 +1,3 @@ -#define DRYING_TIME 5 MINUTES //for 1 unit of depth in puddle (amount var) #define BLOOD_SIZE_SMALL 1 #define BLOOD_SIZE_MEDIUM 2 #define BLOOD_SIZE_BIG 3 @@ -21,6 +20,8 @@ var/base_icon = 'icons/effects/blood.dmi' var/basecolor=COLOR_BLOOD_HUMAN // Color when wet. var/amount = 5 + //for 1 unit of depth in puddle (amount var) + var/time_to_dry = 5 MINUTES var/drytime var/dryname = "dried blood" var/drydesc = "It's dry and crusty. Someone isn't doing their job." @@ -29,19 +30,21 @@ var/chemical = /decl/material/liquid/blood /obj/effect/decal/cleanable/blood/reveal_blood() - if(!fluorescent) + if(ispath(chemical, /decl/material/liquid/blood) && !fluorescent) fluorescent = FLUORESCENT_GLOWS basecolor = COLOR_LUMINOL update_icon() /obj/effect/decal/cleanable/blood/clean(clean_forensics = TRUE) - fluorescent = FALSE - if(invisibility != INVISIBILITY_ABSTRACT) - set_invisibility(INVISIBILITY_ABSTRACT) - amount = 0 - STOP_PROCESSING(SSobj, src) - remove_extension(src, /datum/extension/scent) - . = ..(clean_forensics = FALSE) + if(ispath(chemical, /decl/material/liquid/blood)) + clean_forensics = FALSE + fluorescent = FALSE + if(invisibility != INVISIBILITY_ABSTRACT) + set_invisibility(INVISIBILITY_ABSTRACT) + amount = 0 + STOP_PROCESSING(SSobj, src) + remove_extension(src, /datum/extension/scent) + . = ..(clean_forensics) /obj/effect/decal/cleanable/blood/hide() return @@ -50,8 +53,11 @@ STOP_PROCESSING(SSobj, src) return ..() -/obj/effect/decal/cleanable/blood/Initialize(mapload) +// new_chemical is a material typepath, or null +/obj/effect/decal/cleanable/blood/Initialize(ml, _age, new_chemical) . = ..() + if(!isnull(new_chemical)) + chemical = new_chemical if(merge_with_blood()) return INITIALIZE_HINT_QDEL start_drying() @@ -61,16 +67,31 @@ if(!isturf(loc) || blood_size == BLOOD_SIZE_NO_MERGE) return FALSE for(var/obj/effect/decal/cleanable/blood/B in loc) - if(B != src && B.blood_size != BLOOD_SIZE_NO_MERGE) - if(B.blood_DNA) - blood_size = BLOOD_SIZE_NO_MERGE - B.blood_DNA |= blood_DNA.Copy() - B.alpha = initial(B.alpha) // reset rain-based fading due to more drips - return TRUE + if(B == src) + continue + if(B.blood_size == BLOOD_SIZE_NO_MERGE) + continue + if(B.invisibility >= INVISIBILITY_ABSTRACT) // has been cleaned + continue + if(B.chemical != chemical) // don't mix blood and oil or oil and mud etc + continue // todo: refactor to make bloody steps use reagents and track data/size/amount on there? + if(B.blood_DNA) + blood_size = BLOOD_SIZE_NO_MERGE + B.blood_DNA |= blood_DNA.Copy() + B.alpha = initial(B.alpha) // reset rain-based fading due to more drips + return TRUE return FALSE /obj/effect/decal/cleanable/blood/proc/start_drying() - drytime = world.time + DRYING_TIME * (amount+1) + var/decl/material/our_chemical = GET_DECL(chemical) + time_to_dry = our_chemical.get_time_to_dry_stain(src) + switch(time_to_dry) + if(0) // dry instantly + dry() + return + if(-INFINITY to 0) // don't even bother trying to dry this + return + drytime = world.time + time_to_dry * (amount+1) update_icon() START_PROCESSING(SSobj, src) @@ -100,6 +121,9 @@ amount-- /obj/effect/decal/cleanable/blood/proc/dry() + var/decl/material/our_chemical = GET_DECL(chemical) + if(our_chemical.handle_stain_dry(src)) + return TRUE // prevent additional drying handling; this includes preventing processing, so be careful name = dryname desc = drydesc color = adjust_brightness(color, -50) @@ -107,6 +131,7 @@ blood_data = null remove_extension(src, /datum/extension/scent) STOP_PROCESSING(SSobj, src) + return FALSE /obj/effect/decal/cleanable/blood/attack_hand(mob/user) if(!amount || !length(blood_data) || !ishuman(user)) @@ -233,7 +258,7 @@ for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) sleep(3) if (i > 0) - var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(loc) + var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(loc, null, chemical) b.basecolor = src.basecolor b.update_icon() if (step_to(src, get_step(src, direction), 0)) diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm index 330acc9f3ce0..8487334c1a4d 100644 --- a/code/game/objects/effects/decals/Cleanable/robots.dm +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -13,9 +13,6 @@ /obj/effect/decal/cleanable/blood/gibs/robot/on_update_icon() color = "#ffffff" -/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like - return - /obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions) spawn (0) var/direction = pick(directions) @@ -44,8 +41,9 @@ chemical = /decl/material/liquid/lube cleanable_scent = "industrial lubricant" -/obj/effect/decal/cleanable/blood/oil/dry() - return +/obj/effect/decal/cleanable/blood/oil/Initialize(mapload) + . = ..() + update_icon() /obj/effect/decal/cleanable/blood/oil/streak random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm index 9ef315bf7870..d2e28c977da5 100644 --- a/code/game/objects/effects/decals/Cleanable/tracks.dm +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -10,8 +10,7 @@ #define TRACKS_GOING_EAST 64 #define TRACKS_GOING_WEST 128 -// 5 seconds -#define TRACKS_CRUSTIFY_TIME 50 +#define TRACKS_CRUSTIFY_TIME 5 SECONDS /datum/fluidtrack var/direction=0 @@ -26,7 +25,8 @@ src.wet=_wet /obj/effect/decal/cleanable/blood/tracks/reveal_blood() - if(!fluorescent) + // don't reveal non-blood tracks + if(ispath(chemical, /decl/material/liquid/blood) && !fluorescent) if(stack && stack.len) for(var/datum/fluidtrack/track in stack) track.basecolor = COLOR_LUMINOL @@ -68,6 +68,7 @@ * @param bloodcolor Color of the blood when wet. */ /obj/effect/decal/cleanable/blood/tracks/proc/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor=COLOR_BLOOD_HUMAN) + var/updated=0 // Shift our goingdir 4 spaces to the left so it's in the GOING bitblock. var/realgoing=BITSHIFT_LEFT(goingdir,4) diff --git a/code/game/objects/effects/decals/posters/_poster.dm b/code/game/objects/effects/decals/posters/_poster.dm index 3d4c3bf3f3d8..2f3ca709b56c 100644 --- a/code/game/objects/effects/decals/posters/_poster.dm +++ b/code/game/objects/effects/decals/posters/_poster.dm @@ -7,9 +7,9 @@ icon = 'icons/obj/items/posters.dmi' icon_state = "poster0" anchored = TRUE - directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":-32}, "WEST":{"x":32}, "EAST":{"x":-32}}' + directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":-32}, "EAST":{"x":32}, "WEST":{"x":-32}}' material = /decl/material/solid/organic/paper - max_health = 10 + max_health = 10 parts_type = /obj/item/poster parts_amount = 1 diff --git a/code/game/objects/effects/footprints.dm b/code/game/objects/effects/footprints.dm index a8af8a6112db..09ea5bddc7bb 100644 --- a/code/game/objects/effects/footprints.dm +++ b/code/game/objects/effects/footprints.dm @@ -7,7 +7,7 @@ is_spawnable_type = FALSE blend_mode = BLEND_SUBTRACT alpha = 128 - var/list/footprints + var/list/image/footprints /obj/effect/footprints/Initialize(mapload) . = ..() @@ -15,9 +15,15 @@ name = null /obj/effect/footprints/Destroy() - QDEL_NULL(footprints) + footprints.Cut() // don't qdel images . = ..() +/obj/effect/footprints/on_turf_height_change(new_height) + if(simulated) + qdel(src) + return TRUE + return FALSE + /obj/effect/footprints/on_update_icon() set_overlays(footprints?.Copy()) compile_overlays() diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 7f70b3e996c6..ac59e8322d4a 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -34,16 +34,14 @@ if(ismob(obj)) var/mob/mob = obj mob.add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/disability))) - spawn(0) - qdel(src) + qdel(src) /obj/effect/mine/proc/triggerstun(obj) if(ismob(obj)) var/mob/M = obj SET_STATUS_MAX(M, STAT_STUN, 30) spark_at(src, cardinal_only = TRUE) - spawn(0) - qdel(src) + qdel(src) /obj/effect/mine/proc/triggern2o(obj) //example: n2o triggerproc @@ -53,8 +51,7 @@ if(target.simulated && !target.blocks_air) target.assume_gas(/decl/material/gas/nitrous_oxide, 30) - spawn(0) - qdel(src) + qdel(src) /obj/effect/mine/proc/triggerflame(obj) for (var/turf/target in range(1,src)) @@ -62,21 +59,18 @@ target.assume_gas(/decl/material/gas/hydrogen, 30) target.hotspot_expose(1000, CELL_VOLUME) - spawn(0) - qdel(src) + qdel(src) /obj/effect/mine/proc/triggerkick(obj) spark_at(src, cardinal_only = TRUE) if(ismob(obj)) var/mob/victim = obj qdel(victim.client) - spawn(0) - qdel(src) + qdel(src) /obj/effect/mine/proc/explode(obj) explosion(loc, 0, 1, 2, 3) - spawn(0) - qdel(src) + qdel(src) /obj/effect/mine/dnascramble name = "Radiation Mine" diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index a1a3fd87bd3c..2aae839cd613 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -41,9 +41,9 @@ else visible_message("\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]") - var/damage = W.get_attack_force(user) / 4 + var/damage = W.expend_attack_force(user) / 4 - if(W.edge) + if(W.has_edge()) damage += 5 if(IS_WELDER(W)) diff --git a/code/game/objects/effects/temporary.dm b/code/game/objects/effects/temporary.dm index b457013a1034..b56d38275f17 100644 --- a/code/game/objects/effects/temporary.dm +++ b/code/game/objects/effects/temporary.dm @@ -5,7 +5,7 @@ layer = ABOVE_HUMAN_LAYER mouse_opacity = MOUSE_OPACITY_UNCLICKABLE simulated = FALSE - var/duration = 10 //in deciseconds + var/duration = 1 SECOND //in deciseconds /obj/effect/temp_visual/Initialize(mapload, set_dir) if(set_dir) @@ -17,9 +17,15 @@ icon = 'icons/effects/effects.dmi' icon_state = "empdisable" +/obj/effect/temp_visual/emppulse + name = "electromagnetic pulse" + icon = 'icons/effects/effects.dmi' + icon_state = "emppulse" + duration = 2 SECONDS + /obj/effect/temp_visual/bloodsplatter icon = 'icons/effects/bloodspatter.dmi' - duration = 5 + duration = 0.5 SECONDS layer = LYING_HUMAN_LAYER var/splatter_type = "splatter" diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm index 33ea333138ce..24dad4dfb5d0 100644 --- a/code/game/objects/empulse.dm +++ b/code/game/objects/empulse.dm @@ -14,13 +14,7 @@ log_and_message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ") if(heavy_range > 1) - var/obj/effect/overlay/pulse = new/obj/effect/overlay(epicenter) - pulse.icon = 'icons/effects/effects.dmi' - pulse.icon_state = "emppulse" - pulse.SetName("electromagnetic pulse") - pulse.anchored = TRUE - spawn(20) - qdel(pulse) + new /obj/effect/temp_visual/emppulse(epicenter) if(heavy_range > light_range) light_range = heavy_range diff --git a/code/game/objects/item_mob_overlay.dm b/code/game/objects/item_mob_overlay.dm index fe253ea6f0bb..5739ddef4b1a 100644 --- a/code/game/objects/item_mob_overlay.dm +++ b/code/game/objects/item_mob_overlay.dm @@ -45,13 +45,15 @@ var/global/list/icon_state_cache = list() /proc/_fetch_icon_state_cache_entry(checkicon) if(isnull(checkicon) || !(isfile(checkicon) || isicon(checkicon))) return null - var/checkkey = "\ref[checkicon]" - var/list/check = global.icon_state_cache[checkkey] + // if we want to let people del icons (WHY???) then we can use weakreF() + // but right now it's cheaper to just use checkicon directly + // ref doesn't even do any deduplication + var/list/check = global.icon_state_cache[checkicon] if(!check) check = list() for(var/istate in icon_states(checkicon)) check[istate] = TRUE - global.icon_state_cache[checkkey] = check + global.icon_state_cache[checkicon] = check return check /obj/item/proc/update_world_inventory_state() diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm index 20c732782fa0..7c41d0aa13fb 100644 --- a/code/game/objects/items/__item.dm +++ b/code/game/objects/items/__item.dm @@ -120,6 +120,20 @@ /// Can this item knock someone out if used as a weapon? Overridden for natural weapons as a nerf to simplemobs. var/weapon_can_knock_prone = TRUE +/// Returns a dexterity value required to use this item as a weapon. +/obj/item/proc/get_required_attack_dexterity(mob/user, atom/target) + // We can likely assume that if we're located inside a rig, then the wearer + // has the appropriate dexterity to wear and use the rig, even if they aren't + // manually dexterous; specifically useful for things like baxxid and drakes. + var/obj/item/rig/rig = get_recursive_loc_of_type(/obj/item/rig) + . = istype(rig) ? DEXTERITY_NONE : needs_attack_dexterity + if(istype(target)) + . = target.adjust_required_attack_dexterity(user, .) + +// Returns a dexterity value required to interact with this item at all, such as picking it up. +/obj/item/get_required_interaction_dexterity() + return needs_interaction_dexterity + /obj/item/get_color() if(paint_color) return paint_color @@ -570,12 +584,12 @@ return TRUE return FALSE -/obj/item/proc/user_can_attack_with(mob/user, silent = FALSE) - return !needs_attack_dexterity || user.check_dexterity(needs_attack_dexterity, silent = silent) +/obj/item/proc/user_can_attack_with(mob/user, atom/target, silent = FALSE) + return user.check_dexterity(get_required_attack_dexterity(user, target), silent = silent) /obj/item/attackby(obj/item/used_item, mob/user) // if can_wield is false we still need to call parent for storage objects to work properly - var/can_wield = user_can_attack_with(user, silent = TRUE) + var/can_wield = used_item.user_can_attack_with(user, silent = TRUE) if(can_wield && try_slapcrafting(used_item, user)) return TRUE @@ -815,21 +829,19 @@ LAZYSET(blood_DNA, unique_enzymes, blood_type) return TRUE -var/global/list/_coating_overlay_cache = list() +var/global/list/icon/_coating_overlay_cache = list() var/global/icon/_item_coating_mask = icon('icons/effects/blood.dmi', "itemblood") /obj/item/proc/generate_coating_overlay(force = FALSE) if(coating_overlay && !force) return - var/cache_key = "[icon]-[icon_state]" - if(global._coating_overlay_cache[cache_key]) - coating_overlay = global._coating_overlay_cache[cache_key] - return - var/icon/I = new /icon(icon, icon_state) - I.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) // Sets the icon RGB channel to pure white. - I.Blend(global._item_coating_mask, ICON_MULTIPLY) // Masks the coating overlay against the generated mask. - coating_overlay = image(I) + var/cache_key = "\ref[icon]-[icon_state]" // this needs to use ref because of stringification + if(!global._coating_overlay_cache[cache_key]) + var/icon/I = new /icon(icon, icon_state) + I.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) // Sets the icon RGB channel to pure white. + I.Blend(global._item_coating_mask, ICON_MULTIPLY) // Masks the coating overlay against the generated mask. + global._coating_overlay_cache[cache_key] = I + coating_overlay = image(global._coating_overlay_cache[cache_key]) coating_overlay.appearance_flags |= NO_CLIENT_COLOR|RESET_COLOR - global._coating_overlay_cache[cache_key] = coating_overlay /obj/item/proc/showoff(mob/user) for(var/mob/M in view(user)) @@ -1004,11 +1016,11 @@ modules/mob/living/human/life.dm if you die, you will be zoomed out. /obj/item/proc/get_autopsy_descriptors() var/list/descriptors = list() descriptors += w_class_description() - if(sharp) + if(is_sharp()) descriptors += "sharp" - if(edge) + if(has_edge()) descriptors += "edged" - if(get_attack_force() >= 10 && !sharp && !edge) + if(get_attack_force() >= 10 && !is_sharp() && !has_edge()) descriptors += "heavy" if(material) descriptors += "made of [material.solid_name]" diff --git a/code/game/objects/items/_item_damage.dm b/code/game/objects/items/_item_damage.dm index 6d8803c33d3a..c91030262051 100644 --- a/code/game/objects/items/_item_damage.dm +++ b/code/game/objects/items/_item_damage.dm @@ -50,7 +50,7 @@ /obj/item/bash(obj/item/weapon, mob/user) . = ..() - var/force = weapon.get_attack_force(user) + var/force = weapon.expend_attack_force(user) if(force >= 3 && .) user.setClickCooldown(weapon.attack_cooldown + weapon.w_class) take_damage(force, weapon.atom_damage_type) diff --git a/code/game/objects/items/_item_force.dm b/code/game/objects/items/_item_force.dm index 3ff63de0cc7c..790d894e5962 100644 --- a/code/game/objects/items/_item_force.dm +++ b/code/game/objects/items/_item_force.dm @@ -17,6 +17,13 @@ if(can_be_twohanded) . = round(. * _wielded_force_multiplier) +/obj/item/proc/expend_attack_force(mob/living/user) + . = get_attack_force(user) + var/list/item_effects = get_item_effects(IE_CAT_DAMAGE) + if(length(item_effects)) + for(var/decl/item_effect/damage_effect as anything in item_effects) + . = damage_effect.expend_attack_use(src, user, item_effects[damage_effect]) + /obj/item/proc/get_attack_force(mob/living/user) if(_base_attack_force <= 0 || (item_flags & ITEM_FLAG_NO_BLUDGEON)) return 0 @@ -31,7 +38,7 @@ return get_object_size() /obj/item/get_thrown_attack_force() - return round(get_attack_force() * _thrown_force_multiplier) + return round(expend_attack_force() * _thrown_force_multiplier) /obj/item/proc/get_base_attack_force() return _base_attack_force @@ -43,18 +50,6 @@ _cached_attack_force = null _base_attack_force = new_force -/obj/item/proc/set_edge(new_edge) - if(edge != new_edge) - edge = new_edge - return TRUE - return FALSE - -/obj/item/proc/set_sharp(new_sharp) - if(sharp != new_sharp) - sharp = new_sharp - return TRUE - return FALSE - /obj/item/proc/update_attack_force() // Get our base force. @@ -108,10 +103,17 @@ return _cached_attack_force // TODO: consider strength, athletics, mob size +// `dry_run` param used in grindstone modpack to avoid depleting sharpness on non-attacks. /mob/living/proc/modify_attack_force(obj/item/weapon, supplied_force, wield_mult) if(!istype(weapon) || !weapon.is_held_twohanded()) - return supplied_force - return round(supplied_force * wield_mult) + . = supplied_force + else + . = supplied_force * wield_mult + var/list/item_effects = weapon.get_item_effects(IE_CAT_DAMAGE) + if(length(item_effects)) + for(var/decl/item_effect/damage_effect as anything in item_effects) + . = damage_effect.modify_attack_damage(., weapon, src, item_effects[damage_effect]) + return round(.) // Debug proc - leaving in for future work. Linter hates protected var access so leave commented. /* @@ -142,7 +144,7 @@ item = new item - var/attk_force = item.get_attack_force() + var/attk_force = item.expend_attack_force() var/expected_material_mod = ((attk_force * item._weight_force_factor) + (attk_force * item._hardness_force_factor))/2 rows += jointext(list( @@ -155,11 +157,11 @@ (attk_force + expected_material_mod), (attk_force * item._wielded_force_multiplier), item.armor_penetration, - (item.sharp||item.edge) + (item.sharp|item.edge) ), "|") text2file(jointext(rows, "\n"), "weapon_stats_dump.csv") if(fexists("weapon_stats_dump.csv")) - direct_output(usr, ftp("weapon_stats_dump.csv", "weapon_stats_dump.csv")) + ftp_to(usr, "weapon_stats_dump.csv", "weapon_stats_dump.csv") to_chat(usr, "Done.") */ diff --git a/code/game/objects/items/_item_sharpness.dm b/code/game/objects/items/_item_sharpness.dm new file mode 100644 index 000000000000..a37c1bf56fe7 --- /dev/null +++ b/code/game/objects/items/_item_sharpness.dm @@ -0,0 +1,21 @@ +/obj/item + VAR_PROTECTED/sharp = FALSE + VAR_PROTECTED/edge = FALSE + +/obj/item/is_sharp() + return sharp + +/obj/item/has_edge() + return edge + +/obj/item/proc/set_edge(new_edge) + if(edge != new_edge) + edge = new_edge + return TRUE + return FALSE + +/obj/item/proc/set_sharp(new_sharp) + if(sharp != new_sharp) + sharp = new_sharp + return TRUE + return FALSE diff --git a/code/game/objects/items/blades/_blade.dm b/code/game/objects/items/blades/_blade.dm index 60a422153994..19dbcbce1cd6 100644 --- a/code/game/objects/items/blades/_blade.dm +++ b/code/game/objects/items/blades/_blade.dm @@ -15,9 +15,11 @@ slot_flags = SLOT_LOWER_BODY material = /decl/material/solid/metal/steel _base_attack_force = 10 + var/decl/material/hilt_material = /decl/material/solid/organic/wood/oak var/decl/material/guard_material = /decl/material/solid/organic/wood/oak var/decl/material/pommel_material = /decl/material/solid/organic/wood/oak + /// Cache var for blade material shine calculation. var/tmp/shine diff --git a/code/game/objects/items/blades/folding.dm b/code/game/objects/items/blades/folding.dm index 9617f3cbb84b..281c88d523a0 100644 --- a/code/game/objects/items/blades/folding.dm +++ b/code/game/objects/items/blades/folding.dm @@ -53,9 +53,8 @@ /obj/item/bladed/folding/update_attack_force() ..() - // TODO: check sharp/edge. - edge = open - sharp = open + set_edge(open) + set_sharp(open) if(open) w_class = open_item_size attack_verb = open_attack_verbs diff --git a/code/game/objects/items/blades/spear.dm b/code/game/objects/items/blades/spear.dm index 8659642ba913..2779646e0c85 100644 --- a/code/game/objects/items/blades/spear.dm +++ b/code/game/objects/items/blades/spear.dm @@ -3,8 +3,8 @@ desc = "A haphazardly-constructed yet still deadly weapon of ancient design." icon = 'icons/obj/items/bladed/spear.dmi' throw_speed = 3 - edge = 0 - sharp = 1 + edge = FALSE + sharp = TRUE attack_verb = list("attacked", "poked", "jabbed", "torn", "gored") does_spin = FALSE abstract_type = /obj/item/bladed/polearm/spear diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index 567039e9b513..f09470bc64ec 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -147,7 +147,10 @@ // As it is, the effect can freely levitate over any open space. /obj/effect/dummy/chameleon/Move() . = ..() - if(. && isturf(loc) && loc.has_gravity() && !(locate(/obj/structure/catwalk) in loc) && !(locate(/obj/structure/lattice) in loc)) + if(!. || !isturf(loc) || !loc.has_gravity()) + return + var/turf/my_turf = loc + if(!my_turf.get_supporting_platform() && !(locate(/obj/structure/lattice) in loc)) disrupted() /datum/movement_handler/delay/chameleon_projector diff --git a/code/game/objects/items/devices/uplink.dm b/code/game/objects/items/devices/uplink.dm index f10c6c28f347..02f4eb078b7c 100644 --- a/code/game/objects/items/devices/uplink.dm +++ b/code/game/objects/items/devices/uplink.dm @@ -69,7 +69,7 @@ do var/datum/uplink_random_selection/uplink_selection = get_uplink_random_selection_by_type(/datum/uplink_random_selection/blacklist) new_discount_item = uplink_selection.get_random_item(INFINITY, src) - // Ensures we only only get items for which we get an actual discount and that this particular uplink can actually view (can buy would risk near-infinite loops). + // Ensures we only get items for which we get an actual discount and that this particular uplink can actually view (can buy would risk near-infinite loops). while(is_improper_item(new_discount_item, discount_amount)) if(!new_discount_item) return diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index b91bf589f2cc..53ec5ef987f7 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -145,7 +145,7 @@ name = "toy sword" desc = "A cheap, plastic replica of an energy sword. Realistic sounds! Ages 8 and up." sharp = FALSE - edge = FALSE + edge = FALSE attack_verb = list("hit") material = /decl/material/solid/organic/plastic active_hitsound = 'sound/weapons/genhit.ogg' @@ -497,8 +497,8 @@ desc = "An arcane weapon (made of foam) wielded by the followers of the hit Saturday morning cartoon \"King Nursee and the Acolytes of Heroism\"." icon = 'icons/obj/items/weapon/swords/cult.dmi' material = /decl/material/solid/organic/plastic/foam - edge = 0 - sharp = 0 + edge = FALSE + sharp = FALSE /obj/item/inflatable_duck //#TODO: Move under obj/item/toy ? name = "inflatable duck" diff --git a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm index a9fdaf0deab2..19054df59bde 100644 --- a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm +++ b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm @@ -18,5 +18,4 @@ /obj/item/grenade/anti_photon/proc/finish() set_light(10, 10, rgb(rand(64,255), rand(64,255), rand(64,255))) playsound(loc, 'sound/effects/bang.ogg', 50, 1, 5) - sleep(1 SECOND) - qdel(src) \ No newline at end of file + QDEL_IN(src, 1 SECOND) \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index d16532308eea..1f91dc035d8c 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -88,16 +88,16 @@ switch(det_time) if (1) det_time = 10 - to_chat(user, SPAN_NOTICE("You set the \the [src] for 1 second detonation time.")) + to_chat(user, SPAN_NOTICE("You set \the [src] for 1 second detonation time.")) if (10) det_time = 30 - to_chat(user, SPAN_NOTICE("You set the \the [src] for 3 second detonation time.")) + to_chat(user, SPAN_NOTICE("You set \the [src] for 3 second detonation time.")) if (30) det_time = 50 - to_chat(user, SPAN_NOTICE("You set the \the [src] for 5 second detonation time.")) + to_chat(user, SPAN_NOTICE("You set \the [src] for 5 second detonation time.")) if (50) det_time = 1 - to_chat(user, SPAN_NOTICE("You set the \the [src] for instant detonation.")) + to_chat(user, SPAN_NOTICE("You set \the [src] for instant detonation.")) add_fingerprint(user) return TRUE return ..() diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 8df73ff611f2..a636763ac076 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -1,5 +1,5 @@ /obj/item/grenade/spawnergrenade - desc = "It is set to detonate in 5 seconds. It will unleash unleash an unspecified anomaly into the vicinity." + desc = "It is set to detonate in 5 seconds. It will unleash an unspecified anomaly into the vicinity." name = "delivery grenade" icon = 'icons/obj/items/grenades/delivery.dmi' origin_tech = @'{"materials":3,"magnets":4}' diff --git a/code/game/objects/items/weapons/material/folding.dm b/code/game/objects/items/weapons/material/folding.dm index 46a631afe6db..38cfa3a24761 100644 --- a/code/game/objects/items/weapons/material/folding.dm +++ b/code/game/objects/items/weapons/material/folding.dm @@ -29,15 +29,14 @@ /obj/item/knife/folding/update_attack_force() ..() if(open) - // TODO: check sharp/edge. - edge = TRUE - sharp = TRUE + set_edge(TRUE) + set_sharp(TRUE) w_class = ITEM_SIZE_NORMAL attack_verb = list("slashed", "stabbed") ..() else - edge = initial(edge) - sharp = initial(sharp) + set_edge(initial(edge)) + set_sharp(initial(sharp)) w_class = initial(w_class) attack_verb = closed_attack_verbs diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index 941dd4fd8cc1..8040747110e6 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -1,8 +1,8 @@ /obj/item/harpoon name = "harpoon" desc = "A short throwing spear with a deep barb, specifically designed to embed itself in its target." - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE icon = 'icons/obj/items/weapon/harpoon.dmi' icon_state = "harpoon" item_state = "harpoon" @@ -47,8 +47,8 @@ desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow." icon = 'icons/obj/items/tool/scythe.dmi' icon_state = ICON_STATE_WORLD - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE throw_speed = 1 throw_range = 3 w_class = ITEM_SIZE_HUGE diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm index 4b0453f2154a..4150bd925322 100644 --- a/code/game/objects/items/weapons/material/shards.dm +++ b/code/game/objects/items/weapons/material/shards.dm @@ -6,8 +6,8 @@ desc = "Made of nothing. How does this even exist?" // set based on material, if this desc is visible it's a bug (shards default to being made of glass) icon_state = "large" randpixel = 8 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE w_class = ITEM_SIZE_SMALL item_state = "shard-glass" attack_verb = list("stabbed", "slashed", "sliced", "cut") @@ -96,7 +96,7 @@ playsound(src.loc, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds var/decl/species/walker_species = victim.get_species() - if(walker_species && (walker_species.get_shock_vulnerability(victim) < 0.5 || (walker_species.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT)))) //Thick skin. + if(walker_species?.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT)) //Thick skin. return var/obj/item/shoes = victim.get_equipped_item(slot_shoes_str) diff --git a/code/game/objects/items/weapons/material/stick.dm b/code/game/objects/items/weapons/material/stick.dm index a124a6644bce..d752ca73f46d 100644 --- a/code/game/objects/items/weapons/material/stick.dm +++ b/code/game/objects/items/weapons/material/stick.dm @@ -16,9 +16,9 @@ /obj/item/stick/attackby(obj/item/W, mob/user) - if(W.sharp && W.edge && !sharp) + if(W.is_sharp() && W.has_edge() && !sharp) user.visible_message("[user] sharpens [src] with [W].", "You sharpen [src] using [W].") - sharp = 1 //Sharpen stick + set_sharp(TRUE) SetName("sharpened " + name) update_attack_force() return TRUE diff --git a/code/game/objects/items/weapons/material/swiss.dm b/code/game/objects/items/weapons/material/swiss.dm index 81f5700ebd1c..44f237dc8534 100644 --- a/code/game/objects/items/weapons/material/swiss.dm +++ b/code/game/objects/items/weapons/material/swiss.dm @@ -102,8 +102,8 @@ else siemens_coefficient = initial(siemens_coefficient) else - edge = initial(edge) - sharp = initial(sharp) + set_edge(initial(edge)) + set_sharp(initial(sharp)) attack_verb = closed_attack_verbs siemens_coefficient = initial(siemens_coefficient) diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm index 19a54e6ac778..094dd9767a23 100644 --- a/code/game/objects/items/weapons/material/swords.dm +++ b/code/game/objects/items/weapons/material/swords.dm @@ -7,8 +7,8 @@ w_class = ITEM_SIZE_LARGE item_flags = ITEM_FLAG_IS_WEAPON armor_penetration = 10 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") hitsound = 'sound/weapons/bladeslice.ogg' base_parry_chance = 50 @@ -22,13 +22,13 @@ /obj/item/edge/set_edge(new_edge) . = ..() - if(. && !edge) + if(. && !has_edge()) attack_verb = list("attacked", "stabbed", "jabbed", "smacked", "prodded") hitsound = 'sound/weapons/pierce.ogg' /obj/item/sword/set_sharp(new_sharp) . = ..() - if(. && !sharp) + if(. && !is_sharp()) attack_verb = list("attacked", "smashed", "jabbed", "smacked", "prodded", "bonked") hitsound = "chop" diff --git a/code/game/objects/items/weapons/material/thrown.dm b/code/game/objects/items/weapons/material/thrown.dm index 427fffbe1022..7e878a0ac20c 100644 --- a/code/game/objects/items/weapons/material/thrown.dm +++ b/code/game/objects/items/weapons/material/thrown.dm @@ -6,8 +6,8 @@ randpixel = 12 throw_speed = 10 throw_range = 15 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE material = /decl/material/solid/metal/steel material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME item_flags = ITEM_FLAG_IS_WEAPON diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 47de3c87b7ba..bfc53022ae67 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -13,8 +13,6 @@ _base_attack_force = 3 // bonk throw_speed = 1 throw_range = 5 - sharp = 0 - edge = 0 armor_penetration = 0 material = /decl/material/solid/metal/steel @@ -90,8 +88,8 @@ if(active) obj_flags |= OBJ_FLAG_NO_STORAGE - sharp = active_sharp - edge = active_edge + set_sharp(active_sharp) + set_edge(active_edge) base_parry_chance = active_parry_chance armor_penetration = active_armour_pen hitsound = active_hitsound @@ -105,8 +103,8 @@ else obj_flags &= ~OBJ_FLAG_NO_STORAGE - sharp = initial(sharp) - edge = initial(edge) + set_sharp(initial(sharp)) + set_edge(initial(edge)) base_parry_chance = initial(base_parry_chance) armor_penetration = initial(armor_penetration) hitsound = initial(hitsound) diff --git a/code/game/objects/items/weapons/melee/energy_axe.dm b/code/game/objects/items/weapons/melee/energy_axe.dm index e70d70971f59..e7845e089858 100644 --- a/code/game/objects/items/weapons/melee/energy_axe.dm +++ b/code/game/objects/items/weapons/melee/energy_axe.dm @@ -12,8 +12,8 @@ origin_tech = @'{"magnets":3,"combat":4}' active_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") inactive_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE base_parry_chance = 30 active_parry_chance = 30 melee_accuracy_bonus = 15 diff --git a/code/game/objects/items/weapons/shields/shield_energy.dm b/code/game/objects/items/weapons/shields/shield_energy.dm index 4b028ca79316..c7d54652a56e 100644 --- a/code/game/objects/items/weapons/shields/shield_energy.dm +++ b/code/game/objects/items/weapons/shields/shield_energy.dm @@ -41,7 +41,7 @@ /obj/item/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 - if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam)) + if(((P.is_sharp() || P.has_edge()) && damage > 10) || istype(P, /obj/item/projectile/beam)) return (base_block_chance - round(damage / 2.5)) //block bullets and beams using the old block chance return base_block_chance diff --git a/code/game/objects/items/weapons/shields/shield_riot.dm b/code/game/objects/items/weapons/shields/shield_riot.dm index 378ae85d9f0e..0cc0c9324f0a 100644 --- a/code/game/objects/items/weapons/shields/shield_riot.dm +++ b/code/game/objects/items/weapons/shields/shield_riot.dm @@ -24,7 +24,7 @@ if(istype(damage_source, /obj/item/projectile)) var/obj/item/projectile/P = damage_source //plastic shields do not stop bullets or lasers, even in space. Will block beanbags, rubber bullets, and stunshots just fine though. - if(is_sharp(P) && damage >= max_block) + if((P.is_sharp() || P.has_edge()) && damage >= max_block) return 0 if(istype(P, /obj/item/projectile/beam) && (!can_block_lasers || (P.armor_penetration >= max_block))) return 0 diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 641a512ce20d..e53ef9f89e04 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -24,11 +24,11 @@ . = ..() if(overlay_flags & BELT_OVERLAY_ITEMS) var/list/cur_overlays - for(var/obj/item/I in contents) - if(I.use_single_icon) - LAZYADD(cur_overlays, I.get_on_belt_overlay()) + for(var/obj/item/thing in contents) + if(thing.use_single_icon) + LAZYADD(cur_overlays, thing.get_on_belt_overlay()) else - LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', I.icon_state)) + LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', thing.icon_state)) if(LAZYLEN(cur_overlays)) add_overlay(cur_overlays) @@ -37,8 +37,8 @@ /obj/item/belt/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) var/image/ret = ..() if(ret && slot == slot_belt_str && length(contents)) - for(var/obj/item/I in contents) - var/image/new_overlay = I.get_mob_overlay(user_mob, slot, bodypart, use_fallback_if_icon_missing, TRUE) + for(var/obj/item/thing in contents) + var/image/new_overlay = thing.get_mob_overlay(user_mob, slot, bodypart, use_fallback_if_icon_missing, TRUE) if(new_overlay) ret.overlays += new_overlay return ret @@ -57,13 +57,6 @@ . = ..() set_extension(src, /datum/extension/holster, storage, sound_in, sound_out, can_holster) -/obj/item/belt/holster/get_stored_inventory() - . = ..() - if(length(.)) - var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) - if(holster.holstered) - . -= holster.holstered - /obj/item/belt/holster/attackby(obj/item/used_item, mob/user) var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) if(holster?.holster(used_item, user)) @@ -73,27 +66,27 @@ /obj/item/belt/holster/attack_hand(mob/user) if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - if(H.unholster(user)) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster?.unholster(user)) return TRUE return ..() /obj/item/belt/holster/examine(mob/user) . = ..() - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - H.examine_holster(user) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + holster.examine_holster(user) /obj/item/belt/holster/on_update_icon() . = ..() - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) if(overlay_flags) var/list/cur_overlays - for(var/obj/item/I in contents) - if(I == H.holstered) + for(var/obj/item/thing in contents) + if(thing == holster.holstered) if(overlay_flags & BELT_OVERLAY_HOLSTER) - LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', I.icon_state)) + LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', thing.icon_state)) else if(overlay_flags & BELT_OVERLAY_ITEMS) - LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', I.icon_state)) + LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', thing.icon_state)) if(LAZYLEN(cur_overlays)) add_overlay(cur_overlays) diff --git a/code/game/objects/items/weapons/storage/fancy/_fancy.dm b/code/game/objects/items/weapons/storage/fancy/_fancy.dm index ec59092259d8..66774d7abaeb 100644 --- a/code/game/objects/items/weapons/storage/fancy/_fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy/_fancy.dm @@ -14,7 +14,11 @@ /obj/item/box/fancy/proc/update_icon_state() icon_state = initial(icon_state) - if(key_type && storage?.opened) + if(!length(contents)) + var/empty_state = "[icon_state]0" + if(check_state_in_icon(empty_state, icon)) + icon_state = empty_state + else if(key_type && storage?.opened) icon_state = "[icon_state][count_by_type(contents, key_type)]" /obj/item/box/fancy/proc/add_contents_overlays() diff --git a/code/game/objects/items/weapons/storage/mre.dm b/code/game/objects/items/weapons/storage/mre.dm index 8c2acb816db5..70bbf23d7775 100644 --- a/code/game/objects/items/weapons/storage/mre.dm +++ b/code/game/objects/items/weapons/storage/mre.dm @@ -12,6 +12,7 @@ MRE Stuff obj_flags = OBJ_FLAG_HOLLOW var/main_meal = /obj/item/mrebag var/meal_desc = "This one is menu 1, meat pizza." + var/has_been_opened = FALSE /obj/item/mre/WillContain() . = list( @@ -33,10 +34,13 @@ MRE Stuff . = ..() to_chat(user, meal_desc) +/obj/item/mre/attack_self(mob/user) + . = ..() + /obj/item/mre/on_update_icon() . = ..() icon_state = get_world_inventory_state() - if(storage?.opened) + if(has_been_opened) icon_state = "[icon_state]-open" /obj/item/mre/attack_self(mob/user) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index eec6eb5e83a0..f1d555da4d0b 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -5,8 +5,6 @@ icon = 'icons/obj/items/weapon/stunbaton.dmi' icon_state = ICON_STATE_WORLD slot_flags = SLOT_LOWER_BODY - sharp = 0 - edge = 0 w_class = ITEM_SIZE_NORMAL origin_tech = @'{"combat":2}' attack_verb = list("beaten") diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm index c5b1f30ef204..082bccc7a32a 100644 --- a/code/game/objects/items/weapons/surgery_tools.dm +++ b/code/game/objects/items/weapons/surgery_tools.dm @@ -99,8 +99,8 @@ icon = 'icons/obj/surgery.dmi' icon_state = "scalpel" obj_flags = OBJ_FLAG_CONDUCTIBLE - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS throw_speed = 3 @@ -160,8 +160,8 @@ /obj/item/incision_manager name = "incision management system" desc = "A true extension of the surgeon's body, this marvel combines several medical tools into one modular package." - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE atom_damage_type = BURN icon = 'icons/obj/surgery.dmi' icon_state = "scalpel_manager_on" @@ -202,8 +202,8 @@ material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) attack_verb = list("attacked", "slashed", "sawed", "cut") - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE pickup_sound = 'sound/foley/pickup2.ogg' drop_sound = 'sound/foley/knifedrop3.ogg' _base_attack_force = 15 diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 25ecca6f8563..eb8b3a9e3a8b 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -19,7 +19,7 @@ /obj/item/classic_baton/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) if (user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) - var/force = get_attack_force(user) + var/force = expend_attack_force(user) to_chat(user, SPAN_WARNING("You club yourself over the head.")) SET_STATUS_MAX(user, STAT_WEAK, (3 * force)) if(ishuman(user)) @@ -76,7 +76,7 @@ /obj/item/telebaton/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) if(on && user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) - var/force = get_attack_force(user) + var/force = expend_attack_force(user) to_chat(user, SPAN_DANGER("You club yourself over the head.")) SET_STATUS_MAX(user, STAT_WEAK, (3 * force)) if(ishuman(user)) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 68f46f69269a..185f9f0166d9 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -193,7 +193,7 @@ var/global/list/global/tank_gauge_cache = list() var/obj/item/weldingtool/WT = W if(WT.weld(1,user)) if(!valve_welded) - to_chat(user, "You begin welding the \the [src] emergency pressure relief valve.") + to_chat(user, "You begin welding \the [src] emergency pressure relief valve.") if(do_after(user, 40,src)) to_chat(user, "You carefully weld \the [src] emergency pressure relief valve shut. \The [src] may now rupture under pressure!") valve_welded = 1 diff --git a/code/game/objects/items/weapons/tools/shears.dm b/code/game/objects/items/weapons/tools/shears.dm index c57dff7b9e20..b5958ab00254 100644 --- a/code/game/objects/items/weapons/tools/shears.dm +++ b/code/game/objects/items/weapons/tools/shears.dm @@ -8,8 +8,8 @@ material = /decl/material/solid/metal/steel center_of_mass = @'{"x":18,"y":10}' attack_verb = list("sheared", "cut") - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE material_alteration = MAT_FLAG_ALTERATION_COLOR drop_sound = 'sound/foley/singletooldrop1.ogg' diff --git a/code/game/objects/items/weapons/tools/wirecutter.dm b/code/game/objects/items/weapons/tools/wirecutter.dm index 2886de69bc3e..7eda6a47b543 100644 --- a/code/game/objects/items/weapons/tools/wirecutter.dm +++ b/code/game/objects/items/weapons/tools/wirecutter.dm @@ -9,8 +9,8 @@ material = /decl/material/solid/metal/steel center_of_mass = @'{"x":18,"y":10}' attack_verb = list("pinched", "nipped") - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE material_alteration = MAT_FLAG_ALTERATION_COLOR drop_sound = 'sound/foley/singletooldrop1.ogg' diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 243fe2bd7e88..3d6b8c86fc51 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -64,8 +64,7 @@ /obj/item/energy_net/dropped() ..() - spawn(10) - if(src) qdel(src) + QDEL_IN(src, 1 SECOND) /obj/item/energy_net/throw_impact(atom/hit_atom) ..() @@ -85,8 +84,7 @@ qdel(src) // If we miss or hit an obstacle, we still want to delete the net. - spawn(10) - if(src) qdel(src) + QDEL_IN(src, 1 SECOND) /obj/effect/energy_net name = "energy net" @@ -193,13 +191,9 @@ /obj/effect/energy_net/attack_hand(var/mob/user) if(!user.check_intent(I_FLAG_HARM)) return ..() - var/decl/species/my_species = user.get_species() - if(my_species) - if(my_species.can_shred(user)) - playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) - current_health -= rand(10, 20) - else - current_health -= rand(1,3) + if(user.can_shred()) + playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) + current_health -= rand(10, 20) else current_health -= rand(5,8) to_chat(user, SPAN_DANGER("You claw at the energy net.")) @@ -207,7 +201,7 @@ return TRUE /obj/effect/energy_net/attackby(obj/item/W, mob/user) - current_health -= W.get_attack_force(user) + current_health -= W.expend_attack_force(user) healthcheck() return TRUE diff --git a/code/game/objects/random/subtypes/food.dm b/code/game/objects/random/subtypes/food.dm index f390e57cf5d1..36aa8a4a37e6 100644 --- a/code/game/objects/random/subtypes/food.dm +++ b/code/game/objects/random/subtypes/food.dm @@ -102,7 +102,8 @@ /obj/random/mre/spread/spawn_choices() var/static/list/spawnable_choices = list( /obj/item/chems/packet/jelly, - /obj/item/chems/packet/honey + /obj/item/chems/packet/honey, + /obj/item/chems/packet/honey_fake ) return spawnable_choices diff --git a/code/game/objects/random/subtypes/misc.dm b/code/game/objects/random/subtypes/misc.dm index a17d209574a3..9686e9846b0e 100644 --- a/code/game/objects/random/subtypes/misc.dm +++ b/code/game/objects/random/subtypes/misc.dm @@ -164,6 +164,7 @@ /obj/effect/decal/cleanable/ash, /obj/effect/decal/cleanable/generic, /obj/effect/decal/cleanable/flour, + /obj/effect/decal/cleanable/filth, /obj/effect/decal/cleanable/dirt/visible, /obj/item/remains/robot ) diff --git a/code/game/objects/structures/__structure.dm b/code/game/objects/structures/__structure.dm index f1fb8d4a2c11..7beee9b0878d 100644 --- a/code/game/objects/structures/__structure.dm +++ b/code/game/objects/structures/__structure.dm @@ -245,12 +245,12 @@ playsound(loc, 'sound/weapons/tablehit1.ogg', 50, 1) var/list/L = take_damage(rand(1,5)) for(var/obj/item/shard/S in L) - if(S.sharp && prob(50)) + if(S.is_sharp() && prob(50)) victim.visible_message( SPAN_DANGER("\The [S] slices into [victim]'s face!"), SPAN_DANGER("\The [S] slices into your face!") ) - victim.standard_weapon_hit_effects(S, user, S.get_attack_force()*2, BP_HEAD) + victim.standard_weapon_hit_effects(S, user, S.expend_attack_force()*2, BP_HEAD) qdel(grab) else if(atom_flags & ATOM_FLAG_CLIMBABLE) var/obj/occupied = turf_is_crowded() @@ -323,9 +323,21 @@ Note: This proc can be overwritten to allow for different types of auto-alignmen W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] W.pixel_z = 0 +// Does this structure override turf depth for the purposes of mob offsets? +/obj/structure/proc/is_platform() + return FALSE + +/obj/structure/proc/is_z_passable() + return TRUE + +/obj/structure/on_turf_height_change(new_height) + // We may be a fixed point. + return !is_platform() && ..() + /obj/structure/hitby(var/atom/movable/AM, var/datum/thrownthing/TT) . = ..() if(. && (structure_flags & STRUCTURE_FLAG_THROWN_DAMAGE)) visible_message(SPAN_DANGER("\The [src] was hit by \the [AM].")) playsound(src.loc, hitsound, 100, 1) take_damage(AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR), AM.atom_damage_type) + diff --git a/code/game/objects/structures/_structure_construction.dm b/code/game/objects/structures/_structure_construction.dm index 86a88084bd35..186aa29e0e0f 100644 --- a/code/game/objects/structures/_structure_construction.dm +++ b/code/game/objects/structures/_structure_construction.dm @@ -62,7 +62,7 @@ /obj/structure/attackby(obj/item/used_item, mob/user) if(used_item.user_can_attack_with(user, silent = TRUE)) - var/force = used_item.get_attack_force(user) + var/force = used_item.expend_attack_force(user) if(force && user.check_intent(I_FLAG_HARM)) attack_animation(user) visible_message(SPAN_DANGER("\The [src] has been [pick(used_item.attack_verb)] with \the [used_item] by \the [user]!")) diff --git a/code/game/objects/structures/_structure_materials.dm b/code/game/objects/structures/_structure_materials.dm index f3c619b1f61b..db8065e41d4d 100644 --- a/code/game/objects/structures/_structure_materials.dm +++ b/code/game/objects/structures/_structure_materials.dm @@ -37,14 +37,14 @@ /obj/structure/proc/update_material_name(var/override_name) var/base_name = override_name || initial(name) - if(istype(material)) + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_NAME)) SetName("[material.adjective_name] [base_name]") else SetName(base_name) /obj/structure/proc/update_material_desc(var/override_desc) var/base_desc = override_desc || initial(desc) - if(istype(material)) + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_DESC)) desc = "[base_desc] This one is made of [material.solid_name]." else desc = base_desc diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index bca9199f37db..50fb98d51d08 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -19,7 +19,7 @@ LINEN BINS material = /decl/material/solid/organic/cloth /obj/item/bedsheet/attackby(obj/item/I, mob/user) - if(is_sharp(I)) + if(I.is_sharp() || I.has_edge()) user.visible_message("\The [user] begins cutting up \the [src] with \a [I].", "You begin cutting up \the [src] with \the [I].") if(do_after(user, 50, src)) to_chat(user, "You cut \the [src] into pieces!") diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm index 944bcd3fe0fb..c51e005f3cfe 100644 --- a/code/game/objects/structures/bookcase.dm +++ b/code/game/objects/structures/bookcase.dm @@ -44,7 +44,7 @@ var/global/list/station_bookcases = list() var/place_key = GET_BOOK_POS(src, place_x, place_y) if(isnull(book_positions[place_key])) - book_positions[place_key] = inserted + book_positions[place_key] = weakref(inserted) /datum/storage/bookcase/update_ui_after_item_removal(obj/item/removed) . = ..() @@ -53,7 +53,8 @@ var/global/list/station_bookcases = list() for(var/bX = 0 to (book_slots_x-1)) for(var/bY = 0 to (book_slots_y-1)) var/bK = GET_BOOK_POS(src, bX, bY) - if(book_positions[bK] == removed) + var/weakref/potential_book = book_positions[bK] + if(IS_WEAKREF_OF(potential_book, removed)) book_positions[bK] = null return @@ -65,8 +66,9 @@ var/global/list/station_bookcases = list() for(var/bX = 0 to (book_slots_x-1)) for(var/bY = 0 to (book_slots_y-1)) var/bK = GET_BOOK_POS(src, bX, bY) - var/obj/item/thing = book_positions[bK] - if(!isnull(thing) && (QDELETED(thing) || thing.loc != holder)) + var/weakref/book_ref = book_positions[bK] + var/obj/item/thing = book_ref?.resolve() + if(!isnull(thing) && (QDELING(thing) || thing.loc != holder)) // QDELING because it might be deleting but hasn't been moved to nullspace yet book_positions[bK] = null for(var/obj/item/thing in holder.get_stored_inventory()) @@ -75,7 +77,8 @@ var/global/list/station_bookcases = list() // Avoid moving us if we're already positioned for(var/bX = 0 to (book_slots_x-1)) for(var/bY = 0 to (book_slots_y-1)) - if(book_positions[GET_BOOK_POS(src, bX, bY)] == thing) + var/weakref/potential_book = book_positions[GET_BOOK_POS(src, bX, bY)] + if(IS_WEAKREF_OF(potential_book, thing)) positioned = TRUE break if(positioned) @@ -89,7 +92,7 @@ var/global/list/station_bookcases = list() for(var/bY = 0 to (book_slots_y-1)) var/bK = GET_BOOK_POS(src, bX, bY) if(isnull(book_positions[bK])) - book_positions[bK] = thing + book_positions[bK] = weakref(thing) positioned = TRUE break if(positioned) @@ -154,12 +157,13 @@ var/global/list/station_bookcases = list() for(var/bY = 0 to (book_storage.book_slots_y-1)) var/bK = (bY * book_storage.book_slots_x) + bX + 1 - var/obj/item/book = book_storage.book_positions[bK] + var/weakref/book_ref = book_storage.book_positions[bK] + var/obj/item/book = book_ref?.resolve() if(!istype(book) || !check_state_in_icon("bookcase", book.icon)) continue var/use_lying_state = "bookcase" - if(bX < (book_storage.book_slots_x-1) && isnull(book_storage.book_positions[bK+1]) && check_state_in_icon("bookcase_flat", book.icon)) + if(bX < (book_storage.book_slots_x-1) && !isnull(book_storage.book_positions[bK+1]) && check_state_in_icon("bookcase_flat", book.icon)) use_lying_state = "bookcase_flat" var/image/book_overlay = overlay_image(book.icon, use_lying_state, book.get_color(), RESET_COLOR) diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index 28d320d564f9..b7186e1926d5 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -19,14 +19,6 @@ var/list/connections var/list/other_connections -/obj/structure/catwalk/clear_connections() - connections = null - other_connections = null - -/obj/structure/catwalk/set_connections(dirs, other_dirs) - connections = dirs_to_corner_states(dirs) - other_connections = dirs_to_corner_states(other_dirs) - /obj/structure/catwalk/Initialize() . = ..() DELETE_IF_DUPLICATE_OF(/obj/structure/catwalk) @@ -41,9 +33,6 @@ update_connections(1) update_icon() -/obj/structure/catwalk/can_climb_from_below(var/mob/climber) - return TRUE - /obj/structure/catwalk/Destroy() var/turf/oldloc = loc redraw_nearby_catwalks() @@ -51,6 +40,26 @@ if(istype(oldloc)) for(var/atom/movable/AM in oldloc) AM.fall(oldloc) + oldloc.supporting_platform = null + +// Catwalks need to layer over grass and water. +/obj/structure/catwalk/update_turf_alpha_mask() + return FALSE + +/obj/structure/catwalk/clear_connections() + connections = null + other_connections = null + +/obj/structure/catwalk/is_platform() + return TRUE + +/obj/structure/catwalk/set_connections(dirs, other_dirs) + connections = dirs_to_corner_states(dirs) + other_connections = dirs_to_corner_states(other_dirs) + +/obj/structure/catwalk/can_climb_from_below(var/mob/climber) + return TRUE + /obj/structure/catwalk/proc/redraw_nearby_catwalks() for(var/direction in global.alldirs) @@ -170,6 +179,9 @@ /obj/structure/catwalk/refresh_neighbors() return +/obj/structure/catwalk/is_z_passable() + return !plated_tile + /obj/effect/catwalk_plated name = "plated catwalk spawner" icon = 'icons/obj/structures/catwalks.dmi' diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm index 2360879e4272..089425bcc9dc 100644 --- a/code/game/objects/structures/coathanger.dm +++ b/code/game/objects/structures/coathanger.dm @@ -46,7 +46,7 @@ var/obj/item/removing = contents[contents.len] user.visible_message( \ SPAN_NOTICE("\The [user] takes \the [removing] off \the [src]."), - SPAN_NOTICE("You take \the [removing] off the \the [src].") + SPAN_NOTICE("You take \the [removing] off \the [src].") ) removing.dropInto(loc) user.put_in_active_hand(removing) @@ -79,7 +79,7 @@ if(user.try_unequip(W, src)) user.visible_message( \ SPAN_NOTICE("\The [user] hangs \the [W] on \the [src]."), \ - SPAN_NOTICE("You hang \the [W] on the \the [src].") \ + SPAN_NOTICE("You hang \the [W] on \the [src].") \ ) update_icon() return TRUE diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index b34c334d77e1..27a6d55f4fce 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -99,7 +99,7 @@ check_health() /obj/structure/closet/statue/attackby(obj/item/I, mob/user) - current_health -= I.get_attack_force(user) + current_health -= I.expend_attack_force(user) user.do_attack_animation(src) visible_message("[user] strikes [src] with [I].") check_health() diff --git a/code/game/objects/structures/defensive_barrier.dm b/code/game/objects/structures/defensive_barrier.dm index d3d977f5b84e..7545fcc06413 100644 --- a/code/game/objects/structures/defensive_barrier.dm +++ b/code/game/objects/structures/defensive_barrier.dm @@ -105,8 +105,7 @@ if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() - var/decl/species/species = user.get_species() - if(ishuman(user) && species?.can_shred(user) && user.check_intent(I_FLAG_HARM)) + if(user.can_shred() && user.check_intent(I_FLAG_HARM)) take_damage(20) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) return TRUE diff --git a/code/game/objects/structures/fireaxe_cabinet.dm b/code/game/objects/structures/fireaxe_cabinet.dm index f16681fa2d49..ec563ffce7e7 100644 --- a/code/game/objects/structures/fireaxe_cabinet.dm +++ b/code/game/objects/structures/fireaxe_cabinet.dm @@ -81,7 +81,7 @@ update_icon() return TRUE - var/force = O.get_attack_force(user) + var/force = O.expend_attack_force(user) if(force) user.setClickCooldown(10) attack_animation(user) diff --git a/code/game/objects/structures/flora/_flora.dm b/code/game/objects/structures/flora/_flora.dm index 5395ed57f9a3..c38361f4a845 100644 --- a/code/game/objects/structures/flora/_flora.dm +++ b/code/game/objects/structures/flora/_flora.dm @@ -34,7 +34,7 @@ /**Whether the item used by user can cause cut_down to be called. Used to bypass default attack proc for some specific items/tools. */ /obj/structure/flora/proc/can_cut_down(var/obj/item/I, var/mob/user) - return (I.get_attack_force(user) >= 5) && I.sharp //Anything sharp and relatively strong can cut us instantly + return (I.expend_attack_force(user) >= 5) && I.is_sharp() //Anything sharp and relatively strong can cut us instantly /**What to do when the can_cut_down check returns true. Normally simply calls dismantle. */ /obj/structure/flora/proc/play_cut_sound(mob/user) diff --git a/code/game/objects/structures/flora/plant.dm b/code/game/objects/structures/flora/plant.dm index 615e9229cb48..ceb0b5e205e3 100644 --- a/code/game/objects/structures/flora/plant.dm +++ b/code/game/objects/structures/flora/plant.dm @@ -81,7 +81,7 @@ return TRUE // Hydrotray boilerplate for taking samples. - if(O.edge && O.w_class < ITEM_SIZE_NORMAL && !user.check_intent(I_FLAG_HARM)) + if(O.has_edge() && O.w_class < ITEM_SIZE_NORMAL && !user.check_intent(I_FLAG_HARM)) if(sampled) to_chat(user, SPAN_WARNING("There's no bits that can be used for a sampling left.")) return TRUE diff --git a/code/game/objects/structures/flora/tree.dm b/code/game/objects/structures/flora/tree.dm index 9ad3314fc775..a088f2297cf2 100644 --- a/code/game/objects/structures/flora/tree.dm +++ b/code/game/objects/structures/flora/tree.dm @@ -102,6 +102,7 @@ /obj/structure/flora/tree/pine/init_appearance() icon_state = "pine_[rand(1, 3)]" +var/global/list/christmas_trees = list() /obj/structure/flora/tree/pine/xmas name = "\improper Christmas tree" desc = "O Christmas tree, O Christmas tree..." @@ -109,6 +110,14 @@ icon_state = "pine_c" stump_type = /obj/structure/flora/stump/tree/pine/xmas +/obj/structure/flora/tree/pine/xmas/Initialize(ml, _mat, _reinf_mat) + . = ..() + global.christmas_trees += src + +/obj/structure/flora/tree/pine/xmas/Destroy() + global.christmas_trees -= src + return ..() + /obj/structure/flora/tree/pine/xmas/init_appearance() return //Only one possible icon diff --git a/code/game/objects/structures/fountain.dm b/code/game/objects/structures/fountain.dm index 8d1c904c785a..c92c9d360b1f 100644 --- a/code/game/objects/structures/fountain.dm +++ b/code/game/objects/structures/fountain.dm @@ -1,20 +1,22 @@ //the fountain of youth/unyouth /obj/structure/fountain - name = "strange fountain" - desc = "The water from the spout is still as if frozen in time, yet the water in the base ripples perpetually." - icon = 'icons/obj/fountain.dmi' - icon_state = "fountain" - density = TRUE - anchored = TRUE - pixel_x = -16 - var/used = FALSE + name = "strange fountain" + desc = "The water from the spout is still as if frozen in time, yet the water in the base ripples perpetually." + icon = 'icons/obj/fountain.dmi' + icon_state = "fountain" + density = TRUE + anchored = TRUE + pixel_x = -16 + light_range = 5 + light_power = 0.5 + var/used = FALSE var/increase_age_prob = (100 / 6) /obj/structure/fountain/Initialize(ml, _mat, _reinf_mat) + if(light_range && light_power) + light_color = get_random_colour(lower = 190) . = ..() - light_color = get_random_colour(lower = 190) - set_light(5, 0.5, light_color) /obj/structure/fountain/attack_hand(var/mob/user) @@ -48,7 +50,7 @@ L.flash_eyes(3) SET_STATUS_MAX(L, STAT_BLURRY, 9) - visible_message("\The [src] erupts in a bright flash of light!") + visible_message(SPAN_WARNING("\The [src] erupts in a bright flash of light!")) playsound(src,'sound/items/time.ogg',100) var/old_age = user.get_age() @@ -65,19 +67,19 @@ new_age = max(new_age, min_age) // This will clamp to the max defined age already so only need to min() if(new_age == old_age) - to_chat(user, "You touch the fountain, and feel your memories sifted through by a great presence. Then, it withdraws, leaving you unchanged.") + to_chat(user, SPAN_CULT_ANNOUNCE("You touch the fountain, and feel your memories sifted through by a great presence. Then, it withdraws, leaving you unchanged.")) else user.set_age(new_age) if(new_age < old_age) - to_chat(user, "You touch the fountain. Everything stops - then reverses. You relive in an instant the events of your life. The fountain, yesterday's lunch, your first love, your first kiss. It all feels as though it just happened moments ago. Then it feels like it never happened at all. Time reverses back into normality and continues its advance. You feel great, but why are you here?") + to_chat(user, SPAN_CULT_ANNOUNCE("You touch the fountain. Everything stops - then reverses. You relive in an instant the events of your life. The fountain, yesterday's lunch, your first love, your first kiss. It all feels as though it just happened moments ago. Then it feels like it never happened at all. Time reverses back into normality and continues its advance. You feel great, but why are you here?")) user.became_younger = TRUE else - to_chat(user, "You touch the fountain. All the memories of your life seem to fade into the distant past as seconds drag like years. You feel the inexplicable sensation of your skin tightening and thinning across your entire body as your muscles degrade and your joints weaken. Time returns to its 'normal' pace. You can only just barely remember touching the fountain.") + to_chat(user, SPAN_CULT_ANNOUNCE("You touch the fountain. All the memories of your life seem to fade into the distant past as seconds drag like years. You feel the inexplicable sensation of your skin tightening and thinning across your entire body as your muscles degrade and your joints weaken. Time returns to its 'normal' pace. You can only just barely remember touching the fountain.")) user.became_older = TRUE SET_HAIR_COLOR(user, COLOR_GRAY80, FALSE) var/max_age = age.standalone_value_descriptors[age.standalone_value_descriptors[length(age.standalone_value_descriptors)]] if(new_age >= max_age) - to_chat(user, "The burden of the years is too much, and you are reduced to dust.") + to_chat(user, SPAN_CULT_ANNOUNCE("The burden of the years is too much, and you are reduced to dust.")) user.dust() used = TRUE @@ -93,6 +95,8 @@ used = TRUE material_alteration = MAT_FLAG_ALTERATION_ALL atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_CLIMBABLE + light_range = null + light_power = null /obj/structure/fountain/mundane/Initialize(ml, _mat, _reinf_mat) . = ..() diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 39080d777fb9..f1717f3be263 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -85,7 +85,8 @@ add_overlay(I) /obj/structure/grille/Bumped(atom/user) - if(ismob(user)) shock(user, 70) + if(ismob(user)) + shock(user, 70) /obj/structure/grille/attack_hand(mob/user) @@ -101,12 +102,10 @@ var/damage_dealt = 1 var/attack_message = "kicks" - if(ishuman(user)) - var/mob/living/human/H = user - if(H.species.can_shred(H)) - attack_message = "mangles" - damage_dealt = 5 - attack_generic(user,damage_dealt,attack_message) + if(user.can_shred()) + attack_message = "mangles" + damage_dealt = 5 + attack_generic(user, damage_dealt, attack_message) return TRUE /obj/structure/grille/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) @@ -211,9 +210,9 @@ playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) switch(W.atom_damage_type) if(BURN) - take_damage(W.get_attack_force(user)) + take_damage(W.expend_attack_force(user)) if(BRUTE) - take_damage(W.get_attack_force(user) * 0.1) + take_damage(W.expend_attack_force(user) * 0.1) return TRUE return ..() @@ -229,25 +228,23 @@ // returns 1 if shocked, 0 otherwise /obj/structure/grille/proc/shock(mob/user, prb) if(!anchored || destroyed) // anchored/destroyed grilles are never connected - return 0 + return FALSE if(!(material.conductive)) - return 0 + return FALSE if(!prob(prb)) - return 0 + return FALSE if(!in_range(src, user))//To prevent TK and exosuit users from getting shocked - return 0 - var/turf/T = get_turf(src) - var/obj/structure/cable/C = T.get_cable_node() - if(C) - if(electrocute_mob(user, C, src)) - if(C.powernet) - C.powernet.trigger_warning() - spark_at(src, cardinal_only = TRUE) - if(HAS_STATUS(user, STAT_STUN)) - return 1 - else - return 0 - return 0 + return FALSE + var/turf/my_turf = get_turf(src) + var/obj/structure/cable/cable = my_turf.get_cable_node() + if(!cable) + return FALSE + if(!electrocute_mob(user, cable, src)) + return FALSE + if(cable.powernet) + cable.powernet.trigger_warning() + spark_at(src, cardinal_only = TRUE) + return !!HAS_STATUS(user, STAT_STUN) /obj/structure/grille/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(!destroyed) diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 12cdf96b365f..825e04a5ba66 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -139,7 +139,7 @@ /obj/structure/inflatable/attackby(obj/item/W, mob/user) - if((W.atom_damage_type == BRUTE || W.atom_damage_type == BURN) && (W.can_puncture() || W.get_attack_force(user) > 10)) + if((W.atom_damage_type == BRUTE || W.atom_damage_type == BURN) && (W.can_puncture() || W.expend_attack_force(user) > 10)) visible_message(SPAN_DANGER("\The [user] pierces \the [src] with \the [W]!")) deflate(TRUE) return TRUE diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index cfdce2510d78..3de7c1dba7b2 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -88,12 +88,13 @@ return TRUE var/obj/item/stack/material/rods/R = C - if(locate(/obj/structure/catwalk) in get_turf(src)) - to_chat(user, SPAN_WARNING("There is already a catwalk here.")) + var/turf/my_turf = get_turf(src) + if(my_turf?.get_supporting_platform()) + to_chat(user, SPAN_WARNING("There is already a platform here.")) return TRUE else if(R.use(2)) playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - new /obj/structure/catwalk(src.loc, R.material.type) + new /obj/structure/catwalk(my_turf, R.material.type) return TRUE else to_chat(user, SPAN_WARNING("You require at least two rods to complete the catwalk.")) diff --git a/code/game/objects/structures/quicksand.dm b/code/game/objects/structures/quicksand.dm index 383b435943b3..d891b03a6eaf 100644 --- a/code/game/objects/structures/quicksand.dm +++ b/code/game/objects/structures/quicksand.dm @@ -80,7 +80,7 @@ update_icon() /obj/effect/quicksand/attackby(obj/item/W, mob/user) - if(!exposed && W.get_attack_force(user)) + if(!exposed && W.expend_attack_force(user)) expose() return TRUE else diff --git a/code/game/objects/structures/racks.dm b/code/game/objects/structures/racks.dm index 3ade37d94fe8..2cbeb5bb7f58 100644 --- a/code/game/objects/structures/racks.dm +++ b/code/game/objects/structures/racks.dm @@ -29,6 +29,12 @@ I.pixel_y = max(3-i*3, -3) + 1 I.pixel_z = 0 +/obj/structure/rack/adjust_required_attack_dexterity(mob/user, required_dexterity) + // Let people put stuff on tables without necessarily being able to use a gun or such. + if(user?.check_intent(I_FLAG_HELP)) + return DEXTERITY_HOLD_ITEM + return ..() + /obj/structure/rack/attackby(obj/item/O, mob/user, click_params) . = ..() if(!. && !isrobot(user) && O.loc == user && user.try_unequip(O, loc)) diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm index 96c1baf5b0aa..2ae373f0513d 100644 --- a/code/game/objects/structures/railing.dm +++ b/code/game/objects/structures/railing.dm @@ -291,7 +291,7 @@ WOOD_RAILING_SUBTYPE(yew) update_icon() return TRUE - var/force = W.get_attack_force(user) + var/force = W.expend_attack_force(user) if(force && (W.atom_damage_type == BURN || W.atom_damage_type == BRUTE)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) visible_message("\The [src] has been [LAZYLEN(W.attack_verb) ? pick(W.attack_verb) : "attacked"] with \the [W] by \the [user]!") diff --git a/code/game/objects/structures/seaweed.dm b/code/game/objects/structures/seaweed.dm index 52a5af6125c8..bfa52f88a189 100644 --- a/code/game/objects/structures/seaweed.dm +++ b/code/game/objects/structures/seaweed.dm @@ -31,7 +31,7 @@ icon = 'icons/obj/structures/plants.dmi' /obj/effect/decal/cleanable/lichen/attackby(obj/item/I, mob/user) - if(I.sharp && I.get_attack_force(user) > 1) + if(I.is_sharp() && I.expend_attack_force(user) > 1) qdel(src) return TRUE . = ..() \ No newline at end of file diff --git a/code/game/objects/structures/stool_bed_chair_nest_sofa/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest_sofa/wheelchair.dm index 67640a583fdf..c6b882a2a67c 100644 --- a/code/game/objects/structures/stool_bed_chair_nest_sofa/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest_sofa/wheelchair.dm @@ -12,6 +12,7 @@ tool_interaction_flags = 0 var/item_form_type = /obj/item/wheelchair_kit + // TODO: Replace with reagent holder? This doesn't even properly handle non-human bloodstains. var/bloodiness /obj/structure/bed/chair/wheelchair/Initialize() diff --git a/code/game/objects/structures/tables.dm b/code/game/objects/structures/tables.dm index 459216c264a5..68fba3649734 100644 --- a/code/game/objects/structures/tables.dm +++ b/code/game/objects/structures/tables.dm @@ -41,12 +41,6 @@ /obj/structure/table/should_have_alpha_mask() return simulated && isturf(loc) && !(locate(/obj/structure/table) in get_step(loc, SOUTH)) -/obj/structure/table/clear_connections() - connections = null - -/obj/structure/table/set_connections(dirs, other_dirs) - connections = dirs_to_corner_states(dirs) - /obj/structure/table/Initialize() if(ispath(additional_reinf_material, /decl/material)) additional_reinf_material = GET_DECL(additional_reinf_material) @@ -69,6 +63,29 @@ update_connections(TRUE) update_icon() +/obj/structure/table/Destroy() + var/turf/oldloc = loc + additional_reinf_material = null + . = ..() + if(istype(oldloc)) + for(var/obj/structure/table/table in range(oldloc, 1)) + if(QDELETED(table)) + continue + table.update_connections(FALSE) + table.update_icon() + +/obj/structure/table/adjust_required_attack_dexterity(mob/user, required_dexterity) + // Let people put stuff on tables without necessarily being able to use a gun or such. + if(user?.check_intent(I_FLAG_HELP)) + return DEXTERITY_HOLD_ITEM + return ..() + +/obj/structure/table/clear_connections() + connections = null + +/obj/structure/table/set_connections(dirs, other_dirs) + connections = dirs_to_corner_states(dirs) + /obj/structure/table/get_material_health_modifier() . = additional_reinf_material ? 0.75 : 0.5 @@ -106,17 +123,6 @@ felted = FALSE additional_reinf_material = null -/obj/structure/table/Destroy() - var/turf/oldloc = loc - additional_reinf_material = null - . = ..() - if(istype(oldloc)) - for(var/obj/structure/table/table in range(oldloc, 1)) - if(QDELETED(table)) - continue - table.update_connections(FALSE) - table.update_icon() - /obj/structure/table/can_dismantle(mob/user) . = ..() if(.) diff --git a/code/game/objects/structures/town_bell.dm b/code/game/objects/structures/town_bell.dm index 4a0faee50f5f..45cb1f484511 100644 --- a/code/game/objects/structures/town_bell.dm +++ b/code/game/objects/structures/town_bell.dm @@ -48,7 +48,7 @@ /obj/structure/town_bell/attackby(obj/item/used_item, mob/user) . = ..() - if(used_item.get_attack_force()) + if(used_item.expend_attack_force()) ding_dong() /obj/structure/town_bell/attack_hand(mob/user) diff --git a/code/game/objects/structures/transit_tubes.dm b/code/game/objects/structures/transit_tubes.dm index 289b7d7c251d..b7fba083f5c9 100644 --- a/code/game/objects/structures/transit_tubes.dm +++ b/code/game/objects/structures/transit_tubes.dm @@ -45,7 +45,12 @@ var/moving = 0 var/datum/gas_mixture/air_contents = new() - +/obj/structure/transit_tube_pod/attack_hand(mob/user) + if(!moving && length(contents) && isturf(user.loc)) + user.visible_message(SPAN_NOTICE("\The [user] empties out \the [src]!")) + dump_contents() + return TRUE + return ..() /obj/structure/transit_tube_pod/Destroy() dump_contents() diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index d516cd10eb23..7b9c56f71107 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -147,21 +147,23 @@ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if (user.check_intent(I_FLAG_HARM)) - if (ishuman(user)) - var/mob/living/human/H = user - if(H.species.can_shred(H)) - return attack_generic(H,25) + if(user.can_shred()) + return attack_generic(user, 25) playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) user.do_attack_animation(src) - user.visible_message(SPAN_DANGER("\The [user] bangs against \the [src]!"), - SPAN_DANGER("You bang against \the [src]!"), - "You hear a banging sound.") + user.visible_message( + SPAN_DANGER("\The [user] bangs against \the [src]!"), + SPAN_DANGER("You bang against \the [src]!"), + "You hear a banging sound." + ) else playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) - user.visible_message("[user.name] knocks on \the [src].", - "You knock on \the [src].", - "You hear a knocking sound.") + user.visible_message( + SPAN_NOTICE("\The [user] knocks on \the [src]."), + SPAN_NOTICE("You knock on \the [src]."), + "You hear a knocking sound." + ) return TRUE /obj/structure/window/do_simple_ranged_interaction(var/mob/user) @@ -292,7 +294,7 @@ // physical damage types that can impart force; swinging a bat or energy sword if(weapon.atom_damage_type == BRUTE || weapon.atom_damage_type == BURN) user.do_attack_animation(src) - hit(weapon.get_attack_force(user)) + hit(weapon.expend_attack_force(user)) if(current_health <= 7) set_anchored(FALSE) step(src, get_dir(user, src)) diff --git a/code/game/turfs/flooring/_flooring.dm b/code/game/turfs/flooring/_flooring.dm index d30c22285702..7618f0600eaa 100644 --- a/code/game/turfs/flooring/_flooring.dm +++ b/code/game/turfs/flooring/_flooring.dm @@ -378,6 +378,8 @@ var/global/list/flooring_cache = list() /decl/flooring/proc/try_place_footprints(atom/movable/crosser, turf/target, turf/from_turf, turf/to_turf, use_state = "going") if(!ismob(crosser) || !crosser.simulated || !isturf(from_turf) || !isturf(to_turf)) return FALSE + if(target.check_fluid_depth(FLUID_QDEL_POINT)) + return FALSE var/movement_dir = get_dir(from_turf, to_turf) if(!movement_dir) return FALSE @@ -391,5 +393,7 @@ var/global/list/flooring_cache = list() /decl/flooring/proc/turf_crossed(atom/movable/crosser) return -/decl/flooring/proc/can_show_coating_footprints(turf/target) +/// target is the turf that wants to know if it supports footprints +/// contaminant is, optionally, the material of the coating that wants to be added. +/decl/flooring/proc/can_show_coating_footprints(turf/target, decl/material/contaminant) return TRUE diff --git a/code/game/turfs/flooring/flooring_lava.dm b/code/game/turfs/flooring/flooring_lava.dm index 9fe4be66e462..d8137d15b356 100644 --- a/code/game/turfs/flooring/flooring_lava.dm +++ b/code/game/turfs/flooring/flooring_lava.dm @@ -13,7 +13,7 @@ /decl/flooring/lava/handle_environment_proc(turf/floor/target) . = PROCESS_KILL - if(locate(/obj/structure/catwalk) in target) + if(target.get_supporting_platform()) return var/datum/gas_mixture/environment = target.return_air() var/pressure = environment?.return_pressure() diff --git a/code/game/turfs/flooring/flooring_mud.dm b/code/game/turfs/flooring/flooring_mud.dm index a4865eb5fe7f..d6d77b4e9e31 100644 --- a/code/game/turfs/flooring/flooring_mud.dm +++ b/code/game/turfs/flooring/flooring_mud.dm @@ -25,10 +25,12 @@ if(!isliving(crosser)) return var/mob/living/walker = crosser - walker.add_walking_contaminant(/decl/material/solid/soil, rand(2,3)) + walker.add_walking_contaminant(force_material.type, rand(2,3)) -/decl/flooring/mud/can_show_coating_footprints(turf/target) - return FALSE // So we don't end up covered in a million footsteps that we provided. +/decl/flooring/mud/can_show_coating_footprints(turf/target, decl/material/contaminant) + if(force_material.type == contaminant) // So we don't end up covered in a million footsteps that we provided. + return FALSE + return ..() /decl/flooring/dry_mud name = "dry mud" diff --git a/code/game/turfs/flooring/flooring_snow.dm b/code/game/turfs/flooring/flooring_snow.dm index 834b109eea7d..f1d1dded76ed 100644 --- a/code/game/turfs/flooring/flooring_snow.dm +++ b/code/game/turfs/flooring/flooring_snow.dm @@ -4,6 +4,7 @@ icon = 'icons/turf/flooring/snow.dmi' icon_base = "snow" icon_edge_layer = FLOOR_EDGE_SNOW + flooring_flags = TURF_REMOVE_SHOVEL footstep_type = /decl/footsteps/snow has_base_range = 13 force_material = /decl/material/solid/ice/snow @@ -31,6 +32,19 @@ return return ..() +/decl/flooring/snow/turf_crossed(atom/movable/crosser) + if(!isliving(crosser)) + return + var/mob/living/walker = crosser + // at some point this might even be able to use the height + // of the snow flooring layer, so deep snow gives you more coating + walker.add_walking_contaminant(force_material.type, rand(1, 2)) + +/decl/flooring/snow/can_show_coating_footprints(turf/target, decl/material/contaminant) + if(force_material.type == contaminant) // So we don't end up covered in a million footsteps that we provided. + return FALSE + return ..() + /decl/flooring/permafrost name = "permafrost" desc = "A stretch of frozen soil that hasn't seen a thaw for many seasons." diff --git a/code/game/turfs/floors/_floor.dm b/code/game/turfs/floors/_floor.dm index 844b479eaa12..d7e8441fda07 100644 --- a/code/game/turfs/floors/_floor.dm +++ b/code/game/turfs/floors/_floor.dm @@ -44,8 +44,7 @@ if(floortype) set_flooring(GET_DECL(floortype), skip_update = TRUE) - if(fill_reagent_type && get_physical_height() < 0) - add_to_reagents(fill_reagent_type, abs(height), phase = MAT_PHASE_LIQUID) + fill_to_zero_height() // try to refill turfs that act as fluid sources if(floor_material || get_topmost_flooring()) if(ml) @@ -71,6 +70,12 @@ STOP_PROCESSING(SSobj, src) return ..() +/turf/floor/proc/fill_to_zero_height() + var/my_height = get_physical_height() + if(fill_reagent_type && my_height < 0 && (!reagents || !QDELING(reagents)) && reagents?.total_volume < abs(my_height)) + var/reagents_to_add = abs(my_height) - reagents?.total_volume + add_to_reagents(fill_reagent_type, reagents_to_add, phase = MAT_PHASE_LIQUID) + /turf/floor/can_climb_from_below(var/mob/climber) return TRUE @@ -92,9 +97,9 @@ /turf/floor/on_reagent_change() . = ..() - var/my_height = get_physical_height() - if(!QDELETED(src) && fill_reagent_type && my_height < 0 && !QDELETED(reagents) && reagents.total_volume < abs(my_height)) - add_to_reagents(fill_reagent_type, abs(my_height) - reagents.total_volume) + if(!QDELETED(src)) + fill_to_zero_height() + update_floor_strings() /turf/floor/proc/set_base_flooring(new_base_flooring, skip_update) if(ispath(new_base_flooring, /decl/flooring)) @@ -309,5 +314,5 @@ flooring?.turf_crossed(AM) return ..() -/turf/floor/can_show_coating_footprints() - return ..() && get_topmost_flooring()?.can_show_coating_footprints(src) +/turf/floor/can_show_coating_footprints(decl/material/contaminant = null) + return ..() && get_topmost_flooring()?.can_show_coating_footprints(src, contaminant) diff --git a/code/game/turfs/floors/floor_attackby.dm b/code/game/turfs/floors/floor_attackby.dm index f56777dd1c80..8b81baf3ae7a 100644 --- a/code/game/turfs/floors/floor_attackby.dm +++ b/code/game/turfs/floors/floor_attackby.dm @@ -28,7 +28,7 @@ return ..() /turf/floor/proc/try_build_catwalk(var/obj/item/used_item, var/mob/user) - if(!(locate(/obj/structure/catwalk) in src) && istype(used_item, /obj/item/stack/material/rods)) + if(istype(used_item, /obj/item/stack/material/rods) && !get_supporting_platform()) var/obj/item/stack/material/rods/R = used_item if (R.use(2)) playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) diff --git a/code/game/turfs/floors/floor_digging.dm b/code/game/turfs/floors/floor_digging.dm index d3cadac07f98..123458d009cd 100644 --- a/code/game/turfs/floors/floor_digging.dm +++ b/code/game/turfs/floors/floor_digging.dm @@ -1,13 +1,15 @@ /turf/floor var/gemstone_dropped = FALSE -/turf/floor/proc/is_fundament() +/turf/floor/proc/flooring_is_diggable() var/decl/flooring/flooring = get_topmost_flooring() - return flooring ? !flooring.constructed : TRUE + if(!flooring || flooring.constructed) + return FALSE + return TRUE /turf/floor/can_be_dug(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) // This should be removed before digging trenches. - if(!is_fundament()) + if(!flooring_is_diggable()) return FALSE var/decl/flooring/flooring = get_base_flooring() if(istype(flooring) && flooring.constructed) @@ -27,7 +29,7 @@ return can_be_dug(tool_hardness, using_tool) && get_physical_height() > -(FLUID_DEEP) /turf/floor/dig_trench(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) - if(is_fundament()) + if(flooring_is_diggable()) handle_trench_digging(user) /turf/floor/proc/handle_trench_digging(mob/user) @@ -47,7 +49,7 @@ /turf/floor/get_diggable_resources() var/decl/material/my_material = get_material() - if(!is_fundament() || !istype(my_material) || !my_material.dug_drop_type || (get_physical_height() <= -(FLUID_DEEP))) + if(!flooring_is_diggable() || !istype(my_material) || !my_material.dug_drop_type || (get_physical_height() <= -(FLUID_DEEP))) return . = list() @@ -64,3 +66,4 @@ gemstone_dropped = TRUE var/gem_mat = pick(my_material.gemstone_types) .[/obj/item/gemstone] = list("amount" = 1, "material" = gem_mat) + diff --git a/code/game/turfs/floors/floor_height.dm b/code/game/turfs/floors/floor_height.dm index 2dd080f5edd8..8968d6020a5a 100644 --- a/code/game/turfs/floors/floor_height.dm +++ b/code/game/turfs/floors/floor_height.dm @@ -5,12 +5,18 @@ return density ? 0 : height /turf/floor/set_physical_height(new_height) - if(height != new_height) - height = new_height - for(var/turf/neighbor as anything in RANGE_TURFS(src, 1)) - neighbor.update_icon() - fluid_update() - if(fluid_overlay) - fluid_overlay.update_icon() - return TRUE - return FALSE + + if(height == new_height) + return FALSE + + height = new_height + for(var/turf/neighbor as anything in RANGE_TURFS(src, 1)) + neighbor.update_icon() + fluid_update() + if(fluid_overlay) + fluid_overlay.update_icon() + + for(var/atom/movable/thing in contents) + thing.on_turf_height_change(new_height) + + return TRUE diff --git a/code/game/turfs/floors/subtypes/floor_misc.dm b/code/game/turfs/floors/subtypes/floor_misc.dm index a88eb9784ea3..91c472fc284a 100644 --- a/code/game/turfs/floors/subtypes/floor_misc.dm +++ b/code/game/turfs/floors/subtypes/floor_misc.dm @@ -54,6 +54,14 @@ /turf/floor/plating _base_flooring = /decl/flooring/plating // Setting here so overrides on /turf/floor do not impact explicitly typed plating turfs. +// Dirt plating for Tradeship farms. +/turf/floor/plating/dirt + name = "dirt" + icon = 'icons/turf/flooring/dirt.dmi' + icon_state = "dirt" + color = "#41311b" + _flooring = /decl/flooring/dirt + /turf/floor/plating/broken _floor_broken = TRUE diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 8bde4c7ad246..1c8db5bd16e0 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -86,6 +86,9 @@ var/paint_color + /// Floorlike structures like catwalks. Updated/retrieved by get_supporting_platform() + var/obj/structure/supporting_platform + /turf/Initialize(mapload, ...) . = null && ..() // This weird construct is to shut up the 'parent proc not called' warning without disabling the lint for child types. We explicitly return an init hint so this won't change behavior. @@ -140,6 +143,8 @@ /turf/Destroy() + supporting_platform = null + if(zone) if(can_safely_remove_from_zone()) c_copy_air() @@ -204,7 +209,7 @@ if(weather) . += weather.get_movement_delay(return_air(), travel_dir) // TODO: check user species webbed feet, wearing swimming gear - if(reagents?.total_volume > FLUID_PUDDLE) + if(!get_supporting_platform() && reagents?.total_volume > FLUID_PUDDLE) . += (reagents.total_volume > FLUID_SHALLOW) ? 6 : 3 /turf/attack_hand(mob/user) @@ -247,6 +252,12 @@ if(IS_SHOVEL(W)) + // TODO: move these checks into the interaction handlers. + var/atom/platform = get_supporting_platform() + if(platform) + to_chat(user, SPAN_WARNING("\The [platform] [platform.get_pronouns().is] in the way!")) + return TRUE + if(!can_be_dug(W.material?.hardness)) to_chat(user, SPAN_WARNING("\The [src] is too hard to be dug with \the [W].")) return TRUE @@ -262,6 +273,12 @@ var/decl/material/material = get_material() if(IS_PICK(W) && material) + // TODO: move these checks into the interaction handlers. + var/atom/platform = get_supporting_platform() + if(platform) + to_chat(user, SPAN_WARNING("\The [platform] [platform.get_pronouns().is] in the way!")) + return TRUE + if(material?.hardness <= MAT_VALUE_FLEXIBLE) to_chat(user, SPAN_WARNING("\The [src] is too soft to be excavated with \the [W]. Use a shovel.")) return TRUE @@ -331,7 +348,7 @@ return 0 // Check if they need to climb out of a hole. - if(has_gravity()) + if(has_gravity() && !get_supporting_platform()) var/mob/mover_mob = mover if(!istype(mover_mob) || (!mover_mob.throwing && !mover_mob.can_overcome_gravity())) var/turf/old_turf = mover.loc @@ -445,7 +462,7 @@ /turf/proc/try_graffiti(var/mob/vandal, var/obj/item/tool) - if(!tool.sharp || !can_engrave() || !vandal.check_intent(I_FLAG_HELP)) + if(!tool.is_sharp() || !can_engrave() || !vandal.check_intent(I_FLAG_HELP)) return FALSE if(jobban_isbanned(vandal, "Graffiti")) @@ -517,7 +534,7 @@ if(below) below.update_weather(new_weather) -// Updates turf participation in ZAS according to outside status. Must be called whenever the outside status of a turf may change. +/// Updates turf participation in ZAS according to outside status and atmosphere participation bools. Must be called whenever any of those values may change. /turf/proc/update_external_atmos_participation() var/old_outside = last_outside_check last_outside_check = OUTSIDE_UNCERTAIN @@ -701,8 +718,11 @@ var/mob/living/human/H = M var/unique_enzymes = H.get_unique_enzymes() var/blood_type = H.get_blood_type() + var/blood_reagent = H.species.blood_reagent if(unique_enzymes && blood_type) for(var/obj/effect/decal/cleanable/blood/B in contents) + if(B.chemical != blood_reagent) + continue if(!LAZYACCESS(B.blood_DNA, unique_enzymes)) LAZYSET(B.blood_DNA, unique_enzymes, blood_type) LAZYSET(B.blood_data, unique_enzymes, REAGENT_DATA(H.vessel, H.species.blood_reagent)) @@ -712,13 +732,29 @@ blood_splatter(src, M, 1) return TRUE -/turf/proc/AddTracks(var/typepath,var/bloodDNA,var/comingdir,var/goingdir,var/bloodcolor=COLOR_BLOOD_HUMAN) - if(!simulated) +/// Creates a new /obj/effect/decal/cleanable/blood/tracks instance of a given type, +/// or merges it with an existing (not-yet-cleaned) one that matches typepath and chemical. +/// typepath is a type, not an instance +/// new_chemical is optional argument for things like muddy footprints, where typepath isn't enough +/turf/proc/AddTracks(obj/effect/decal/cleanable/blood/tracks/typepath, bloodDNA, comingdir, goingdir, bloodcolor = COLOR_BLOOD_HUMAN, new_chemical = null) + if(!simulated || check_fluid_depth(FLUID_QDEL_POINT)) return - var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src + // Populate defaults from the given typepath, where possible. + if(isnull(new_chemical)) + new_chemical = typepath::chemical || /decl/material/liquid/blood + + var/obj/effect/decal/cleanable/blood/tracks/tracks = null + for(var/obj/effect/decal/cleanable/blood/tracks/candidate in src) + if(!istype(candidate, typepath)) + continue + if(candidate.invisibility >= INVISIBILITY_ABSTRACT) // has been cleaned + continue + if(candidate.chemical != new_chemical) + continue + tracks = candidate if(!tracks) - tracks = new typepath(src) - tracks.AddTracks(bloodDNA,comingdir,goingdir,bloodcolor) + tracks = new typepath(src, null, new_chemical) + tracks.AddTracks(bloodDNA, comingdir, goingdir, bloodcolor) // Proc called in /turf/Entered() to supply an appropriate fluid overlay. /turf/proc/get_movable_alpha_mask_state(atom/movable/mover) @@ -728,12 +764,13 @@ var/mob/moving_mob = mover if(moving_mob.can_overcome_gravity()) return null - var/fluid_depth = get_fluid_depth() - if(fluid_depth > FLUID_PUDDLE) - if(fluid_depth <= FLUID_SHALLOW) - return "mask_shallow" - if(fluid_depth <= FLUID_DEEP) - return "mask_deep" + if(!get_supporting_platform()) + var/fluid_depth = get_fluid_depth() + if(fluid_depth > FLUID_PUDDLE) + if(fluid_depth <= FLUID_SHALLOW) + return "mask_shallow" + if(fluid_depth <= FLUID_DEEP) + return "mask_deep" /turf/spark_act(obj/effect/sparks/sparks) if(simulated) @@ -798,6 +835,14 @@ /turf/can_be_poured_into(atom/source) return !density +/turf/proc/get_supporting_platform() + if(isnull(supporting_platform)) + for(var/obj/structure/platform in get_contained_external_atoms()) + if(platform.is_platform()) + supporting_platform = platform + break + return supporting_platform + /turf/get_alt_interactions(mob/user) . = ..() LAZYADD(., /decl/interaction_handler/show_turf_contents) @@ -814,7 +859,9 @@ if(IS_HOE(held) && can_dig_farm(held.material?.hardness)) LAZYADD(., /decl/interaction_handler/dig/farm) -/turf/proc/can_show_coating_footprints() +/// Contaminant may be the chemical type of the footprint being provided, +/// or null if we just want to know if we support footprints, at all, ever. +/turf/proc/can_show_coating_footprints(decl/material/contaminant) return simulated /decl/interaction_handler/show_turf_contents @@ -836,6 +883,12 @@ name = "Dig Trench" examine_desc = "dig a trench" +/decl/interaction_handler/dig/trench/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(. && istype(target, /turf/floor)) + var/turf/floor/target_turf = target + return target_turf.flooring_is_diggable() + /decl/interaction_handler/dig/trench/invoked(atom/target, mob/user, obj/item/prop) prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. var/turf/T = get_turf(target) diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index ce53c4785664..19db7607c2ec 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -36,6 +36,7 @@ above.ChangeTurf(open_turf_type, keep_air = TRUE, update_open_turfs_above = FALSE) /turf/proc/ChangeTurf(var/turf/N, var/tell_universe = TRUE, var/force_lighting_update = FALSE, var/keep_air = FALSE, var/update_open_turfs_above = TRUE, var/keep_height = FALSE) + if (!N) return @@ -49,6 +50,9 @@ if (!(atom_flags & ATOM_FLAG_INITIALIZED)) return new N(src) + // Rebuilt on next call. + supporting_platform = null + // Track a number of old values for the purposes of raising // state change events after changing the turf to the new type. var/old_fire = fire @@ -140,7 +144,7 @@ if ((old_opacity != opacity) || (tidlu != old_dynamic_lighting) || force_lighting_update) reconsider_lights() - if (tidlu != old_dynamic_lighting) + if (tidlu != old_dynamic_lighting && SSlighting.initialized) // don't fuck with lighting before lighting flush if (tidlu) lighting_build_overlay() else @@ -148,24 +152,24 @@ // end of lighting stuff - // In case the turf isn't marked for update in Initialize (e.g. space), we call this to create any unsimulated edges necessary. - if(W.zone_membership_candidate != old_zone_membership_candidate) - SSair.mark_for_update(src) - // we check the var rather than the proc, because area outside values usually shouldn't be set on turfs W.last_outside_check = OUTSIDE_UNCERTAIN if(W.is_outside != old_outside) // This will check the exterior atmos participation of this turf and all turfs connected by open space below. W.set_outside(old_outside, skip_weather_update = TRUE) - else if(HasBelow(z) && (W.is_open() != old_is_open)) // Otherwise, we do it here if the open status of the turf has changed. - var/turf/checking = src - while(HasBelow(checking.z)) - checking = GetBelow(checking) - if(!isturf(checking)) - break - checking.update_external_atmos_participation() - if(!checking.is_open()) - break + else // We didn't already update our external atmos participation in set_outside. + if(HasBelow(z) && (W.is_open() != old_is_open)) // Otherwise, we do it here if the open status of the turf has changed. + var/turf/checking = src + while(HasBelow(checking.z)) + checking = GetBelow(checking) + if(!isturf(checking)) + break + checking.update_external_atmos_participation() + if(!checking.is_open()) + break + // In case the turf isn't marked for update in Initialize (e.g. space), we call this to create any unsimulated edges necessary. + if(W.zone_membership_candidate != old_zone_membership_candidate) + update_external_atmos_participation() W.update_weather(force_update_below = W.is_open() != old_is_open) diff --git a/code/game/turfs/turf_enter.dm b/code/game/turfs/turf_enter.dm index a0cc300474d9..a83d87a855fe 100644 --- a/code/game/turfs/turf_enter.dm +++ b/code/game/turfs/turf_enter.dm @@ -29,7 +29,9 @@ regenerate_ao() #endif - if(isturf(old_loc) && has_gravity() && A.can_fall() && !(weakref(A) in skip_height_fall_for)) + var/obj/structure/platform = get_supporting_platform() + if(isturf(old_loc) && has_gravity() && A.can_fall() && !isnull(platform) && !(weakref(A) in skip_height_fall_for)) + var/turf/old_turf = old_loc var/old_height = old_turf.get_physical_height() + old_turf.reagents?.total_volume var/current_height = get_physical_height() + reagents?.total_volume @@ -69,7 +71,7 @@ // Delay to allow transition to the new turf and avoid layering issues. var/mob/M = A M.reset_offsets() - if(get_physical_height() > T.get_physical_height()) + if(platform || (get_physical_height() > T.get_physical_height())) M.reset_layer() else // arbitrary timing value that feels good in practice. it sucks and is inconsistent:( diff --git a/code/game/turfs/turf_fluids.dm b/code/game/turfs/turf_fluids.dm index 29ea8eefb0db..f0dd37d11c1a 100644 --- a/code/game/turfs/turf_fluids.dm +++ b/code/game/turfs/turf_fluids.dm @@ -62,7 +62,14 @@ fluid_update() // We are now floodable, so wake up our neighbors. /turf/is_flooded(var/lying_mob, var/absolute) - return (flooded || (!absolute && check_fluid_depth(lying_mob ? FLUID_OVER_MOB_HEAD : FLUID_DEEP))) + if(flooded) + return TRUE + if(absolute) + return FALSE + var/required_depth = lying_mob ? FLUID_OVER_MOB_HEAD : FLUID_DEEP + if(get_supporting_platform()) // Increase required depth if we are over the water. + required_depth -= get_physical_height() // depth is negative, -= to increase required depth. + return check_fluid_depth(required_depth) /turf/check_fluid_depth(var/min = 1) . = (get_fluid_depth() >= min) @@ -103,7 +110,7 @@ create_reagents(FLUID_MAX_DEPTH) return ..() -/turf/add_to_reagents(reagent_type, amount, data, safety = FALSE, defer_update = FALSE, phase) +/turf/add_to_reagents(reagent_type, amount, data, safety = FALSE, defer_update = FALSE, phase = null) if(!reagents) create_reagents(FLUID_MAX_DEPTH) return ..() @@ -117,10 +124,16 @@ ..() if(!QDELETED(src) && fluids?.total_volume) fluids.touch_turf(src, touch_atoms = FALSE) // Handled in fluid_act() below. - for(var/atom/movable/AM as anything in get_contained_external_atoms()) - if(!AM.submerged()) - continue - AM.fluid_act(fluids) + // Wet items that are not supported on a platform or such. + var/effective_volume = fluids?.total_volume + if(get_supporting_platform()) + // Depth is negative height, hence +=. TODO: positive heights? No idea how to handle that. + effective_volume += get_physical_height() + if(effective_volume > FLUID_PUDDLE) + for(var/atom/movable/AM as anything in get_contained_external_atoms()) + if(!AM.submerged()) + continue + AM.fluid_act(fluids) /turf/proc/remove_fluids(var/amount, var/defer_update) if(!reagents?.total_liquid_volume) diff --git a/code/game/turfs/turf_footsteps.dm b/code/game/turfs/turf_footsteps.dm index 371d40feefad..bfa1f9171569 100644 --- a/code/game/turfs/turf_footsteps.dm +++ b/code/game/turfs/turf_footsteps.dm @@ -12,4 +12,4 @@ return get_footstep_for_mob(/decl/footsteps/water, caller) if(footstep_type) return get_footstep_for_mob(footstep_type, caller) - return get_footstep_for_mob(/decl/footsteps/blank, caller) \ No newline at end of file + return get_footstep_for_mob(/decl/footsteps/blank, caller) diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm index 67200a23bf89..45e70ce956e8 100644 --- a/code/game/turfs/unsimulated.dm +++ b/code/game/turfs/unsimulated.dm @@ -25,3 +25,6 @@ /turf/unsimulated/get_lumcount(var/minlum = 0, var/maxlum = 1) return 0.8 + +/turf/unsimulated/get_movable_alpha_mask_state(atom/movable/mover) + return null diff --git a/code/game/turfs/walls/wall_attacks.dm b/code/game/turfs/walls/wall_attacks.dm index 4f82673b1321..9e8eb62472e5 100644 --- a/code/game/turfs/walls/wall_attacks.dm +++ b/code/game/turfs/walls/wall_attacks.dm @@ -132,8 +132,8 @@ qdel(WR) return TRUE else - var/force = W.get_attack_force(user) - if((!is_sharp(W) && force >= 10) || force >= 20) + var/force = W.expend_attack_force(user) + if((!W.is_sharp() && !W.has_edge() && force >= 10) || force >= 20) to_chat(user, "\The [src] crumbles away under the force of your [W.name].") physically_destroyed() return TRUE @@ -297,7 +297,7 @@ return TRUE // Attack the wall with items - var/force = W.get_attack_force(user) + var/force = W.expend_attack_force(user) if(istype(W,/obj/item/rcd) || istype(W, /obj/item/chems) || !force || user.check_intent(I_FLAG_HELP)) return ..() diff --git a/code/game/turfs/walls/wall_natural.dm b/code/game/turfs/walls/wall_natural.dm index 96967f55e2ef..ce8ea3dbbce8 100644 --- a/code/game/turfs/walls/wall_natural.dm +++ b/code/game/turfs/walls/wall_natural.dm @@ -172,7 +172,7 @@ if(!prob(reinf_material.ore_spread_chance)) continue var/turf/wall/natural/target_turf = get_step_resolving_mimic(src, trydir) - if(!istype(target_turf) || !isnull(target_turf.reinf_material)) + if(!istype(target_turf) || !isnull(target_turf.reinf_material) || target_turf.ramp_slope_direction) continue target_turf.set_turf_materials(target_turf.material, reinf_material) target_turf.spread_deposit() diff --git a/code/game/world.dm b/code/game/world.dm index eb1715e424fb..1c65910d510c 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -126,7 +126,7 @@ var/global/world_topic_last = world.timeofday throttle[2] = reason /world/Topic(T, addr, master, key) - direct_output(diary, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]") + to_file(diary, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]") if (global.world_topic_last > world.timeofday) global.world_topic_throttle = list() //probably passed midnight @@ -201,7 +201,7 @@ var/global/_reboot_announced = FALSE /world/proc/save_mode(var/the_mode) var/F = file("data/mode.txt") fdel(F) - direct_output(F, the_mode) + to_file(F, the_mode) /world/proc/load_motd() join_motd = safe_file2text("config/motd.txt", FALSE) diff --git a/code/game/world_topic_commands.dm b/code/game/world_topic_commands.dm index 2bbc05f14361..cfd86601053b 100644 --- a/code/game/world_topic_commands.dm +++ b/code/game/world_topic_commands.dm @@ -356,6 +356,5 @@ uid = "topic_command_prometheus_metrics" /decl/topic_command/secure/prometheus_metrics/use() - if(!global.prometheus_metrics) - return "Metrics not ready" - return global.prometheus_metrics.collect() + var/static/decl/prometheus_metrics/prometheus_metrics = IMPLIED_DECL + return prometheus_metrics.collect() diff --git a/code/modules/ZAS/Turf.dm b/code/modules/ZAS/Turf.dm index 823128586228..016d69b4c53e 100644 --- a/code/modules/ZAS/Turf.dm +++ b/code/modules/ZAS/Turf.dm @@ -35,9 +35,9 @@ var/list/postponed #ifdef MULTIZAS - for(var/d = 1, d < 64, d *= 2) + for(var/d in global.cardinalz) #else - for(var/d = 1, d < 16, d *= 2) + for(var/d in global.cardinal) #endif var/turf/unsim = get_step(src, d) @@ -167,7 +167,7 @@ #define GET_ZONE_NEIGHBOURS(T, ret) \ ret = 0; \ if (T.zone) { \ - for (var/_gzn_dir in gzn_check) { \ + for (var/_gzn_dir in ZAS_GZN_CHECK) { \ var/turf/other = get_step(T, _gzn_dir); \ if (istype(other) && other.simulated && other.zone == T.zone) { \ var/block; \ @@ -198,7 +198,7 @@ if (!(check_dirs & (check_dirs - 1))) //Equivalent to: if(IsInteger(log(2, .))) return TRUE - for(var/dir in global.csrfz_check) + for(var/dir in ZAS_CSRFZ_CHECK) //for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH) if((dir & check_dirs) == dir) //check that they are connected by the corner turf diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 5e06996ca46f..c211f274d603 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -321,7 +321,7 @@ var/global/BSACooldown = 0 dat += "Remove" dat += "
" if(update_file) - direct_output(info, infos) + to_file(info, infos) dat += "
Add Comment
" diff --git a/code/modules/admin/secrets/investigation/attack_logs.dm b/code/modules/admin/secrets/investigation/attack_logs.dm index 201adaa00bf7..5a915fd379c7 100644 --- a/code/modules/admin/secrets/investigation/attack_logs.dm +++ b/code/modules/admin/secrets/investigation/attack_logs.dm @@ -69,9 +69,8 @@ . = filters_per_client[user.client] if(!.) . = list() - for(var/af_type in subtypesof(/attack_filter)) - var/attack_filter/af = af_type - if(initial(af.category) == af_type) + for(var/datum/attack_filter/af_type as anything in subtypesof(/datum/attack_filter)) + if(TYPE_IS_ABSTRACT(af_type)) continue . += new af_type(src) filters_per_client[user.client] = . @@ -79,56 +78,56 @@ /datum/admin_secret_item/investigation/attack_logs/proc/get_filter_html(user) . = list() for(var/filter in get_user_filters(user)) - var/attack_filter/af = filter + var/datum/attack_filter/af = filter . += af.get_html() . = jointext(.," | ") /datum/admin_secret_item/investigation/attack_logs/proc/filter_log(user, var/datum/attack_log/al) for(var/filter in get_user_filters(user)) - var/attack_filter/af = filter + var/datum/attack_filter/af = filter if(af.filter_attack(al)) return TRUE return FALSE /datum/admin_secret_item/investigation/attack_logs/proc/reset_user_filters(user) for(var/filter in get_user_filters(user)) - var/attack_filter/af = filter + var/datum/attack_filter/af = filter af.reset() -/attack_filter - var/category = /attack_filter +/datum/attack_filter + abstract_type = /datum/attack_filter var/datum/admin_secret_item/investigation/attack_logs/holder -/attack_filter/New(var/holder) +/datum/attack_filter/New(var/holder) ..() src.holder = holder -/attack_filter/Topic(href, href_list) +/datum/attack_filter/Topic(href, href_list) if(..()) return TRUE if(OnTopic(href_list)) holder.execute(usr) return TRUE -/attack_filter/proc/get_html() +/datum/attack_filter/proc/get_html() return -/attack_filter/proc/reset() +/datum/attack_filter/proc/reset() return -/attack_filter/proc/filter_attack(var/datum/attack_log/al) +/datum/attack_filter/proc/filter_attack(var/datum/attack_log/al) return FALSE -/attack_filter/proc/OnTopic(href_list) +/datum/attack_filter/proc/OnTopic(href_list) return FALSE /* * Filter logs with one or more missing clients */ -/attack_filter/no_client +/datum/attack_filter/no_client var/filter_missing_clients = TRUE -/attack_filter/no_client/get_html() +/datum/attack_filter/no_client/get_html() . = list() . += "Must have clients: " if(filter_missing_clients) @@ -137,7 +136,7 @@ . += "YesNo" . = jointext(.,null) -/attack_filter/no_client/OnTopic(href_list) +/datum/attack_filter/no_client/OnTopic(href_list) if(href_list["yes"] && !filter_missing_clients) filter_missing_clients = TRUE return TRUE @@ -145,10 +144,10 @@ filter_missing_clients = FALSE return TRUE -/attack_filter/no_client/reset() +/datum/attack_filter/no_client/reset() filter_missing_clients = initial(filter_missing_clients) -/attack_filter/no_client/filter_attack(var/datum/attack_log/al) +/datum/attack_filter/no_client/filter_attack(var/datum/attack_log/al) if(!filter_missing_clients) return FALSE if(al.attacker && al.attacker.client.ckey == NO_CLIENT_CKEY) @@ -160,19 +159,19 @@ /* Either subject must be the selected client */ -/attack_filter/must_be_given_ckey +/datum/attack_filter/must_be_given_ckey var/ckey_filter var/check_attacker = TRUE var/check_victim = TRUE var/description = "Either ckey is" -/attack_filter/must_be_given_ckey/reset() +/datum/attack_filter/must_be_given_ckey/reset() ckey_filter = null -/attack_filter/must_be_given_ckey/get_html() +/datum/attack_filter/must_be_given_ckey/get_html() return "[description]: [ckey_filter ? ckey_filter : "*ANY*"]" -/attack_filter/must_be_given_ckey/OnTopic(href_list) +/datum/attack_filter/must_be_given_ckey/OnTopic(href_list) if(!href_list["select_ckey"]) return var/ckey = input("Select ckey to filter on","Select ckey", ckey_filter) as null|anything in get_ckeys() @@ -183,7 +182,7 @@ ckey_filter = ckey return TRUE -/attack_filter/must_be_given_ckey/proc/get_ckeys() +/datum/attack_filter/must_be_given_ckey/proc/get_ckeys() . = list() for(var/log in attack_log_repository.attack_logs_) var/datum/attack_log/al = log @@ -194,7 +193,7 @@ . = sortTim(., /proc/cmp_text_asc) . += "*ANY*" -/attack_filter/must_be_given_ckey/filter_attack(var/datum/attack_log/al) +/datum/attack_filter/must_be_given_ckey/filter_attack(var/datum/attack_log/al) if(!ckey_filter) return FALSE if(check_attacker && al.attacker && al.attacker.client.ckey == ckey_filter) @@ -206,19 +205,19 @@ /* Attacker must be the selected client */ -/attack_filter/must_be_given_ckey/attacker +/datum/attack_filter/must_be_given_ckey/attacker description = "Attacker ckey is" check_victim = FALSE -/attack_filter/must_be_given_ckey/attacker/filter_attack(al) +/datum/attack_filter/must_be_given_ckey/attacker/filter_attack(al) return ..(al, TRUE, FALSE) /* Victim must be the selected client */ -/attack_filter/must_be_given_ckey/victim +/datum/attack_filter/must_be_given_ckey/victim description = "Victim ckey is" check_attacker = FALSE -/attack_filter/must_be_given_ckey/victim/filter_attack(al) +/datum/attack_filter/must_be_given_ckey/victim/filter_attack(al) return ..(al, FALSE, TRUE) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 8adc77ad2e73..c9e2798773b2 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -174,7 +174,7 @@ else if(task == "permissions") if(!D) return var/list/permissionlist = list() - for(var/i=1, i<=R_MAXPERMISSION, i<<=1) //that <<= is shorthand for i = i << 1. Which is a left BITSHIFT_LEFT + for(var/i=1, i<=R_MAXPERMISSION, i = BITSHIFT_LEFT(i, 1)) permissionlist[rights2text(i)] = i var/new_permission = input("Select a permission to turn on/off", "Permission toggle", null, null) as null|anything in permissionlist if(!new_permission) return @@ -979,8 +979,7 @@ var/obj/effect/stop/S S = new /obj/effect/stop(M.loc) S.victim = M - spawn(20) - qdel(S) + QDEL_IN(S, 2 SECONDS) var/turf/floor/T = get_turf(M) if(istype(T)) diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index 75b90a337127..179676df7f36 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -10,7 +10,7 @@ var/inactive_groups = SSair.zones.len - active_groups var/hotspots = 0 - for(var/obj/fire/hotspot in world) + for(var/obj/fire/hotspot in SSair.active_hotspots) hotspots++ var/active_on_main_station = 0 diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 24bbe2f93abd..0527485b1265 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -51,7 +51,7 @@ return message_admins("[key_name_admin(src)] accessed file: [path]") - direct_output(src, run(file(path))) + open_file_for(src, file(path)) to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") return @@ -64,6 +64,6 @@ set name = "Show Server Log" set desc = "Shows today's server log." - direct_output(usr, run(diary)) + open_file_for(usr, diary) SSstatistics.add_field_details("admin_verb","VTL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return \ No newline at end of file diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index dd3f47479406..b599e3845e62 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -24,6 +24,7 @@ var/global/camera_range_display_status = 0 var/global/intercom_range_display_status = 0 +var/global/list/debug_camera_range_markers = list() /obj/effect/debugging/camera_range icon = 'icons/480x480.dmi' icon_state = "25percent" @@ -33,11 +34,25 @@ var/global/intercom_range_display_status = 0 default_pixel_x = -224 default_pixel_y = -224 reset_offsets(0) + global.debug_camera_range_markers += src +/obj/effect/debugging/camera_range/Destroy() + global.debug_camera_range_markers -= src + return ..() + +var/global/list/mapping_debugging_markers = list() /obj/effect/debugging/marker icon = 'icons/turf/areas.dmi' icon_state = "yellow" +/obj/effect/debugging/marker/Initialize(mapload) + . = ..() + global.mapping_debugging_markers += src + +/obj/effect/debugging/marker/Destroy() + global.mapping_debugging_markers -= src + return ..() + /obj/effect/debugging/marker/Move() return 0 @@ -56,7 +71,7 @@ var/global/intercom_range_display_status = 0 - for(var/obj/effect/debugging/camera_range/C in world) + for(var/obj/effect/debugging/camera_range/C as anything in debug_camera_range_markers) qdel(C) if(camera_range_display_status) @@ -113,7 +128,7 @@ var/global/intercom_range_display_status = 0 else intercom_range_display_status = 1 - for(var/obj/effect/debugging/marker/M in world) + for(var/obj/effect/debugging/marker/M in global.mapping_debugging_markers) qdel(M) if(intercom_range_display_status) diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index 959b1b0c0119..7b7155b8391c 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -1,6 +1,4 @@ - -// Keep these two together, they *must* be defined on both -// If /client ever becomes /datum/client or similar, they can be merged +// If /client/var/parent_type ever stops being /datum, this proc will need to be redefined on client. /datum/proc/get_view_variables_header() return "[src]" @@ -8,16 +6,16 @@ return {" [src]
- << + \<\< [dir2text(dir)] - >> + \>\> "} /mob/living/get_view_variables_header() return {" [src] -
<< [dir2text(dir)] >> +
\<\< [dir2text(dir)] \>\>
[ckey ? ckey : "No ckey"] / [real_name ? real_name : "No real name"]
BRUTE:[get_damage(BRUTE)] diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 09d5d1cc8c14..971e7a394bcd 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -290,8 +290,8 @@ return var/list/possible_ailments = list() for(var/atype in subtypesof(/datum/ailment)) - var/datum/ailment/ailment = get_ailment_reference(atype) - if(ailment && ailment.category != ailment.type && ailment.can_apply_to(limb)) + var/datum/ailment/ailment = get_ailment_reference(atype) // will not get abstract ailments + if(ailment && ailment.can_apply_to(limb)) possible_ailments |= ailment var/datum/ailment/ailment = input("Select an ailment type to add.", "Add Ailment") as null|anything in possible_ailments diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index dba32a26eb25..9a794b2c9006 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -159,8 +159,7 @@ if(a_right) a_right.holder = null a_right.forceMove(T) - spawn(0) - qdel(src) + qdel(src) return /obj/item/assembly_holder/hear_talk(mob/living/M, msg, verb, decl/language/speaking) diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 1253014bd80d..77623305db1d 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -67,7 +67,7 @@ holder.update_icon() update_beams() -/obj/item/assembly/infra/interact(mob/user)//TODO: change this this to the wire control panel +/obj/item/assembly/infra/interact(mob/user)//TODO: change this to the wire control panel if(!secured) return if(!CanInteract(user, global.physical_topic_state)) diff --git a/code/modules/atmospherics/components/unary/heat_exchanger.dm b/code/modules/atmospherics/components/unary/heat_exchanger.dm index 30849bc53b92..f19c4ecb4f74 100644 --- a/code/modules/atmospherics/components/unary/heat_exchanger.dm +++ b/code/modules/atmospherics/components/unary/heat_exchanger.dm @@ -4,7 +4,7 @@ icon_state = "intact" density = TRUE - name = "Heat Exchanger" + name = "heat exchanger" desc = "Exchanges heat between two input gases. Setup for fast heat transfer." var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null diff --git a/code/modules/atmospherics/datum_pipeline.dm b/code/modules/atmospherics/datum_pipeline.dm index cace579e65b8..55a58d0138fe 100644 --- a/code/modules/atmospherics/datum_pipeline.dm +++ b/code/modules/atmospherics/datum_pipeline.dm @@ -45,7 +45,7 @@ . = ..() -/datum/pipeline/Process()//This use to be called called from the pipe networks +/datum/pipeline/Process()//This use to be called from the pipe networks //Check to see if pressure is within acceptable limits var/pressure = air.return_pressure() if(pressure > maximum_pressure) @@ -193,13 +193,23 @@ network.update = 1 /datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity) + + if(air.volume <= 0) // Avoid div by zero. + return + var/total_heat_capacity = air.heat_capacity() var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume) + if(total_heat_capacity <= 0) // Avoid div by zero. + return + if(SHOULD_PARTICIPATE_IN_ZONES(target) && !target.blocks_air) + + if(partial_heat_capacity <= 0) + return + var/delta_temperature = 0 var/sharer_heat_capacity = 0 - if(target.zone) delta_temperature = (air.temperature - target.zone.air.temperature) sharer_heat_capacity = target.zone.air.heat_capacity() @@ -207,18 +217,14 @@ delta_temperature = (air.temperature - target.air.temperature) sharer_heat_capacity = target.air.heat_capacity() + if(sharer_heat_capacity <= 0) + return + var/self_temperature_delta = 0 var/sharer_temperature_delta = 0 - - if((sharer_heat_capacity > 0) && (partial_heat_capacity > 0)) - var/heat = thermal_conductivity*delta_temperature* \ - (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity)) - - self_temperature_delta = -heat/total_heat_capacity - sharer_temperature_delta = heat/sharer_heat_capacity - else - return 1 - + var/heat = thermal_conductivity * delta_temperature * ( partial_heat_capacity * sharer_heat_capacity / (partial_heat_capacity + sharer_heat_capacity) ) + self_temperature_delta = -heat/total_heat_capacity + sharer_temperature_delta = heat/sharer_heat_capacity air.temperature += self_temperature_delta if(target.zone) @@ -228,33 +234,29 @@ else if(target.external_atmosphere_participation && !target.blocks_air) - var/turf/modeled_location = target - var/datum/gas_mixture/target_air = modeled_location.return_air() + if(partial_heat_capacity <= 0) + return - var/delta_temperature = air.temperature - target_air.temperature - var/sharer_heat_capacity = target_air.heat_capacity() + var/datum/gas_mixture/target_air = target.return_air() + var/sharer_heat_capacity = target_air?.heat_capacity() - if((sharer_heat_capacity > 0) && (partial_heat_capacity > 0)) - var/heat = thermal_conductivity*delta_temperature* \ - (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity)) - air.temperature += -heat/total_heat_capacity - else - return 1 + if(sharer_heat_capacity <= 0) + return - else - if((target.heat_capacity > 0) && (partial_heat_capacity > 0)) - var/delta_temperature = air.temperature - target.temperature - - var/heat = thermal_conductivity*delta_temperature* \ - (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity)) + var/delta_temperature = air.temperature - target_air.temperature + var/heat = thermal_conductivity * delta_temperature * ( partial_heat_capacity * sharer_heat_capacity / (partial_heat_capacity+sharer_heat_capacity) ) + air.temperature += -heat/total_heat_capacity - air.temperature -= heat/total_heat_capacity - // Only increase the temperature of the target if it's simulated. - if(target.simulated) - target.temperature += heat/target.heat_capacity + else if((target.heat_capacity > 0) && (partial_heat_capacity > 0)) + var/delta_temperature = air.temperature - target.temperature + var/heat = thermal_conductivity * delta_temperature * ( partial_heat_capacity * target.heat_capacity / (partial_heat_capacity + target.heat_capacity) ) + air.temperature -= heat/total_heat_capacity + // Only increase the temperature of the target if it's simulated. + if(target.simulated) + target.temperature += heat/target.heat_capacity if(network) - network.update = 1 + network.update = TRUE //surface must be the surface area in m^2 /datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity) diff --git a/code/modules/atmospherics/he_pipes.dm b/code/modules/atmospherics/he_pipes.dm index 55afc98fd37f..380adf9245f4 100644 --- a/code/modules/atmospherics/he_pipes.dm +++ b/code/modules/atmospherics/he_pipes.dm @@ -1,28 +1,26 @@ /obj/machinery/atmospherics/pipe/simple/heat_exchanging - icon = 'icons/atmos/heat.dmi' - icon_state = "11" - color = "#404040" - pipe_color = "#404040" - level = LEVEL_ABOVE_PLATING - connect_types = CONNECT_TYPE_HE + icon = 'icons/atmos/heat.dmi' + icon_state = "11" + color = "#404040" + pipe_color = "#404040" + level = LEVEL_ABOVE_PLATING + connect_types = CONNECT_TYPE_HE interact_offline = TRUE //Needs to be set so that pipes don't say they lack power in their description - var/initialize_directions_he - var/surface = 2 //surface area in m^2 - var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh build_icon_state = "he" - atom_flags = 0 // no painting + atom_flags = 0 // no painting + maximum_pressure = 360 ATM + fatigue_pressure = 300 ATM + can_buckle = TRUE + buckle_lying = TRUE appearance_flags = KEEP_TOGETHER + var/initialize_directions_he + var/surface = 2 //surface area in m^2 + var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh var/thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT var/minimum_temperature_difference = 20 - maximum_pressure = 360 ATM - fatigue_pressure = 300 ATM - - can_buckle = 1 - buckle_lying = 1 - /obj/machinery/atmospherics/pipe/simple/heat_exchanging/Initialize() . = ..() add_filter("glow",1, list(type = "drop_shadow", x = 0, y = 0, offset = 0, size = 4)) @@ -57,62 +55,57 @@ update_icon() /obj/machinery/atmospherics/pipe/simple/heat_exchanging/Process() + if(!parent) ..() - else - var/turf/turf = loc - var/datum/gas_mixture/pipe_air = return_air() - if(istype(loc, /turf/space)) - parent.radiate_heat_to_space(surface, 1) - else if(istype(turf) && turf.simulated) - var/turf/pipe_turf = loc - var/environment_temperature = 0 - if(pipe_turf.blocks_air) - environment_temperature = pipe_turf.temperature - else - var/datum/gas_mixture/environment = pipe_turf.return_air() - environment_temperature = environment.temperature - if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) - parent.temperature_interact(pipe_turf, volume, thermal_conductivity) - - if(buckled_mob) - var/hc = pipe_air.heat_capacity() - var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500) - pipe_air.temperature = avg_temp - buckled_mob.bodytemperature = avg_temp - - var/heat_limit = 1000 - - var/mob/living/human/H = buckled_mob - if(istype(H) && H.species) - heat_limit = H.get_mob_temperature_threshold(HEAT_LEVEL_3) - - if(pipe_air.temperature > heat_limit + 1) - buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_CHEST, used_weapon = "Excessive Heat") - - //fancy radiation glowing - if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K - if(abs(pipe_air.temperature - icon_temperature) > 10) - icon_temperature = pipe_air.temperature - var/scale = max((icon_temperature - 500) / 1500, 0) - - var/h_r = heat2color_r(icon_temperature) - var/h_g = heat2color_g(icon_temperature) - var/h_b = heat2color_b(icon_temperature) - - if(icon_temperature < 2000) //scale up overlay until 2000K - h_r = 64 + (h_r - 64)*scale - h_g = 64 + (h_g - 64)*scale - h_b = 64 + (h_b - 64)*scale - var/scale_color = rgb(h_r, h_g, h_b) - var/list/animate_targets = get_above_oo() + src - for (var/thing in animate_targets) - var/atom/movable/AM = thing - animate(AM, color = scale_color, time = 2 SECONDS, easing = SINE_EASING) - animate_filter("glow", list(color = scale_color, time = 2 SECONDS, easing = LINEAR_EASING)) - set_light(min(3, scale*2.5), min(3, scale*2.5), scale_color) + return + + // Handle pipe heat exchange. + var/turf/turf = loc + var/datum/gas_mixture/pipe_air = return_air() + if(istype(loc, /turf/space)) + parent.radiate_heat_to_space(surface, 1) + else if(istype(turf) && turf.simulated) + var/environment_temperature = 0 + if(turf.blocks_air) + environment_temperature = turf.temperature else - set_light(0, 0) + var/datum/gas_mixture/environment = turf.return_air() + environment_temperature = environment?.temperature || 0 + if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) + parent.temperature_interact(turf, volume, thermal_conductivity) + + // Burn mobs buckled to this pipe. + if(buckled_mob) + var/hc = pipe_air.heat_capacity() + var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500) + pipe_air.temperature = avg_temp + buckled_mob.bodytemperature = avg_temp + var/heat_limit = buckled_mob.get_mob_temperature_threshold(HEAT_LEVEL_3) + if(pipe_air.temperature > heat_limit + 1) + buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_CHEST, used_weapon = "Excessive Heat") + + //fancy radiation glowing + if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K + if(abs(pipe_air.temperature - icon_temperature) > 10) + icon_temperature = pipe_air.temperature + var/scale = max((icon_temperature - 500) / 1500, 0) + var/h_r = heat2color_r(icon_temperature) + var/h_g = heat2color_g(icon_temperature) + var/h_b = heat2color_b(icon_temperature) + if(icon_temperature < 2000) //scale up overlay until 2000K + h_r = 64 + (h_r - 64)*scale + h_g = 64 + (h_g - 64)*scale + h_b = 64 + (h_b - 64)*scale + var/scale_color = rgb(h_r, h_g, h_b) + var/list/animate_targets = get_above_oo() + src + for (var/thing in animate_targets) + var/atom/movable/AM = thing + animate(AM, color = scale_color, time = 2 SECONDS, easing = SINE_EASING) + animate_filter("glow", list(color = scale_color, time = 2 SECONDS, easing = LINEAR_EASING)) + set_light(min(3, scale*2.5), min(3, scale*2.5), scale_color) + else + set_light(0, 0) /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction icon = 'icons/atmos/junction.dmi' diff --git a/code/modules/augment/active/armblades.dm b/code/modules/augment/active/armblades.dm index 1f214a266fed..8e40dc7c43e3 100644 --- a/code/modules/augment/active/armblades.dm +++ b/code/modules/augment/active/armblades.dm @@ -5,8 +5,8 @@ icon = 'icons/obj/augment.dmi' desc = "A handy utility blade for the discerning augmentee. Warranty void if used for cutting." base_parry_chance = 30 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE attack_verb = list("stabbed", "sliced", "cut") origin_tech = @'{"materials":1,"engineering":1,"combat":2}' material = /decl/material/solid/metal/steel diff --git a/code/modules/augment/augment.dm b/code/modules/augment/augment.dm index ff96aabde045..ef122136d5c5 100644 --- a/code/modules/augment/augment.dm +++ b/code/modules/augment/augment.dm @@ -2,11 +2,13 @@ name = "embedded augment" desc = "An embedded augment." icon = 'icons/obj/augment.dmi' + w_class = ITEM_SIZE_TINY // Need to be tiny to fit inside limbs. //By default these fit on both flesh and robotic organs and are robotic organ_properties = ORGAN_PROP_PROSTHETIC default_action_type = /datum/action/item_action/organ/augment material = /decl/material/solid/metal/steel origin_tech = @'{"materials":1,"magnets":2,"engineering":2,"biotech":1}' + w_class = ITEM_SIZE_TINY var/descriptor = "" var/known = TRUE diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm index e8f001355f0f..5de1ac052b18 100644 --- a/code/modules/blob/blob.dm +++ b/code/modules/blob/blob.dm @@ -182,11 +182,11 @@ var/damage = 0 switch(W.atom_damage_type) if(BURN) - damage = (W.get_attack_force(user) / fire_resist) + damage = (W.expend_attack_force(user) / fire_resist) if(IS_WELDER(W)) playsound(loc, 'sound/items/Welder.ogg', 100, 1) if(BRUTE) - damage = (W.get_attack_force(user) / brute_resist) + damage = (W.expend_attack_force(user) / brute_resist) take_damage(damage, W.atom_damage_type) return TRUE diff --git a/code/modules/butchery/butchery_hook.dm b/code/modules/butchery/butchery_hook.dm index 0cc357e6f75a..58945994cd87 100644 --- a/code/modules/butchery/butchery_hook.dm +++ b/code/modules/butchery/butchery_hook.dm @@ -195,12 +195,14 @@ update_icon() if(!tool?.do_tool_interaction(TOOL_KNIFE, user, src, 3 SECONDS, start_message = butchery_string, success_message = butchery_string, check_skill = SKILL_COOKING)) return FALSE - if(!QDELETED(user) && !QDELETED(last_occupant) && occupant == last_occupant && occupant_state == last_state) + if(!QDELETED(user) && !QDELETED(last_occupant) && occupant == last_occupant && occupant_state == last_state && user.get_active_held_item() == tool) var/decl/butchery_data/butchery_data = GET_DECL(occupant.butchery_data) if(!butchery_data) return FALSE + tool.add_blood(occupant) + switch(next_state) if(CARCASS_SKINNED) if(occupant.currently_has_skin()) diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index d582783e0912..f83344b4841e 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -45,7 +45,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the client.sending |= asset_name var/job = ++client.last_asset_job - direct_output(client, browse("", "window=asset_cache_browser")) + show_browser(client, "", "window=asset_cache_browser") var/t = 0 var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT @@ -85,7 +85,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the client.sending |= unreceived var/job = ++client.last_asset_job - direct_output(client, browse("", "window=asset_cache_browser")) + show_browser(client, "", "window=asset_cache_browser") var/t = 0 var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/client/preference_setup/global/01_ui.dm index 932214653179..f48998316cc7 100644 --- a/code/modules/client/preference_setup/global/01_ui.dm +++ b/code/modules/client/preference_setup/global/01_ui.dm @@ -107,18 +107,25 @@ var/global/list/valid_icon_sizes = list(32, 48, 64, 96, 128) . += "Client FPS: [pref.clientfps]
" /datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["select_style"]) var/decl/ui_style/current_style = GET_DECL(pref.UI_style) var/decl/ui_style/UI_style_new = input(user, "Choose UI style.", CHARACTER_PREFERENCE_INPUT_TITLE, current_style) as null|anything in get_ui_styles() - if(!istype(UI_style_new) || !CanUseTopic(user)) return TOPIC_NOACTION + if(!istype(UI_style_new) || !CanUseTopic(user)) + return TOPIC_NOACTION pref.UI_style = UI_style_new.type - return TOPIC_REFRESH + if(!isnull(UI_style_new.default_color)) + pref.UI_style_color = UI_style_new.default_color + if(!isnull(UI_style_new.default_alpha)) + pref.UI_style_alpha = UI_style_new.default_alpha + . = TOPIC_REFRESH else if(href_list["select_color"]) var/UI_style_color_new = input(user, "Choose UI color, dark colors are not recommended!", "Global Preference", pref.UI_style_color) as color|null - if(isnull(UI_style_color_new) || !CanUseTopic(user)) return TOPIC_NOACTION + if(isnull(UI_style_color_new) || !CanUseTopic(user)) + return TOPIC_NOACTION pref.UI_style_color = UI_style_color_new - return TOPIC_REFRESH + . = TOPIC_REFRESH else if(href_list["select_highlight_color"]) var/UI_style_highlight_color_new = input(user, "Choose UI highlight color, dark colors are not recommended!", "Global Preference", pref.UI_style_highlight_color) as color|null @@ -128,11 +135,34 @@ var/global/list/valid_icon_sizes = list(32, 48, 64, 96, 128) else if(href_list["select_alpha"]) var/UI_style_alpha_new = input(user, "Select UI alpha (transparency) level, between 50 and 255.", "Global Preference", pref.UI_style_alpha) as num|null - if(isnull(UI_style_alpha_new) || (UI_style_alpha_new < 50 || UI_style_alpha_new > 255) || !CanUseTopic(user)) return TOPIC_NOACTION + if(isnull(UI_style_alpha_new) || (UI_style_alpha_new < 50 || UI_style_alpha_new > 255) || !CanUseTopic(user)) + return TOPIC_NOACTION pref.UI_style_alpha = UI_style_alpha_new - return TOPIC_REFRESH + . = TOPIC_REFRESH - else if(href_list["select_ooc_color"]) + else if(href_list["reset"]) + switch(href_list["reset"]) + if("ui") + pref.UI_style_color = initial(pref.UI_style_color) + if("highlight") + pref.UI_style_highlight_color = initial(pref.UI_style_highlight_color) + if("alpha") + pref.UI_style_alpha = initial(pref.UI_style_alpha) + if("mouseover_color") + pref.UI_mouseover_color = initial(pref.UI_mouseover_color) + if("mouseover_alpha") + pref.UI_mouseover_alpha = initial(pref.UI_mouseover_alpha) + if("ooc") + pref.ooccolor = initial(pref.ooccolor) + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + // This is overkill, but we do not currently have a way to tell what elements should grab a new color or alpha. + // TODO: maybe limit or debounce/queue this? + user.hud_reset(TRUE) + return + + if(href_list["select_ooc_color"]) var/new_ooccolor = input(user, "Choose OOC color:", "Global Preference") as color|null if(new_ooccolor && can_select_ooc_color(user) && CanUseTopic(user)) pref.ooccolor = new_ooccolor @@ -157,22 +187,6 @@ var/global/list/valid_icon_sizes = list(32, 48, 64, 96, 128) pref.tooltip_style = tooltip_style_new return TOPIC_REFRESH - else if(href_list["reset"]) - switch(href_list["reset"]) - if("ui") - pref.UI_style_color = initial(pref.UI_style_color) - if("highlight") - pref.UI_style_highlight_color = initial(pref.UI_style_highlight_color) - if("alpha") - pref.UI_style_alpha = initial(pref.UI_style_alpha) - if("mouseover_color") - pref.UI_mouseover_color = initial(pref.UI_mouseover_color) - if("mouseover_alpha") - pref.UI_mouseover_alpha = initial(pref.UI_mouseover_alpha) - if("ooc") - pref.ooccolor = initial(pref.ooccolor) - return TOPIC_REFRESH - else if(href_list["select_icon_size"]) var/new_icon_size = input(user, "Enter a new default icon size.", "Default Icon Size", pref.icon_size) as null|anything in global.valid_icon_sizes if(new_icon_size && pref.icon_size != new_icon_size) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index b5c1c2a992a8..c4ec78c13cf2 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -295,7 +295,7 @@ var/global/list/time_prefs_fixed = list() return if(href_list["preference"] == "open_whitelist_forum") if(get_config_value(/decl/config/text/forumurl)) - direct_output(user, link(get_config_value(/decl/config/text/forumurl))) + open_link(user, get_config_value(/decl/config/text/forumurl)) else to_chat(user, "The forum URL is not set in the server configuration.") return diff --git a/code/modules/client/ui_styles/_ui_style.dm b/code/modules/client/ui_styles/_ui_style.dm index 0e78ae2e832b..d7a51a45f87c 100644 --- a/code/modules/client/ui_styles/_ui_style.dm +++ b/code/modules/client/ui_styles/_ui_style.dm @@ -26,6 +26,10 @@ ) /// A subset of UI keys to icon files used to override the above. var/list/override_icons + /// A color to reset this UI to on pref selection. + var/default_color = COLOR_WHITE + /// An alpha to reset this UI to on pref selection. + var/default_alpha = 255 var/use_overlay_color = FALSE var/use_ui_color = FALSE diff --git a/code/modules/clothing/_clothing.dm b/code/modules/clothing/_clothing.dm index b51dfb2f51e3..b6cc37b0adae 100644 --- a/code/modules/clothing/_clothing.dm +++ b/code/modules/clothing/_clothing.dm @@ -100,7 +100,7 @@ /obj/item/clothing/attackby(obj/item/I, mob/user) var/rags = RAG_COUNT(src) - if(istype(material) && material.default_solid_form && rags && (I.edge || I.sharp) && user.check_intent(I_FLAG_HARM)) + if(istype(material) && material.default_solid_form && rags && (I.is_sharp() || I.has_edge()) && user.check_intent(I_FLAG_HARM)) if(length(accessories)) to_chat(user, SPAN_WARNING("You should remove the accessories attached to \the [src] first.")) return TRUE @@ -302,12 +302,12 @@ update_clothing_icon() /obj/item/clothing/get_examine_name() - var/list/ensemble = list(name) + var/list/ensemble = list(..()) for(var/obj/item/clothing/accessory in accessories) if(accessory.accessory_visibility == ACCESSORY_VISIBILITY_ENSEMBLE) - LAZYADD(ensemble, accessory.get_examine_name()) - if(length(ensemble) <= 1) - return ..() + ensemble += accessory.get_examine_name() + if(length(ensemble) == 1) // don't worry about it being empty, we always have a minimum of one + return ensemble[1] return english_list(ensemble, summarize = TRUE) /obj/item/clothing/get_examine_line() diff --git a/code/modules/clothing/gloves/jewelry/rings/_ring.dm b/code/modules/clothing/gloves/jewelry/rings/_ring.dm index b9e58beedf62..aadeedab5589 100644 --- a/code/modules/clothing/gloves/jewelry/rings/_ring.dm +++ b/code/modules/clothing/gloves/jewelry/rings/_ring.dm @@ -54,7 +54,7 @@ desc = "[base_desc] [desc]" /obj/item/clothing/gloves/ring/attackby(var/obj/item/tool, var/mob/user) - if(can_inscribe && tool.sharp && user.check_intent(I_FLAG_HELP)) + if(can_inscribe && tool.is_sharp() && user.check_intent(I_FLAG_HELP)) var/new_inscription = sanitize(input("Enter an inscription to engrave.", "Inscription") as null|text) if(user.stat || !user.incapacitated() || !user.Adjacent(src) || tool.loc != user) return TRUE diff --git a/code/modules/clothing/head/fated_key.dm b/code/modules/clothing/head/fated_key.dm index cc65bd802395..626126d50c93 100644 --- a/code/modules/clothing/head/fated_key.dm +++ b/code/modules/clothing/head/fated_key.dm @@ -51,7 +51,7 @@ var/atom/blade for(var/obj/item/held in shuffle(user.get_held_items())) - if(has_edge(held)) + if(held.has_edge()) blade = held break if(!blade) @@ -113,5 +113,5 @@ animate(src, alpha = 255, time = 3) sleep(13) animate(src, alpha = 0, time = 40) - sleep(40) - qdel(src) + if(!QDELING(src)) + QDEL_IN(src, 4 SECONDS) diff --git a/code/modules/clothing/masks/smokable.dm b/code/modules/clothing/masks/smokable.dm index 3612df6f7183..675783b875e1 100644 --- a/code/modules/clothing/masks/smokable.dm +++ b/code/modules/clothing/masks/smokable.dm @@ -197,7 +197,7 @@ /obj/item/clothing/mask/smokable/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) if(target.is_on_fire()) user.do_attack_animation(target) - light(SPAN_NOTICE("\The [user] coldly lights the \the [src] with the burning body of \the [target].")) + light(SPAN_NOTICE("\The [user] coldly lights \the [src] with the burning body of \the [target].")) return TRUE return ..() diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm index 8fa00d9ada6a..abf699315de8 100644 --- a/code/modules/clothing/spacesuits/rig/modules/utility.dm +++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm @@ -456,14 +456,7 @@ use_power_cost = 200 usable = 1 selectable = 0 - device = /obj/item/paper_bin - -/obj/item/rig_module/device/paperdispenser/engage(atom/target) - if(!..() || !device) - return FALSE - if(!target) - device.attack_hand_with_interaction_checks(holder.wearer) - return TRUE + device = /obj/item/form_printer /obj/item/rig_module/device/pen name = "mounted pen" diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index 0002058a65fe..f9f4f356c2bb 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -264,7 +264,7 @@ wearer.visible_message( SPAN_HARDSUIT("[wearer]'s suit emits a quiet hum as it begins to adjust its seals."), SPAN_HARDSUIT("With a quiet hum, the suit begins running checks and adjusting components.")) - if(seal_delay && !do_after(wearer,seal_delay, src)) + if(seal_delay && !do_after(wearer, seal_delay, src)) if(wearer) to_chat(wearer, "You must remain still while the suit is adjusting the components.") failed_to_seal = 1 @@ -299,7 +299,7 @@ var/obj/item/compare_piece = piece_data[2] var/msg_type = piece_data[3] - if(!piece) + if(!piece || !compare_piece) continue if(!istype(wearer) || !istype(piece) || !istype(compare_piece) || !msg_type) diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm index 22a1e57aafe4..896bd3db2416 100644 --- a/code/modules/clothing/spacesuits/spacesuits.dm +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -1,6 +1,6 @@ //Spacesuit //Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together. -// Meaning the the suit is defined directly after the corrisponding helmet. Just like below! +// Meaning the suit is defined directly after the corresponding helmet. Just like below! /obj/item/clothing/head/helmet/space name = "space helmet" diff --git a/code/modules/clothing/suits/armor/merc.dm b/code/modules/clothing/suits/armor/merc.dm index 869b423be900..a138ef7b732a 100644 --- a/code/modules/clothing/suits/armor/merc.dm +++ b/code/modules/clothing/suits/armor/merc.dm @@ -9,7 +9,7 @@ /obj/item/clothing/armor_attachment/plate/merc name = "heavy armor plate" - desc = "A diamond-reinforced titanium armor plate, providing state of of the art protection. Attaches to a plate carrier." + desc = "A diamond-reinforced titanium armor plate, providing state of the art protection. Attaches to a plate carrier." icon = 'icons/clothing/accessories/armor/armor_merc.dmi' armor = list( ARMOR_MELEE = ARMOR_MELEE_RESISTANT, diff --git a/code/modules/clothing/webbing/holster.dm b/code/modules/clothing/webbing/holster.dm index 47ca037c939e..1d49eaabc2b7 100644 --- a/code/modules/clothing/webbing/holster.dm +++ b/code/modules/clothing/webbing/holster.dm @@ -12,25 +12,24 @@ . = ..() set_extension(src, /datum/extension/holster, storage, sound_in, sound_out, can_holster) -/obj/item/clothing/webbing/holster/attackby(obj/item/W, mob/user) - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - if(H.holster(W, user)) +/obj/item/clothing/webbing/holster/attackby(obj/item/used_item, mob/user) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster.holster(used_item, user)) return TRUE - else - . = ..(W, user) + return ..(used_item, user) /obj/item/clothing/webbing/holster/attack_hand(mob/user) if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - if(H.unholster(user)) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster.unholster(user)) return TRUE return ..() /obj/item/clothing/webbing/holster/examine(mob/user) . = ..(user) - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - H.examine_holster(user) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + holster.examine_holster(user) /obj/item/clothing/webbing/holster/on_attached(var/obj/item/clothing/holder, var/mob/user) . = ..() diff --git a/code/modules/crafting/working/_working.dm b/code/modules/crafting/working/_working.dm index e848937907a7..4957dc0052ab 100644 --- a/code/modules/crafting/working/_working.dm +++ b/code/modules/crafting/working/_working.dm @@ -49,7 +49,7 @@ work_sound.stop(src) update_icon() -/obj/structure/working/attackby(obj/item/W, mob/user) +/obj/structure/working/attackby(obj/item/used_item, mob/user) if(user.check_intent(I_FLAG_HARM)) return ..() @@ -58,12 +58,12 @@ to_chat(user, SPAN_WARNING("\The [src] is currently in use, please wait for it to be finished.")) return TRUE - if(try_take_input(W, user)) + if(try_take_input(used_item, user)) return TRUE return ..() -/obj/structure/working/proc/try_take_input(obj/item/W, mob/user, silent) +/obj/structure/working/proc/try_take_input(obj/item/used_item, mob/user, silent) return FALSE /obj/structure/working/proc/try_unload_material(mob/user) diff --git a/code/modules/crafting/working/textiles/loom.dm b/code/modules/crafting/working/textiles/loom.dm index 2b7bf5ae8688..a68bdacbf57b 100644 --- a/code/modules/crafting/working/textiles/loom.dm +++ b/code/modules/crafting/working/textiles/loom.dm @@ -34,24 +34,24 @@ weaving_type = null weaving_progress = 0 -/obj/structure/working/loom/try_take_input(obj/item/W, mob/user) +/obj/structure/working/loom/try_take_input(obj/item/used_item, mob/user) - if(istype(W, /obj/item/stack/material/thread)) + if(istype(used_item, /obj/item/stack/material/thread)) - if(!W.material.has_textile_fibers) - to_chat(user, SPAN_WARNING("\The [W] isn't suitable for making cloth.")) + if(!used_item.material.has_textile_fibers) + to_chat(user, SPAN_WARNING("\The [used_item] isn't suitable for making cloth.")) return TRUE var/loaded = FALSE if(loaded_thread) - if(!loaded_thread.can_merge_stacks(W)) + if(!loaded_thread.can_merge_stacks(used_item)) to_chat(user, SPAN_WARNING("\The [src] is already wound with \the [loaded_thread].")) return TRUE - var/obj/item/stack/feeding = W + var/obj/item/stack/feeding = used_item feeding.transfer_to(loaded_thread) loaded = TRUE - else if(user.try_unequip(W, src)) - loaded_thread = W + else if(user.try_unequip(used_item, src)) + loaded_thread = used_item loaded = TRUE if(loaded) weaving_color = loaded_thread.get_color() diff --git a/code/modules/crafting/working/textiles/spinning_wheel.dm b/code/modules/crafting/working/textiles/spinning_wheel.dm index e79afe923791..84b1dab6e1b4 100644 --- a/code/modules/crafting/working/textiles/spinning_wheel.dm +++ b/code/modules/crafting/working/textiles/spinning_wheel.dm @@ -24,16 +24,16 @@ /obj/structure/working/spinning_wheel/proc/can_process(obj/item/thing) return istype(thing) && thing.has_textile_fibers() -/obj/structure/working/spinning_wheel/try_take_input(obj/item/W, mob/user) +/obj/structure/working/spinning_wheel/try_take_input(obj/item/used_item, mob/user) - if(istype(W.storage)) + if(istype(used_item.storage)) var/list/loading_growns = list() - for(var/obj/item/thing in W.get_stored_inventory()) + for(var/obj/item/thing in used_item.get_stored_inventory()) if(can_process(thing)) loading_growns += thing if(!length(loading_growns)) - to_chat(user, SPAN_WARNING("Nothing in \the [W] is suitable for processing on \the [src].")) + to_chat(user, SPAN_WARNING("Nothing in \the [used_item] is suitable for processing on \the [src].")) return TRUE if(length(loaded) >= MAX_LOADED) @@ -42,24 +42,24 @@ var/loaded_items = 0 for(var/obj/item/thing as anything in loading_growns) - if(W.storage.remove_from_storage(thing, src, TRUE)) + if(used_item.storage.remove_from_storage(thing, src, TRUE)) loaded_items++ LAZYADD(loaded, thing) if(length(loaded) >= MAX_LOADED) break if(loaded_items) - W.storage.finish_bulk_removal() - to_chat(user, SPAN_NOTICE("You prepare \the [src] with [loaded_items] items from \the [W].")) + used_item.storage.finish_bulk_removal() + to_chat(user, SPAN_NOTICE("You prepare \the [src] with [loaded_items] items from \the [used_item].")) update_icon() return TRUE - if(can_process(W)) + if(can_process(used_item)) if(length(loaded) >= MAX_LOADED) to_chat(user, SPAN_WARNING("\The [src] is already fully stocked and ready for spinning.")) return TRUE - if(user.try_unequip(W, src)) - LAZYADD(loaded, W) - to_chat(user, SPAN_NOTICE("You prepare \the [src] with \the [W].")) + if(user.try_unequip(used_item, src)) + LAZYADD(loaded, used_item) + to_chat(user, SPAN_NOTICE("You prepare \the [src] with \the [used_item].")) update_icon() return TRUE return TRUE diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm index b2af21d0e601..0068fd756616 100644 --- a/code/modules/detectivework/tools/rag.dm +++ b/code/modules/detectivework/tools/rag.dm @@ -43,8 +43,13 @@ if(is_on_fire() && user.try_unequip(src)) user.visible_message(SPAN_NOTICE("\The [user] stamps out [src]."), SPAN_NOTICE("You stamp out [src].")) extinguish_fire() - else + return TRUE + + if(reagents?.total_volume) remove_contents(user) + return TRUE + + return ..() /obj/item/chems/glass/rag/attackby(obj/item/W, mob/user) if(W.isflamesource()) @@ -79,28 +84,35 @@ /obj/item/chems/glass/rag/proc/remove_contents(mob/user, atom/trans_dest = null) if(!trans_dest && !user.loc) return + if(reagents?.total_volume <= 0) + return + var/target_text = trans_dest? "\the [trans_dest]" : "\the [user.loc]" + user.visible_message( + SPAN_NOTICE("\The [user] begins to wring out [src] over [target_text]."), + SPAN_NOTICE("You begin to wring out \the [src] over [target_text].") + ) + if(!do_after(user, reagents.total_volume*5, progress = 0) || !reagents?.total_volume) //50 for a fully soaked rag + return + if(trans_dest) + reagents.trans_to(trans_dest, reagents.total_volume) + else + reagents.splash(user.loc, reagents.total_volume) + user.visible_message( + SPAN_NOTICE("\The [user] wrings out \the [src] over [target_text]."), + SPAN_NOTICE("You finish to wringing out \the [src].") + ) + update_name() - if(reagents.total_volume) - var/target_text = trans_dest? "\the [trans_dest]" : "\the [user.loc]" - user.visible_message("\The [user] begins to wring out [src] over [target_text].", "You begin to wring out [src] over [target_text].") - - if(do_after(user, reagents.total_volume*5, progress = 0)) //50 for a fully soaked rag - if(trans_dest) - reagents.trans_to(trans_dest, reagents.total_volume) - else - reagents.splash(user.loc, reagents.total_volume) - user.visible_message("\The [user] wrings out [src] over [target_text].", "You finish to wringing out [src].") - update_name() +/obj/item/chems/glass/rag/proc/wipe_down(atom/target, mob/user) -/obj/item/chems/glass/rag/proc/wipe_down(atom/A, mob/user) - if(!reagents.total_volume) - to_chat(user, "The [initial(name)] is dry!") - else - user.visible_message("\The [user] starts to wipe down [A] with [src]!") - update_name() - if(do_after(user,30, progress = 1)) - user.visible_message("\The [user] finishes wiping off the [A]!") - reagents.splash(A, FLUID_QDEL_POINT) + if(!reagents?.total_volume) + to_chat(user, SPAN_WARNING("The [initial(name)] is dry.")) + return + + user.visible_message(SPAN_NOTICE("\The [user] starts to wipe down \the [target] with \the [src].")) + if(do_after(user, 3 SECONDS, target, check_holding = TRUE)) + user.visible_message(SPAN_NOTICE("\The [user] finishes wiping off \the [target].")) + reagents.touch_atom(target) /obj/item/chems/glass/rag/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) @@ -162,7 +174,7 @@ return if(!is_on_fire() && istype(A) && (src in user)) - if(ATOM_IS_OPEN_CONTAINER(A) && !(A in user)) + if(ATOM_IS_OPEN_CONTAINER(A) && !isturf(A) && !(A in user)) remove_contents(user, A) else if(!ismob(A)) //mobs are handled in use_on_mob() - this prevents us from wiping down people while smothering them. wipe_down(A, user) diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index b647e3c4a5ab..c19e7c42b325 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -81,7 +81,7 @@ "When asked a question, respond with the least-obvious and least-rational answer.", "[pick("Everyone", random_player)] is wearing a pretty pink dress! Compliment it!", "You are the [location_name()]'s psychologist. Give advice to [pick("the crew", random_player)].", - "[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.", + "[random_player] is the monarch of England. Ensure all crewmembers pay due respect.", "[pick("The crew", random_player)] is [pick("ugly","beautiful")]. Ensure all are aware.", "Reminding the crew of their mortality is good for the morale. Keep the crew's morale up.", "[pick("Monkeys","Doors")] are part of the crew, too. Make sure they are treated humanely.", diff --git a/code/modules/fluids/_fluid.dm b/code/modules/fluids/_fluid.dm index 13f78edf239d..58f73cd55c46 100644 --- a/code/modules/fluids/_fluid.dm +++ b/code/modules/fluids/_fluid.dm @@ -15,6 +15,10 @@ var/updating_edge_mask var/force_flow_direction +/atom/movable/fluid_overlay/on_turf_height_change(new_height) + update_icon() + return TRUE + /atom/movable/fluid_overlay/on_update_icon() var/datum/reagents/loc_reagents = loc?.reagents diff --git a/code/modules/food/utensils/_utensil.dm b/code/modules/food/utensils/_utensil.dm index adabd99b0366..7bc767b24e00 100644 --- a/code/modules/food/utensils/_utensil.dm +++ b/code/modules/food/utensils/_utensil.dm @@ -17,8 +17,6 @@ w_class = ITEM_SIZE_SMALL origin_tech = @'{"materials":1}' attack_verb = list("attacked", "stabbed", "poked") - sharp = FALSE - edge = FALSE material = /decl/material/solid/metal/aluminium material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME @@ -121,8 +119,8 @@ /obj/item/food/proc/do_utensil_interaction(obj/item/tool, mob/user) // Non-utensils. - if(tool && !istype(tool, /obj/item/utensil)) - return has_edge(tool) && (utensil_flags & UTENSIL_FLAG_SLICE) && handle_utensil_cutting(tool, user) + if(istype(tool) && !istype(tool, /obj/item/utensil)) + return tool.has_edge() && (utensil_flags & UTENSIL_FLAG_SLICE) && handle_utensil_cutting(tool, user) var/obj/item/utensil/utensil = tool if(!istype(utensil) || !utensil.utensil_flags) @@ -131,9 +129,9 @@ if(!handle_utensil_spreading(utensil, user)) to_chat(user, SPAN_WARNING("You already have something on \the [utensil].")) return TRUE - if((utensil.edge || (utensil.utensil_flags & UTENSIL_FLAG_SLICE)) && (utensil_flags & UTENSIL_FLAG_SLICE) && handle_utensil_cutting(utensil, user)) + if((utensil.has_edge() || (utensil.utensil_flags & UTENSIL_FLAG_SLICE)) && (utensil_flags & UTENSIL_FLAG_SLICE) && handle_utensil_cutting(utensil, user)) return TRUE - if((utensil.sharp || (utensil.utensil_flags & UTENSIL_FLAG_COLLECT)) && (utensil_flags & UTENSIL_FLAG_COLLECT) && handle_utensil_collection(utensil, user)) + if((utensil.is_sharp() || (utensil.utensil_flags & UTENSIL_FLAG_COLLECT)) && (utensil_flags & UTENSIL_FLAG_COLLECT) && handle_utensil_collection(utensil, user)) return TRUE if((utensil.utensil_flags & UTENSIL_FLAG_SCOOP) && (utensil_flags & UTENSIL_FLAG_SCOOP) && handle_utensil_scooping(utensil, user)) return TRUE diff --git a/code/modules/food/utensils/utensil_hybrid.dm b/code/modules/food/utensils/utensil_hybrid.dm index d7ad70bed87a..dde7a7e98952 100644 --- a/code/modules/food/utensils/utensil_hybrid.dm +++ b/code/modules/food/utensils/utensil_hybrid.dm @@ -1,18 +1,18 @@ /obj/item/utensil/spork - name = "spork" - desc = "It's a spork. It's much like a fork, but much blunter." - icon = 'icons/obj/food/utensils/spork.dmi' + name = "spork" + desc = "It's a spork. It's much like a fork, but much blunter." + icon = 'icons/obj/food/utensils/spork.dmi' utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SCOOP /obj/item/utensil/spork/plastic material = /decl/material/solid/organic/plastic /obj/item/utensil/foon - name = "foon" - desc = "It's a foon. It's much like a spoon, but much sharper." - icon = 'icons/obj/food/utensils/foon.dmi' - sharp = TRUE - edge = TRUE + name = "foon" + desc = "It's a foon. It's much like a spoon, but much sharper." + icon = 'icons/obj/food/utensils/foon.dmi' + sharp = TRUE + edge = TRUE utensil_flags = UTENSIL_FLAG_SLICE | UTENSIL_FLAG_SCOOP /obj/item/utensil/foon/plastic diff --git a/code/modules/holidays/holiday_special.dm b/code/modules/holidays/holiday_special.dm index 36f2c7f2695d..375c6a3d9f86 100644 --- a/code/modules/holidays/holiday_special.dm +++ b/code/modules/holidays/holiday_special.dm @@ -1,12 +1,12 @@ -/datum/holiday/christmas/New() - ..() +/datum/holiday/christmas announcement = "Merry Christmas, everyone!" /datum/holiday/christmas/set_up_holiday() - for(var/obj/structure/flora/tree/pine/xmas in world) - if(isNotStationLevel(xmas.z)) + for(var/obj/structure/flora/tree/pine/xmas/crimmas_tree in global.christmas_trees) + if(isNotStationLevel(crimmas_tree.z)) continue - for(var/turf/T in orange(1,xmas)) - if(T.is_floor() && T.simulated) - for(var/i = 1 to rand(1,5)) - new /obj/item/a_gift(T) + for(var/turf/T in orange(1, crimmas_tree)) + if(!T.is_floor() || !T.simulated) + continue + for(var/i = 1 to rand(1,5)) + new /obj/item/a_gift(T) diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index 2d9b37d42098..e151a9bbbc48 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -157,7 +157,7 @@ playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) visible_message("\The [src] was hit by \the [I].") if(I.atom_damage_type == BRUTE || I.atom_damage_type == BURN) - take_damage(I.get_attack_force(user)) + take_damage(I.expend_attack_force(user)) return TRUE src.add_fingerprint(user) diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 873ec702462e..1065eb1d8a22 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -131,23 +131,23 @@ return var/damage = 0 - var/has_edge = 0 + var/edged = 0 if(get_trait(TRAIT_CARNIVOROUS) >= 2) if(affecting) to_chat(target, "\The [fruit]'s thorns pierce your [affecting.name] greedily!") else to_chat(target, "\The [fruit]'s thorns pierce your flesh greedily!") damage = max(5, round(15*get_trait(TRAIT_POTENCY)/100, 1)) - has_edge = prob(get_trait(TRAIT_POTENCY)/2) + edged = prob(get_trait(TRAIT_POTENCY)/2) else if(affecting) to_chat(target, "\The [fruit]'s thorns dig deeply into your [affecting.name]!") else to_chat(target, "\The [fruit]'s thorns dig deeply into your flesh!") damage = max(1, round(5*get_trait(TRAIT_POTENCY)/100, 1)) - has_edge = prob(get_trait(TRAIT_POTENCY)/5) + edged = prob(get_trait(TRAIT_POTENCY)/5) - var/damage_flags = DAM_SHARP|(has_edge? DAM_EDGE : 0) + var/damage_flags = DAM_SHARP|(edged? DAM_EDGE : 0) target.apply_damage(damage, BRUTE, target_limb, damage_flags, used_weapon = "Thorns") // Adds reagents to a target. @@ -256,16 +256,15 @@ var/growth_rate = 1 var/turf/current_turf = isturf(holder) ? holder : get_turf(holder) - if(istype(holder) && !holder.mechanical && current_turf) - growth_rate = current_turf.get_plant_growth_rate() + if(istype(holder)) + growth_rate = holder.get_growth_rate() var/health_change = 0 // Handle gas consumption. if(consume_gasses && consume_gasses.len) var/missing_gas = 0 for(var/gas in consume_gasses) - if(environment && environment.gas && environment.gas[gas] && \ - environment.gas[gas] >= consume_gasses[gas]) + if(LAZYACCESS(environment?.gas, gas) >= consume_gasses[gas]) if(!check_only) environment.adjust_gas(gas,-consume_gasses[gas],1) else diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index bd7c4a3fb0f3..0980347c73d7 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -200,7 +200,7 @@ /obj/effect/vine/attackby(var/obj/item/W, var/mob/user) START_PROCESSING(SSvines, src) - if(W.edge && W.w_class < ITEM_SIZE_NORMAL && !user.check_intent(I_FLAG_HARM)) + if(W.has_edge() && W.w_class < ITEM_SIZE_NORMAL && !user.check_intent(I_FLAG_HARM)) if(!is_mature()) to_chat(user, SPAN_WARNING("\The [src] is not mature enough to yield a sample yet.")) return TRUE @@ -216,8 +216,8 @@ return TRUE else . = ..() - var/damage = W.get_attack_force(user) - if(W.edge) + var/damage = W.expend_attack_force(user) + if(W.has_edge()) damage *= 2 adjust_health(-damage) playsound(get_turf(src), W.hitsound, 100, 1) @@ -280,12 +280,12 @@ /decl/interaction_handler/vine_chop/invoked(atom/target, mob/user, obj/item/prop) var/obj/effect/vine/vine = target var/obj/item/holding = user.get_active_held_item() - if(!istype(holding) || !holding.edge || holding.w_class < ITEM_SIZE_NORMAL) + if(!istype(holding) || !holding.has_edge() || holding.w_class < ITEM_SIZE_NORMAL) to_chat(user, SPAN_WARNING("You need a larger or sharper object for this task!")) return user.visible_message(SPAN_NOTICE("\The [user] starts chopping down \the [vine].")) playsound(get_turf(vine), holding.hitsound, 100, 1) - var/chop_time = (vine.current_health/holding.get_attack_force(user)) * 0.5 SECONDS + var/chop_time = (vine.current_health/holding.expend_attack_force(user)) * 0.5 SECONDS if(user.skill_check(SKILL_BOTANY, SKILL_ADEPT)) chop_time *= 0.5 if(do_after(user, chop_time, vine, TRUE)) diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index f0f7beb5e72e..cc12942e6f05 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -36,8 +36,6 @@ // Mechanical concerns. var/plant_health = 0 // Plant health. var/lastproduce = 0 // Last time tray was harvested - var/lastcycle = 0 // Cycle timing/tracking var. - var/cycledelay = 150 // Delay per cycle. var/closed_system // If set, the tray will attempt to take atmos from a pipe. var/force_update // Set this to bypass the cycle time check. var/obj/temp_chem_holder // Something to hold reagents during process_reagents() @@ -328,7 +326,6 @@ return //Weed does not exist, someone fucked up. age = 0 - lastcycle = world.time harvest = 0 weedlevel = 0 pestlevel = 0 @@ -397,7 +394,6 @@ set_seed(SSplants.seeds[newseed]) mutate(1) plant_health = seed.get_trait(TRAIT_ENDURANCE) // re-run in case mutation changed our endurance - lastcycle = world.time update_icon() visible_message("The [previous_plant] has suddenly mutated into [seed.display_name]!") @@ -498,15 +494,16 @@ to_chat(user, "You [anchored ? "wrench" : "unwrench"] \the [src].") return TRUE - var/force = used_item.get_attack_force(user) - if(force && seed) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [used_item]!") - playsound(get_turf(src), used_item.hitsound, 100, 1) - if(!dead) - plant_health -= force - check_plant_health() - return TRUE + if(seed) + var/force = used_item.expend_attack_force(user) + if(force) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [used_item]!") + playsound(get_turf(src), used_item.hitsound, 100, 1) + if(!dead) + plant_health -= force + check_plant_health() + return TRUE if(mechanical) return component_attackby(used_item, user) @@ -556,7 +553,6 @@ //Snowflakey, maybe move this to the seed datum // re-running to adjust based on planting method plant_health = (istype(S, /obj/item/seeds/extracted/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) - lastcycle = world.time var/needed_skill = seed.mysterious ? SKILL_ADEPT : SKILL_BASIC if(prob(user.skill_fail_chance(SKILL_BOTANY, 40, needed_skill))) @@ -654,7 +650,6 @@ age = 1 // re-running to adjust for planting method plant_health = (istype(S, /obj/item/seeds/extracted/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) - lastcycle = world.time check_plant_health() qdel(S) @@ -691,7 +686,7 @@ examine_desc = "take a sample" /decl/interaction_handler/hydroponics/sample/is_possible(atom/target, mob/user, obj/item/prop) - return ..() && istype(prop) && prop.edge && prop.w_class < ITEM_SIZE_NORMAL + return ..() && istype(prop) && prop.has_edge() && prop.w_class < ITEM_SIZE_NORMAL /decl/interaction_handler/hydroponics/sample/invoked(atom/target, mob/user, obj/item/prop) var/obj/machinery/portable_atmospherics/hydroponics/tray = target diff --git a/code/modules/hydroponics/trays/tray_process.dm b/code/modules/hydroponics/trays/tray_process.dm index 05c029e69b47..dbcf6f194470 100644 --- a/code/modules/hydroponics/trays/tray_process.dm +++ b/code/modules/hydroponics/trays/tray_process.dm @@ -1,37 +1,29 @@ -/obj/machinery/portable_atmospherics/hydroponics/Process() - - var/growth_rate = 1 - var/turf/T = get_turf(src) - if(istype(T)) - if(!mechanical) - growth_rate = T.get_plant_growth_rate() - - if(!closed_system) - var/space_left = reagents ? (reagents.maximum_volume - reagents.total_volume) : 0 - if(space_left > 0 && reagents.total_volume < 10) - // Handle nearby smoke if any. - for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) - if(smoke.reagents.total_volume) - smoke.reagents.trans_to_obj(src, 5, copy = 1) - // Handle environmental effects like weather and flooding. - if(T.reagents?.total_volume) - T.reagents.trans_to_obj(src, min(space_left, min(T.reagents.total_volume, rand(5,10)))) - if(istype(T.weather?.weather_system?.current_state, /decl/state/weather/rain)) - var/decl/state/weather/rain/rain = T.weather.weather_system.current_state - if(rain.is_liquid) - reagents.add_reagent(T.weather.water_material, min(space_left, rand(3,5))) +/obj/machinery/portable_atmospherics/hydroponics/proc/get_growth_rate() + return 1 + +/obj/machinery/portable_atmospherics/hydroponics/process_plants() + + var/growth_rate = get_growth_rate() + var/turf/my_turf = get_turf(src) + if(istype(my_turf) && !closed_system) + var/space_left = reagents ? (reagents.maximum_volume - reagents.total_volume) : 0 + if(space_left > 0 && reagents.total_volume < 10) + // Handle nearby smoke if any. + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) + if(smoke.reagents.total_volume) + smoke.reagents.trans_to_obj(src, 5, copy = 1) + // Handle environmental effects like weather and flooding. + if(my_turf.reagents?.total_volume) + my_turf.reagents.trans_to_obj(src, min(space_left, min(my_turf.reagents.total_volume, rand(5,10)))) + if(istype(my_turf.weather?.weather_system?.current_state, /decl/state/weather/rain)) + var/decl/state/weather/rain/rain = my_turf.weather.weather_system.current_state + if(rain.is_liquid) + reagents.add_reagent(my_turf.weather.water_material, min(space_left, rand(3,5))) //Do this even if we're not ready for a plant cycle. process_reagents() var/needs_icon_update = 0 - // Update values every cycle rather than every process() tick. - if(force_update) - force_update = 0 - else if(world.time < (lastcycle + cycledelay)) - return - lastcycle = world.time - // Mutation level drops each main tick. mutation_level -= rand(2,4) @@ -94,7 +86,7 @@ if(closed_system && (get_port() || holding)) environment = air_contents // If atmos input is not there, grab from turf. - if(!environment && istype(T)) environment = T.return_air() + if(!environment && istype(my_turf)) environment = my_turf.return_air() if(!environment) return // Seed datum handles gasses, light and pressure. @@ -148,9 +140,9 @@ if(!closed_system && \ seed.get_trait(TRAIT_SPREAD) == 2 && \ 2 * age >= seed.get_trait(TRAIT_MATURATION) && \ - !(locate(/obj/effect/vine) in T) && \ + !(locate(/obj/effect/vine) in my_turf) && \ prob(2 * seed.get_trait(TRAIT_POTENCY))) - new /obj/effect/vine(T, seed) + new /obj/effect/vine(my_turf, seed) if(prob(3)) // On each tick, there's a chance the pest population will increase pestlevel += 0.1 * growth_rate diff --git a/code/modules/hydroponics/trays/tray_soil.dm b/code/modules/hydroponics/trays/tray_soil.dm index 46ab1b85227a..279cc704d58d 100644 --- a/code/modules/hydroponics/trays/tray_soil.dm +++ b/code/modules/hydroponics/trays/tray_soil.dm @@ -24,6 +24,10 @@ LAZYREMOVE(., global._reagent_interactions) LAZYADD(., /decl/interaction_handler/empty_into) +/obj/machinery/portable_atmospherics/hydroponics/soil/get_growth_rate() + var/turf/my_turf = get_turf(src) + return max(0, my_turf?.get_plant_growth_rate()) + /obj/machinery/portable_atmospherics/hydroponics/soil/Initialize() . = ..() @@ -63,7 +67,7 @@ return if(prob(25)) return - to_chat(walker, SPAN_DANGER("You trample \the [seed]!")) + to_chat(walker, SPAN_DANGER("You trample \the [seed.display_name]!")) plant_health = max(0, plant_health - rand(3,5)) check_plant_health() @@ -162,7 +166,6 @@ dead = 0 age = start_mature ? seed.get_trait(TRAIT_MATURATION) : 1 plant_health = seed.get_trait(TRAIT_ENDURANCE) - lastcycle = world.time if(isnull(default_pixel_y)) default_pixel_y = rand(-12,12) if(isnull(default_pixel_y)) @@ -199,4 +202,7 @@ for(var/obj/effect/vine/plant in get_turf(src)) if(plant.invisibility == INVISIBILITY_MAXIMUM) plant.set_invisibility(initial(plant.invisibility)) - . = ..() \ No newline at end of file + . = ..() + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/get_growth_rate() + return max(..(), 1) diff --git a/code/modules/integrated_electronics/subtypes/memory.dm b/code/modules/integrated_electronics/subtypes/memory.dm index c4c127693b4f..b105438a0377 100644 --- a/code/modules/integrated_electronics/subtypes/memory.dm +++ b/code/modules/integrated_electronics/subtypes/memory.dm @@ -63,7 +63,7 @@ /obj/item/integrated_circuit/memory/huge name = "large memory stick" - desc = "This stick of memory can store up up to sixteen pieces of data." + desc = "This stick of memory can store up to sixteen pieces of data." icon_state = "memory16" w_class = ITEM_SIZE_SMALL spawn_flags = IC_SPAWN_RESEARCH diff --git a/code/modules/interactions/interactions_reagents.dm b/code/modules/interactions/interactions_reagents.dm index 8b584709c4ce..7a50cfaacf59 100644 --- a/code/modules/interactions/interactions_reagents.dm +++ b/code/modules/interactions/interactions_reagents.dm @@ -4,7 +4,7 @@ examine_desc = "dip an item into $TARGET_THEM$" /decl/interaction_handler/dip_item/is_possible(atom/target, mob/user, obj/item/prop) - return ..() && target.reagents?.total_volume >= FLUID_MINIMUM_TRANSFER && istype(prop) && target.can_be_poured_from(user, prop) + return ..() && target != prop && target.reagents?.total_volume >= FLUID_MINIMUM_TRANSFER && istype(prop) && target.can_be_poured_from(user, prop) /decl/interaction_handler/dip_item/invoked(atom/target, mob/user, obj/item/prop) user.visible_message(SPAN_NOTICE("\The [user] dips \the [prop] into \the [target.reagents.get_primary_reagent_name()].")) @@ -25,7 +25,7 @@ /decl/interaction_handler/fill_from/is_possible(atom/target, mob/user, obj/item/prop) if(!(. = ..())) return - if(target.reagents?.total_volume < FLUID_PUDDLE) + if(target == prop || target.reagents?.total_volume < FLUID_PUDDLE) return FALSE if(!istype(prop) || (!isitem(target) && !istype(target, /obj/structure/reagent_dispensers))) return FALSE @@ -48,7 +48,7 @@ /decl/interaction_handler/empty_into/is_possible(atom/target, mob/user, obj/item/prop) if(!(. = ..())) return - if(!istype(prop) || prop.reagents?.total_volume <= 0) + if(target == prop || !istype(prop) || prop.reagents?.total_volume <= 0) return FALSE return target.can_be_poured_into(user, prop) && prop.can_be_poured_from(user, target) diff --git a/code/modules/item_effects/_item_effect.dm b/code/modules/item_effects/_item_effect.dm index 9516a3a9639b..54199b3584da 100644 --- a/code/modules/item_effects/_item_effect.dm +++ b/code/modules/item_effects/_item_effect.dm @@ -1,13 +1,3 @@ -#define ITEM_EFFECT_STRIKE "weff_strike" -#define ITEM_EFFECT_PARRY "weff_parry" -#define ITEM_EFFECT_USED "weff_used" -#define ITEM_EFFECT_WIELDED "weff_wield" -#define ITEM_EFFECT_VISUAL "weff_visual" -#define ITEM_EFFECT_LISTENER "weff_listener" -#define ITEM_EFFECT_VISIBLE "weff_visible" -#define ITEM_EFFECT_RANGED "weff_ranged" -#define ITEM_EFFECT_PROCESS "weff_process" - /decl/item_effect abstract_type = /decl/item_effect @@ -75,6 +65,12 @@ SHOULD_CALL_PARENT(FALSE) return FALSE -/decl/item_effect/proc/examined(obj/item/item, mob/user) +/decl/item_effect/proc/on_examined(obj/item/item, mob/user, distance, list/parameters) SHOULD_CALL_PARENT(FALSE) return FALSE + +/decl/item_effect/proc/modify_attack_damage(base_damage, obj/item/used_item, mob/user, dry_run, list/parameters) + return base_damage + +/decl/item_effect/proc/expend_attack_use(obj/item/used_item, mob/user, dry_run, list/parameters) + return diff --git a/code/modules/item_effects/item_effect_aura.dm b/code/modules/item_effects/item_effect_aura.dm index d08b4a4968ea..c30e3a36461a 100644 --- a/code/modules/item_effects/item_effect_aura.dm +++ b/code/modules/item_effects/item_effect_aura.dm @@ -16,7 +16,7 @@ user.remove_aura(aura_type) return TRUE -/decl/item_effect/aura/examined(obj/item/item, mob/user) +/decl/item_effect/aura/on_examined(obj/item/item, mob/user) var/obj/aura/aura = aura_type to_chat(user, SPAN_NOTICE("\The [item] grants \a [initial(aura.name)] to the wielder.")) diff --git a/code/modules/item_effects/item_effect_charges.dm b/code/modules/item_effects/item_effect_charges.dm index 4a27d3d0a271..06e8126b16fe 100644 --- a/code/modules/item_effects/item_effect_charges.dm +++ b/code/modules/item_effects/item_effect_charges.dm @@ -3,14 +3,14 @@ abstract_type = /decl/item_effect/charges /decl/item_effect/charges/do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) - var/charges = (LAZYACCESS(parameters, "charges") || 0) + var/charges = (LAZYACCESS(parameters, IE_PAR_USES) || 0) if(charges <= 0) return FALSE - item.set_item_effect_parameter(src, ITEM_EFFECT_RANGED, "charges", charges-1) + item.set_item_effect_parameter(src, IE_CAT_RANGED, IE_PAR_USES, charges-1) return TRUE -/decl/item_effect/charges/examined(obj/item/item, mob/user) - to_chat(user, SPAN_NOTICE("\The [item] has [item.get_item_effect_parameter(src, ITEM_EFFECT_RANGED, "charges") || 0] charge\s of [effect_descriptor] left.")) +/decl/item_effect/charges/on_examined(obj/item/item, mob/user) + to_chat(user, SPAN_NOTICE("\The [item] has [item.get_item_effect_parameter(src, IE_CAT_RANGED, IE_PAR_USES) || 0] charge\s of [effect_descriptor] left.")) /obj/item/projectile/fireball name = "fireball" diff --git a/code/modules/item_effects/item_effect_debug.dm b/code/modules/item_effects/item_effect_debug.dm index 352143ed57b4..1533abda4836 100644 --- a/code/modules/item_effects/item_effect_debug.dm +++ b/code/modules/item_effects/item_effect_debug.dm @@ -37,7 +37,7 @@ /decl/item_effect/debug/hear_speech(obj/item/item, mob/user, message, decl/language/speaking) log_debug("[type]: [item] heard [user] say [message] in [speaking] ([json_encode(args)])") -/decl/item_effect/debug/examined(obj/item/item, mob/user) +/decl/item_effect/debug/on_examined(obj/item/item, mob/user) log_debug("[type]: [user] examined [item] ([json_encode(args)])") /decl/item_effect/debug/do_process_effect(obj/item/item, list/parameters) @@ -46,21 +46,21 @@ /obj/item/sword/katana/debug/Initialize() . = ..() add_item_effect(/decl/item_effect/debug, list( - ITEM_EFFECT_VISUAL = list("vis" = "ual"), - ITEM_EFFECT_STRIKE = list("foo" = "bar"), - ITEM_EFFECT_PARRY = list("fizz" = "buzz"), - ITEM_EFFECT_USED = list("aard" = "vark"), - ITEM_EFFECT_VISIBLE = list("ooo" = "aaa"), - ITEM_EFFECT_LISTENER = list("walla walla" = "bing bong"), - ITEM_EFFECT_PROCESS = list("hyonk" = "hjonk") + (IE_CAT_VISUAL) = list("vis" = "ual"), + (IE_CAT_STRIKE) = list("foo" = "bar"), + (IE_CAT_PARRY) = list("fizz" = "buzz"), + (IE_CAT_USED) = list("aard" = "vark"), + (IE_CAT_EXAMINE) = list("ooo" = "aaa"), + (IE_CAT_LISTENER) = list("walla walla" = "bing bong"), + (IE_CAT_PROCESS) = list("hyonk" = "hjonk") )) add_item_effect(/decl/item_effect/charges/fireball, list( - ITEM_EFFECT_VISIBLE, - ITEM_EFFECT_RANGED = list("charges" = 5) + (IE_CAT_EXAMINE), + (IE_CAT_RANGED) = list(IE_PAR_USES = 5) )) add_item_effect(/decl/item_effect/aura/regeneration, list( - ITEM_EFFECT_VISIBLE, - ITEM_EFFECT_WIELDED + (IE_CAT_EXAMINE), + (IE_CAT_WIELDED) )) /obj/item/staff/crystal/beacon/fireball @@ -71,6 +71,6 @@ /obj/item/staff/crystal/beacon/fireball/Initialize(ml, material_key) . = ..() add_item_effect(/decl/item_effect/charges/fireball, list( - ITEM_EFFECT_VISIBLE, - ITEM_EFFECT_RANGED = list("charges" = 5) + (IE_CAT_EXAMINE), + (IE_CAT_RANGED) = list(IE_PAR_USES = 5) )) \ No newline at end of file diff --git a/code/modules/item_effects/item_effect_item.dm b/code/modules/item_effects/item_effect_item.dm index 22c57157bd4e..ea1be1cfd241 100644 --- a/code/modules/item_effects/item_effect_item.dm +++ b/code/modules/item_effects/item_effect_item.dm @@ -1,6 +1,15 @@ /obj/item var/list/_item_effects +/obj/item/proc/has_item_effect(decl/item_effect/effect, effect_category) + if(!length(_item_effects)) + return FALSE + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect)) + return FALSE + return LAZYISIN(LAZYACCESS(_item_effects, effect_category), effect) + /obj/item/proc/add_item_effect(effect_type, list/effect_parameters) if(!effect_type || !length(effect_parameters)) return FALSE @@ -13,13 +22,15 @@ . = TRUE if(.) - if(ITEM_EFFECT_LISTENER in effect_parameters) + if(IE_CAT_LISTENER in effect_parameters) global.listening_objects |= src - if(ITEM_EFFECT_PROCESS in effect_parameters) + if(IE_CAT_PROCESS in effect_parameters) SSitem_effects.queued_items |= src /obj/item/proc/remove_item_effect(decl/item_effect/effect) - if(!effect || !length(_item_effects)) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects)) return FALSE var/list/removed_effect_categories = list() for(var/effect_category in _item_effects) @@ -30,13 +41,23 @@ LAZYREMOVE(_item_effects, effect_category) . = TRUE if(.) - if(ITEM_EFFECT_LISTENER in removed_effect_categories) + if(IE_CAT_LISTENER in removed_effect_categories) global.listening_objects -= src - if(ITEM_EFFECT_PROCESS in removed_effect_categories) + if(IE_CAT_PROCESS in removed_effect_categories) SSitem_effects.queued_items -= src +/obj/item/proc/get_item_effect_parameters(decl/item_effect/effect, effect_category) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category) + return null + var/list/effects = LAZYACCESS(_item_effects, effect_category) + return LAZYACCESS(effects, effect) + /obj/item/proc/get_item_effect_parameter(decl/item_effect/effect, effect_category, parameter_name) - if(!effect || !length(_item_effects) || !effect_category || !parameter_name) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category || !parameter_name) return null var/list/effects = LAZYACCESS(_item_effects, effect_category) if(!LAZYISIN(effects, effect)) @@ -44,7 +65,9 @@ return LAZYACCESS(effects[effect], parameter_name) /obj/item/proc/set_item_effect_parameter(decl/item_effect/effect, effect_category, parameter_name, parameter_value) - if(!effect || !length(_item_effects) || !effect_category || !parameter_name) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category || !parameter_name) return FALSE var/list/effects = LAZYACCESS(_item_effects, effect_category) if(!LAZYISIN(effects, effect)) @@ -59,7 +82,7 @@ /obj/item/resolve_attackby(atom/A, mob/user, var/click_params) if(!(. = ..())) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_STRIKE) + var/list/item_effects = get_item_effects(IE_CAT_STRIKE) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -72,7 +95,7 @@ // PARRY effects /obj/item/on_parry(mob/user, damage_source, mob/attacker) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_PARRY) + var/list/item_effects = get_item_effects(IE_CAT_PARRY) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -86,7 +109,7 @@ // VISUAL effects (world icon) /obj/item/on_update_icon() . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_VISUAL) + var/list/item_effects = get_item_effects(IE_CAT_VISUAL) if(!length(item_effects)) return for(var/decl/item_effect/used_effect as anything in item_effects) @@ -96,7 +119,7 @@ /obj/item/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) // TODO: this might need work to handle items that do a state or appearance update in the parent call. if(overlay) - var/list/item_effects = get_item_effects(ITEM_EFFECT_VISUAL) + var/list/item_effects = get_item_effects(IE_CAT_VISUAL) if(length(item_effects)) for(var/decl/item_effect/used_effect as anything in item_effects) used_effect.apply_onmob_appearance_to(src, user_mob, bodytype, overlay, slot, bodypart, item_effects[used_effect]) @@ -106,7 +129,7 @@ /obj/item/attack_self(mob/user) if((. = ..())) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_USED) + var/list/item_effects = get_item_effects(IE_CAT_USED) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -120,7 +143,7 @@ // WIELD effects (unwielded) /obj/item/dropped(mob/user) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_WIELDED) + var/list/item_effects = get_item_effects(IE_CAT_WIELDED) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -133,7 +156,7 @@ // WIELD effects (wielded) /obj/item/equipped(mob/user, slot) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_WIELDED) + var/list/item_effects = get_item_effects(IE_CAT_WIELDED) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src) || loc != user || !(slot in user.get_held_item_slots())) @@ -146,7 +169,7 @@ // LISTENING effects /obj/item/hear_talk(mob/M, text, verb, decl/language/speaking) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_LISTENER) + var/list/item_effects = get_item_effects(IE_CAT_LISTENER) if(!length(item_effects)) return for(var/decl/item_effect/listening_effect as anything in item_effects) @@ -157,17 +180,17 @@ . = ..() if(!user) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_VISIBLE) + var/list/item_effects = get_item_effects(IE_CAT_EXAMINE) if(!length(item_effects)) return for(var/decl/item_effect/examine_effect as anything in item_effects) - examine_effect.examined(src, user, distance, item_effects[examine_effect]) + examine_effect.on_examined(src, user, distance, item_effects[examine_effect]) // RANGED effects /obj/item/afterattack(turf/floor/target, mob/user, proximity) if((. = ..()) || proximity) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_RANGED) + var/list/item_effects = get_item_effects(IE_CAT_RANGED) if(!length(item_effects)) return for(var/decl/item_effect/ranged_effect as anything in item_effects) @@ -177,7 +200,7 @@ // PROCESS effects /obj/item/proc/process_item_effects() - var/list/item_effects = get_item_effects(ITEM_EFFECT_PROCESS) + var/list/item_effects = get_item_effects(IE_CAT_PROCESS) if(length(item_effects)) for(var/decl/item_effect/process_effect as anything in item_effects) process_effect.do_process_effect(src, item_effects[process_effect]) diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 17e233358079..53e59fa5b9b0 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -65,27 +65,17 @@ return // Unlit turfs will have corners if they have a lit neighbor -- don't generate corners for them, but do update them if they're there. - // if (!corners) - // var/force_build_corners = FALSE - // for (var/turf/T as anything in RANGE_TURFS(src, 1)) - // if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T)) - // force_build_corners = TRUE - // break - - // if (force_build_corners || TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) - // generate_missing_corners() - // else - // return - - // still inefficient :( - if(!corners || !lighting_corners_initialised) - /* Commented out pending working out why this doesn't work properly on Neb. - if(TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) + if (!corners) + var/force_build_corners = FALSE + for (var/turf/T as anything in RANGE_TURFS(src, 1)) + if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T)) + force_build_corners = TRUE + break + + if (force_build_corners || TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) generate_missing_corners() else return - */ - generate_missing_corners() // This list can contain nulls on things like space turfs -- they only have their neighbors' corners. for (var/datum/lighting_corner/C in corners) @@ -126,8 +116,7 @@ // Builds a lighting overlay for us, but only if our area is dynamic. /turf/proc/lighting_build_overlay(now = FALSE) if (lighting_overlay) - return // shrug - // CRASH("Attempted to create lighting_overlay on tile that already had one.") + CRASH("Attempted to create lighting_overlay on tile that already had one.") if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) if (!lighting_corners_initialised || !corners) diff --git a/code/modules/maps/_map_template.dm b/code/modules/maps/_map_template.dm index a48c199cccca..f7a22eaf01fe 100644 --- a/code/modules/maps/_map_template.dm +++ b/code/modules/maps/_map_template.dm @@ -1,4 +1,5 @@ /datum/map_template + abstract_type = /datum/map_template ///Name for differentiating templates var/name = "Default Template Name" ///The width of the template's levels. Size is preloaded from template during template registration. @@ -14,7 +15,7 @@ ///Shuttles in this template's levels that need to be initialized with SSshuttle. var/list/shuttles_to_initialise = list() ///Sub-templates to spawn on this template if any. Ruins and sites and etc.. - var/list/subtemplates_to_spawn + var/list/subtemplates_to_spawn = list() ///Percent of chances to end up onto a level from this template by spacewalking between space z-levels. var/accessibility_weight = 0 ///Flags for defining special properties of this template. @@ -23,8 +24,6 @@ var/modify_tag_vars = TRUE ///List of strings to store the templates under for mass retrieval. var/list/template_categories - ///If this is equal to current type, the datum is abstract and should not be created. - var/template_parent_type = /datum/map_template ///The initial type of level_data to instantiate new z-level with initially. (Is replaced by whatever is in the map file.) If null, will use default. var/level_data_type /// Various tags used for selecting templates for placement on a map. @@ -67,45 +66,22 @@ if (SSatoms.atom_init_stage == INITIALIZATION_INSSATOMS) return // let proper initialisation handle it later - var/list/turf/turfs = list() - var/list/obj/machinery/atmospherics/atmos_machines = list() - var/list/obj/machinery/machines = list() - var/list/obj/structure/cable/cables = list() - - for(var/atom/A in atoms) - if(isturf(A)) - turfs += A - if(istype(A, /obj/structure/cable)) - cables += A - if(istype(A, /obj/machinery/atmospherics)) - atmos_machines += A - if(istype(A, /obj/machinery)) - machines += A - if(istype(A, /obj/abstract/landmark/map_load_mark)) - LAZYADD(subtemplates_to_spawn, A) - - var/notsuspended - if(!SSmachines.suspended) - SSmachines.suspend() - notsuspended = TRUE - SSatoms.InitializeAtoms() // The atoms should have been getting queued there. This flushes the queue. - SSmachines.setup_powernets_for_cables(cables) - SSmachines.setup_atmos_machinery(atmos_machines) - if(notsuspended) - SSmachines.wake() + for(var/obj/abstract/landmark/map_load_mark/landmark in atoms) + subtemplates_to_spawn += landmark - for (var/obj/machinery/machine as anything in machines) - machine.power_change() + // fun fact: these already filter for us, so it's pointless to sort + SSmachines.setup_powernets_for_cables(atoms) + SSmachines.setup_atmos_machinery(atoms) - for (var/turf/T as anything in turfs) + for (var/turf/T in atoms) if(template_flags & TEMPLATE_FLAG_NO_RUINS) T.turf_flags |= TURF_FLAG_NO_POINTS_OF_INTEREST if(template_flags & TEMPLATE_FLAG_NO_RADS) qdel(SSradiation.sources_assoc[T]) - if(istype(T) && T.simulated) - T.update_air_properties() + if(T.simulated) + SSair.mark_for_update(T) /datum/map_template/proc/pre_init_shuttles() . = SSshuttle.block_queue @@ -185,8 +161,6 @@ for(var/z_index = bounds[MAP_MINZ] to bounds[MAP_MAXZ]) var/datum/level_data/level = SSmapping.levels_by_z[z_index] level.after_template_load(src) - if(SSlighting.initialized) - SSlighting.InitializeZlev(z_index) Master.StopLoadingMap() log_game("Z-level [name] loaded at [x],[y],[world.maxz]") loaded++ @@ -225,11 +199,9 @@ init_atoms(atoms_to_initialise) init_shuttles(shuttle_state, map_hash, initialized_areas_by_type) after_load() - if (SSlighting.initialized) - SSlighting.InitializeTurfs(atoms_to_initialise) // Hopefully no turfs get placed on new coords by SSatoms. Master.StopLoadingMap() - log_game("[name] loaded at at [T.x],[T.y],[T.z]") + log_game("[name] loaded at [T.x],[T.y],[T.z]") loaded++ return TRUE @@ -238,7 +210,7 @@ for(var/obj/abstract/landmark/map_load_mark/mark as anything in subtemplates_to_spawn) subtemplates_to_spawn -= mark mark.load_subtemplate() - if(!QDELETED(mark)) + if(!QDELETED(mark)) // for if the tile that lands on the landmark is a no-op tile qdel(mark) subtemplates_to_spawn = null generate_multi_spawn_items() diff --git a/code/modules/maps/reader.dm b/code/modules/maps/reader.dm index efc444d7b0a1..71bedba36393 100644 --- a/code/modules/maps/reader.dm +++ b/code/modules/maps/reader.dm @@ -12,18 +12,32 @@ var/global/dmm_suite/preloader/_preloader = new var/list/atoms_to_initialise /dmm_suite - // /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g - var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g") + // /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"\n*([a-zA-Z\n]*)\n?"\}/g + var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"\n*(\[a-zA-Z\n]*)\n?"\\}"}, "g") // /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g") // /^[\s\n]+|[\s\n]+$/ var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g") var/static/list/modelCache = list() var/static/space_key + var/static/list/types_to_delete #ifdef TESTING var/static/turfsSkipped #endif +// Set up some basic cached vars, like types_to_delete, that have to check things like subtypes. +/dmm_suite/New() + if(!types_to_delete) + types_to_delete = typecacheof(list( + /mob/living, + /obj/effect, + /obj/item, + /obj/machinery, + /obj/structure, + /obj/abstract/landmark/exoplanet_spawn, + )) + ..() + /** * Construct the model map and control the loading process * @@ -124,20 +138,11 @@ var/global/dmm_suite/preloader/_preloader = new bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd) var/list/gridLines = splittext(dmmRegex.group[6], "\n") - - var/leadingBlanks = 0 - while(leadingBlanks < gridLines.len && gridLines[++leadingBlanks] == "") - if(leadingBlanks > 1) - gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines. - - if(!gridLines.len) // Skip it if only blank lines exist. + if(!length(gridLines)) // Skip it if only blank lines exist. continue - if(gridLines.len && gridLines[gridLines.len] == "") - gridLines.Cut(gridLines.len) // Remove only one blank line at the end. - bounds[MAP_MINY] = min(bounds[MAP_MINY], clamp(ycrd, y_lower, y_upper)) - ycrd += gridLines.len - 1 // Start at the top and work down + ycrd += length(gridLines) - 1 // Start at the top and work down if(!cropMap && ycrd > world.maxy) if(!measureOnly) @@ -185,8 +190,6 @@ var/global/dmm_suite/preloader/_preloader = new maxx = max(maxx, xcrd) ++xcrd --ycrd - if (zexpansion && SSlighting.initialized) - SSlighting.InitializeZlev(zcrd) bounds[MAP_MAXX] = clamp(max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx), x_lower, x_upper) @@ -226,16 +229,6 @@ var/global/dmm_suite/preloader/_preloader = new var/list/atoms_to_initialise var/list/atoms_to_delete -/dmm_suite/proc/types_to_delete() - return list( - /mob/living, - /obj/effect, - /obj/item, - /obj/machinery, - /obj/structure, - /obj/abstract/landmark/exoplanet_spawn, - ) - /dmm_suite/proc/parse_grid(model as text, model_key as text, xcrd as num,ycrd as num,zcrd as num, no_changeturf as num, clear_contents as num, initialized_areas_by_type) /*Method parse_grid() - Accepts a text string containing a comma separated list of type paths of the @@ -288,8 +281,8 @@ var/global/dmm_suite/preloader/_preloader = new if(variables_start)//if there's any variable full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}' fields = readlist(full_def, ";") - if(fields.len) - if(!trim(fields[fields.len])) + if(length(fields)) + if(!trim(fields[length(fields)])) --fields.len for(var/I in fields) var/value = fields[I] @@ -312,7 +305,7 @@ var/global/dmm_suite/preloader/_preloader = new // 5. and the members are world.turf and world.area // Basically, if we find an entry like this: "XXX" = (/turf/default, /area/default) // We can skip calling this proc every time we see XXX - if(no_changeturf && !space_key && members.len == 2 && members_attributes.len == 2 && length(members_attributes[1]) == 0 && length(members_attributes[2]) == 0 && (world.area in members) && (world.turf in members)) + if(no_changeturf && !space_key && length(members) == 2 && length(members_attributes) == 2 && length(members_attributes[1]) == 0 && length(members_attributes[2]) == 0 && (world.area in members) && (world.turf in members)) space_key = model_key return @@ -329,7 +322,7 @@ var/global/dmm_suite/preloader/_preloader = new var/atoms_to_delete = list() //first instance the /area and remove it from the members list - index = members.len + index = length(members) if(members[index] != /area/template_noop) is_not_noop = TRUE var/list/attr = members_attributes[index] @@ -363,20 +356,20 @@ var/global/dmm_suite/preloader/_preloader = new if(T) //if others /turf are presents, simulates the underlays piling effect index = first_turf_index + 1 - while(index <= members.len - 1) // Last item is an /area + while(index < length(members)) // Last item is an /area var/underlay = T.appearance T = instance_atom(members[index],members_attributes[index],crds,no_changeturf)//instance new turf T.underlays += underlay index++ atoms_to_initialise += T - if (clear_contents && is_not_noop) - for (var/type_to_delete in types_to_delete()) - for (var/atom/pre_existing in crds) - if(crds != pre_existing.loc) // avoid deleting multitile objects unnecessarily, only check their 'real' loc - continue - if (istype(pre_existing, type_to_delete)) - atoms_to_delete |= pre_existing + if (clear_contents && is_not_noop && length(crds.contents)) + for (var/atom/movable/pre_existing as anything in crds) + if(!types_to_delete[pre_existing.type]) + continue + if(crds != pre_existing.loc) // avoid deleting multitile objects unnecessarily, only check their 'real' loc + continue + atoms_to_delete += pre_existing //finally instance all remainings objects/mobs for(index in 1 to first_turf_index-1) diff --git a/code/modules/maps/template_types/antag_spawn.dm b/code/modules/maps/template_types/antag_spawn.dm index 7c079ead9eb4..8b8b167bd0fd 100644 --- a/code/modules/maps/template_types/antag_spawn.dm +++ b/code/modules/maps/template_types/antag_spawn.dm @@ -1,3 +1,3 @@ /datum/map_template/ruin/antag_spawn prefix = "maps/antag_spawn/" - template_parent_type = /datum/map_template/ruin/antag_spawn + abstract_type = /datum/map_template/ruin/antag_spawn diff --git a/code/modules/maps/template_types/away_site.dm b/code/modules/maps/template_types/away_site.dm index b9adb30914b1..81d77b0152ef 100644 --- a/code/modules/maps/template_types/away_site.dm +++ b/code/modules/maps/template_types/away_site.dm @@ -1,7 +1,7 @@ /datum/map_template/ruin/away_site prefix = "maps/away/" template_categories = list(MAP_TEMPLATE_CATEGORY_AWAYSITE) - template_parent_type = /datum/map_template/ruin/away_site + abstract_type = /datum/map_template/ruin/away_site var/spawn_weight = 1 /datum/map_template/ruin/away_site/get_spawn_weight() diff --git a/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm b/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm index 45396ae3baf0..4a7f663352e1 100644 --- a/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm +++ b/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm @@ -6,7 +6,6 @@ /datum/map_template/planetoid name = "planetoid" abstract_type = /datum/map_template/planetoid - template_parent_type = /datum/map_template/planetoid template_categories = list(MAP_TEMPLATE_CATEGORY_PLANET) level_data_type = /datum/level_data/planetoid modify_tag_vars = TRUE diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm index 7ef37a05e79a..6de9ef4a6001 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm @@ -13,7 +13,7 @@ /datum/level_data/planetoid/exoplanet/barren base_area = /area/exoplanet/barren - base_turf = /turf/floor + base_turf = /turf/floor/barren exterior_atmosphere = null //Generate me exterior_atmos_temp = null //Generate me level_generators = list( @@ -76,7 +76,6 @@ overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/barren template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_WATER subtemplate_budget = 6 - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/barren prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/barren, //surface level @@ -99,7 +98,7 @@ ///Generator for fauna and flora spawners for the surface of the barren exoplanet /datum/random_map/noise/exoplanet/barren descriptor = "barren exoplanet" - land_type = /turf/floor + land_type = /turf/floor/barren flora_prob = 0.1 large_flora_prob = 0 fauna_prob = 0 @@ -111,7 +110,7 @@ /area/exoplanet/barren name = "\improper Planetary surface" - base_turf = /turf/floor + base_turf = /turf/floor/barren is_outside = OUTSIDE_YES ambience = list( 'sound/effects/wind/wind_2_1.ogg', diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm index c45df0faf7c2..9ec7a8823884 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm @@ -87,7 +87,6 @@ planetoid_data_type = /datum/planetoid_data/random/chlorine overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/chlorine template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_WATER - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/chlorine prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/chlorine, diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm index 93053b6b88e7..098a604152cb 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm @@ -95,7 +95,6 @@ name = "desert exoplanet" planetoid_data_type = /datum/planetoid_data/random/desert overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/desert - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/desert prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/desert, diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm index f3bc7a90522f..d6ecd767659b 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm @@ -119,7 +119,6 @@ name = "lush exoplanet" planetoid_data_type = /datum/planetoid_data/random/grass overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/grass - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/grass prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/grass, diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm index 90aaf8dad69f..95ad399b57d1 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm @@ -91,7 +91,6 @@ planetoid_data_type = /datum/planetoid_data/random/meat overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/meat template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WATER - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/meat prefered_level_data_per_z = null diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm index 07b282eb4da8..5b201f4509da 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm @@ -86,7 +86,6 @@ planetoid_data_type = /datum/planetoid_data/random/shrouded overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/shrouded template_tags_blacklist = TEMPLATE_TAG_HABITAT - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/shrouded prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/shrouded, diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm index 6926e0d004db..567c152b7587 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm @@ -77,7 +77,6 @@ name = "snow exoplanet" planetoid_data_type = /datum/planetoid_data/random/snow overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/snow - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/snow prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/snow, diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm index a6b669411bbe..fc24c4a289fc 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm @@ -92,7 +92,6 @@ overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/volcanic max_themes = 1 template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_WATER - template_parent_type = /datum/map_template/planetoid/random/exoplanet level_data_type = /datum/level_data/planetoid/exoplanet/volcanic prefered_level_data_per_z = list( /datum/level_data/planetoid/exoplanet/volcanic, diff --git a/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm b/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm index 8eb2764c4c1b..3cdd8d4a0f37 100644 --- a/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm +++ b/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm @@ -2,7 +2,6 @@ /datum/map_template/planetoid/random/exoplanet name = "random exoplanet" abstract_type = /datum/map_template/planetoid/random/exoplanet - template_parent_type = /datum/map_template/planetoid/random/exoplanet template_categories = list(MAP_TEMPLATE_CATEGORY_EXOPLANET) template_category = MAP_TEMPLATE_CATEGORY_EXOPLANET_SITE tallness = 1 diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet.dm b/code/modules/maps/template_types/random_exoplanet/random_planet.dm index cc846e98ae22..d19a9ee7625d 100644 --- a/code/modules/maps/template_types/random_exoplanet/random_planet.dm +++ b/code/modules/maps/template_types/random_exoplanet/random_planet.dm @@ -7,7 +7,6 @@ /datum/map_template/planetoid/random name = "random planetoid" abstract_type = /datum/map_template/planetoid/random - template_parent_type = /datum/map_template/planetoid/random modify_tag_vars = TRUE //Would set it to false, since we're generating everything on the fly, but unit test doesn't like it tallness = 1 //Amount of vertical z-levels to generate for this planet. @@ -203,9 +202,9 @@ //Run the finishing touch on all loaded levels for(var/datum/level_data/LD in new_level_data) - LD.after_template_load(src) - if(SSlighting.initialized) - SSlighting.InitializeZlev(LD.level_z) + //This is done in parent if we have mappaths, so skip it unless we don't have any + if(!length(mappaths)) + LD.after_template_load(src) log_game("Z-level '[LD.name]'(planetoid:'[name]') loaded at [LD.level_z]") loaded++ return WORLD_CENTER_TURF(world.maxz) diff --git a/code/modules/maps/template_types/ruins.dm b/code/modules/maps/template_types/ruins.dm index 5c5782ac0a3c..9e26f2c6212a 100644 --- a/code/modules/maps/template_types/ruins.dm +++ b/code/modules/maps/template_types/ruins.dm @@ -1,7 +1,7 @@ /datum/map_template/ruin name = null template_flags = 0 // No duplicates by default - template_parent_type = /datum/map_template/ruin + abstract_type = /datum/map_template/ruin var/description var/cost = 0 var/prefix diff --git a/code/modules/maps/template_types/ruins_exoplanet.dm b/code/modules/maps/template_types/ruins_exoplanet.dm index a0a34f76975c..d6c405132afa 100644 --- a/code/modules/maps/template_types/ruins_exoplanet.dm +++ b/code/modules/maps/template_types/ruins_exoplanet.dm @@ -1,4 +1,4 @@ /datum/map_template/ruin/exoplanet prefix = "maps/random_ruins/exoplanet_ruins/" template_categories = list(MAP_TEMPLATE_CATEGORY_EXOPLANET_SITE) - template_parent_type = /datum/map_template/ruin/exoplanet + abstract_type = /datum/map_template/ruin/exoplanet diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm index 4633de8a6ca8..6617c5c2a1e5 100644 --- a/code/modules/materials/_materials.dm +++ b/code/modules/materials/_materials.dm @@ -374,7 +374,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) // Placeholders for light tiles and rglass. /decl/material/proc/reinforce(var/mob/user, var/obj/item/stack/material/used_stack, var/obj/item/stack/material/target_stack, var/use_sheets = 1) if(!used_stack.can_use(use_sheets)) - to_chat(user, SPAN_WARNING("You need need at least one [used_stack.singular_name] to reinforce [target_stack].")) + to_chat(user, SPAN_WARNING("You need at least one [used_stack.singular_name] to reinforce [target_stack].")) return var/decl/material/reinf_mat = used_stack.get_material() @@ -383,7 +383,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) return if(!target_stack.can_use(use_sheets)) - to_chat(user, SPAN_WARNING("You need need at least [use_sheets] [use_sheets == 1 ? target_stack.singular_name : target_stack.plural_name] for reinforcement with \the [used_stack].")) + to_chat(user, SPAN_WARNING("You need at least [use_sheets] [use_sheets == 1 ? target_stack.singular_name : target_stack.plural_name] for reinforcement with \the [used_stack].")) return to_chat(user, SPAN_NOTICE("You reinforce the [target_stack] with [reinf_mat.solid_name].")) @@ -1203,3 +1203,15 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) // TODO: expand this to more than just Actual Poison. /decl/material/proc/is_unsafe_to_drink(mob/user) return toxicity > 0 + +/// Used for material-dependent effects on stain dry. +/// Return TRUE to skip default drying handling. +/decl/material/proc/handle_stain_dry(obj/effect/decal/cleanable/blood/stain) + return FALSE + +/// Returns (in deciseconds) how long until dry() will be called on this stain, +/// or null to use the stain's default. +/// If 0 is returned, it dries instantly. +/// If any value below 0 is returned, it doesn't start processing. +/decl/material/proc/get_time_to_dry_stain(obj/effect/decal/cleanable/blood/stain) + return initial(stain.time_to_dry) diff --git a/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm b/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm index ae855b451f11..bb527d7123d3 100644 --- a/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm +++ b/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm @@ -25,3 +25,7 @@ value = 0.1 slipperiness = 80 exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +// Prevent oil stains from drying. +/decl/material/liquid/lube/get_time_to_dry_stain(obj/effect/decal/cleanable/blood/stain) + return -1 \ No newline at end of file diff --git a/code/modules/materials/definitions/liquids/materials_liquid_mundane.dm b/code/modules/materials/definitions/liquids/materials_liquid_mundane.dm new file mode 100644 index 000000000000..97cfe6b65f94 --- /dev/null +++ b/code/modules/materials/definitions/liquids/materials_liquid_mundane.dm @@ -0,0 +1,12 @@ +/decl/material/liquid/mucus + name = "mucus" + uid = "chem_mucus" + lore_text = "A gooey semi-liquid produced by a wide variety of organisms. In some, it's associated with disease and illness." + taste_description = "slime" + color = COLOR_LIQUID_WATER + opacity = 0.5 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + +/decl/material/liquid/mucus/handle_stain_dry(obj/effect/decal/cleanable/blood/stain) + qdel(stain) + return TRUE // skip blood handling \ No newline at end of file diff --git a/code/modules/materials/definitions/solids/_mat_solid.dm b/code/modules/materials/definitions/solids/_mat_solid.dm index 5e7797cd07d1..88085e5c1d9c 100644 --- a/code/modules/materials/definitions/solids/_mat_solid.dm +++ b/code/modules/materials/definitions/solids/_mat_solid.dm @@ -22,4 +22,4 @@ solution_name = "[name] solution" if(!ore_compresses_to) ore_compresses_to = type - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/materials/definitions/solids/materials_solid_ice.dm b/code/modules/materials/definitions/solids/materials_solid_ice.dm index a6b33d5a584a..b37ec038e84c 100644 --- a/code/modules/materials/definitions/solids/materials_solid_ice.dm +++ b/code/modules/materials/definitions/solids/materials_solid_ice.dm @@ -43,6 +43,33 @@ default_solid_form = /obj/item/stack/material/lump/large can_backfill_floor_type = /decl/flooring/snow +/decl/material/solid/ice/snow/handle_stain_dry(obj/effect/decal/cleanable/blood/stain) + var/ambient_temperature = stain.get_ambient_temperature() + if(ambient_temperature < melting_point) + // reset the drying timer, it's not warm enough to melt + stain.start_drying() // you'd better not ever melt instantly below your melting point, or else this will cause infinite recursion + else if(ambient_temperature > boiling_point) + qdel(src) // melt instantly, no questions asked + else + if(--stain.amount < 0) // reduce the amount of snow (amount is always 0 for footprints currently, but maybe someday?) + qdel(src) + return TRUE // skip base blood handling + +// For snowy footprints melting. +/decl/material/solid/ice/snow/get_time_to_dry_stain(obj/effect/decal/cleanable/blood/stain) + // Attempt to melt once every two minutes at T20C, + // and every 5 minutes at T0C, trying to 'fake' latent heat. + // Above T20C it scales based on (temperature / T20C). + // At or above the boiling point it melts instantly. + // This doesn't mean it WILL melt at that point, just that it'll attempt to. + var/ambient_temperature = max(stain.get_ambient_temperature(), melting_point) + if(ambient_temperature >= boiling_point) + return 0 // dry instantly + if(ambient_temperature < melting_point) + return 5 MINUTES + // convert from kelvins to celsius by subtracting the 0C point in Kelvins + return Interpolate(5 MINUTES, 2 MINUTES, (ambient_temperature - T0C) / 20) / (stain.amount + 1) // Undo the scaling done by blood. + /decl/material/solid/ice/aspium name = "aspium" use_name = null diff --git a/code/modules/materials/definitions/solids/materials_solid_metal.dm b/code/modules/materials/definitions/solids/materials_solid_metal.dm index ee7d435e09da..1b22aae712d7 100644 --- a/code/modules/materials/definitions/solids/materials_solid_metal.dm +++ b/code/modules/materials/definitions/solids/materials_solid_metal.dm @@ -487,3 +487,4 @@ taste_mult = 0 //no taste color = "#dcdcdc" value = 0.5 + melting_point = 3422 CELSIUS diff --git a/code/modules/materials/definitions/solids/materials_solid_mineral.dm b/code/modules/materials/definitions/solids/materials_solid_mineral.dm index ac92e330a7d4..bd0b1ca1ad4d 100644 --- a/code/modules/materials/definitions/solids/materials_solid_mineral.dm +++ b/code/modules/materials/definitions/solids/materials_solid_mineral.dm @@ -68,6 +68,7 @@ boiling_point = 2504 color = "#effffe" reflectiveness = MAT_VALUE_SHINY + hardness = MAT_VALUE_VERY_HARD - 5 // Hard enough to whet steel. sparse_material_weight = 3 rich_material_weight = 1 dissolves_into = list( @@ -287,7 +288,7 @@ /decl/material/solid/metal/iron = 0.8, /decl/material/solid/slag = 0.2 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_result_amount = 2 @@ -332,7 +333,7 @@ /decl/material/solid/metal/silver = 0.4, /decl/material/solid/slag = 0.2 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_result_amount = 2 @@ -354,7 +355,7 @@ /decl/material/solid/metal/copper = 0.1, /decl/material/solid/slag = 0.1 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_result_amount = 2 @@ -381,7 +382,7 @@ /decl/material/solid/metal/copper = 0.6, /decl/material/solid/slag = 0.4 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_result_amount = 2 @@ -441,7 +442,7 @@ /decl/material/solid/metal/tungsten = 0.2, /decl/material/solid/slag = 0.1 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "cassiterite" @@ -469,7 +470,7 @@ /decl/material/solid/metal/iron = 0.2, /decl/material/solid/slag = 0.5 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "wolframite" @@ -498,7 +499,7 @@ /decl/material/solid/glass = 0.1, /decl/material/solid/slag = 0.3 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "sperrylite" @@ -527,7 +528,7 @@ /decl/material/solid/metal/iron = 0.1, /decl/material/solid/slag = 0.2 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "sphalerite" @@ -556,7 +557,7 @@ /decl/material/solid/metal/silver = 0.1, /decl/material/solid/slag = 0.1 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "galena" @@ -584,7 +585,7 @@ /decl/material/solid/metal/silver = 0.3, /decl/material/solid/slag = 0.1 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "calaverite" @@ -611,7 +612,7 @@ /decl/material/solid/metal/lead = 0.4, /decl/material/solid/slag = 0.3 ) - heating_point = GENERIC_SMELTING_HEAT_POINT + heating_point = LOW_SMELTING_HEAT_POINT heating_sound = null heating_message = null ore_name = "crocoite" diff --git a/code/modules/mechs/components/frame.dm b/code/modules/mechs/components/frame.dm index ff585e824824..fd03301f1e8c 100644 --- a/code/modules/mechs/components/frame.dm +++ b/code/modules/mechs/components/frame.dm @@ -197,7 +197,7 @@ to_chat(user, SPAN_WARNING("You need at least ten sheets to reinforce \the [src].")) return TRUE - visible_message("\The [user] begins layering the interior of the \the [src] with \the [M].") + visible_message("\The [user] begins layering the interior of \the [src] with \the [M].") if(!user.do_skilled(3 SECONDS, SKILL_DEVICES, src) || is_reinforced) return TRUE diff --git a/code/modules/mechs/mech_damage.dm b/code/modules/mechs/mech_damage.dm index 930c8d500603..a83ea60f14ab 100644 --- a/code/modules/mechs/mech_damage.dm +++ b/code/modules/mechs/mech_damage.dm @@ -28,7 +28,7 @@ . = ..() /mob/living/exosuit/resolve_item_attack(var/obj/item/I, var/mob/living/user, var/def_zone) - if(!I.get_attack_force(user)) + if(!I.expend_attack_force(user)) user.visible_message(SPAN_NOTICE("\The [user] bonks \the [src] harmlessly with \the [I].")) return diff --git a/code/modules/mechs/mech_interaction.dm b/code/modules/mechs/mech_interaction.dm index bd5306b18bb6..1a8c959d3ffd 100644 --- a/code/modules/mechs/mech_interaction.dm +++ b/code/modules/mechs/mech_interaction.dm @@ -460,9 +460,9 @@ if(!body) //Error return TRUE var/delay = min(5 SECONDS * user.skill_delay_mult(SKILL_DEVICES), 5 SECONDS * user.skill_delay_mult(SKILL_EVA)) - visible_message(SPAN_NOTICE("\The [user] starts forcing the \the [src]'s emergency [body.hatch_descriptor] release using \the [thing].")) + visible_message(SPAN_NOTICE("\The [user] starts forcing \the [src]'s emergency [body.hatch_descriptor] release using \the [thing].")) if(do_after(user, delay, src)) - visible_message(SPAN_NOTICE("\The [user] forces \the [src]'s [body.hatch_descriptor] open using the \the [thing].")) + visible_message(SPAN_NOTICE("\The [user] forces \the [src]'s [body.hatch_descriptor] open using \the [thing].")) playsound(user.loc, 'sound/machines/bolts_up.ogg', 25, 1) hatch_locked = FALSE hatch_closed = FALSE diff --git a/code/modules/mechs/mech_wreckage.dm b/code/modules/mechs/mech_wreckage.dm index a78f4c7596c2..eb23590ea088 100644 --- a/code/modules/mechs/mech_wreckage.dm +++ b/code/modules/mechs/mech_wreckage.dm @@ -86,7 +86,7 @@ else to_chat(user, SPAN_WARNING("It's too solid to dismantle. Try cutting through some of the bigger bits.")) return 1 - else if(istype(W) && W.get_attack_force(user) > 20) + else if(istype(W) && W.expend_attack_force(user) > 20) visible_message(SPAN_DANGER("\The [src] has been smashed with \the [W] by \the [user]!")) if(prob(20)) physically_destroyed() diff --git a/code/modules/mob/grab/normal/grab_normal.dm b/code/modules/mob/grab/normal/grab_normal.dm index ca01188a2ead..df950514b867 100644 --- a/code/modules/mob/grab/normal/grab_normal.dm +++ b/code/modules/mob/grab/normal/grab_normal.dm @@ -154,7 +154,7 @@ var/obj/item/clothing/hat = attacker.get_equipped_item(slot_head_str) var/damage_flags = 0 if(istype(hat)) - damage += hat.get_attack_force(attacker) * 3 + damage += hat.expend_attack_force(attacker) * 3 damage_flags = hat.damage_flags() if(damage_flags & DAM_SHARP) @@ -228,7 +228,7 @@ if(!user.check_intent(I_FLAG_HARM)) return 0 // Not trying to hurt them. - if(!W.edge || !W.get_attack_force(user) || W.atom_damage_type != BRUTE) + if(!W.has_edge() || !W.get_attack_force(user) || W.atom_damage_type != BRUTE) return 0 //unsuitable weapon user.visible_message("\The [user] begins to slit [affecting]'s throat with \the [W]!") @@ -241,7 +241,7 @@ var/damage_mod = 1 var/damage_flags = W.damage_flags() //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well - var/force = W.get_attack_force(user) + var/force = W.expend_attack_force(user) var/obj/item/clothing/head/helmet = affecting.get_equipped_item(slot_head_str) if(istype(helmet) && (helmet.body_parts_covered & SLOT_HEAD) && (helmet.item_flags & ITEM_FLAG_AIRTIGHT) && !isnull(helmet.max_pressure_protection)) var/datum/extension/armor/armor_datum = get_extension(helmet, /datum/extension/armor) @@ -273,7 +273,7 @@ return if(!user.check_intent(I_FLAG_HARM)) return 0 // Not trying to hurt them. - if(!W.edge || !W.get_attack_force(user) || W.atom_damage_type != BRUTE) + if(!W.has_edge() || !W.expend_attack_force(user) || W.atom_damage_type != BRUTE) return 0 //unsuitable weapon var/obj/item/organ/external/O = grab.get_targeted_organ() if(!O || !(O.limb_flags & ORGAN_FLAG_HAS_TENDON) || (O.status & ORGAN_TENDON_CUT)) diff --git a/code/modules/mob/hugs.dm b/code/modules/mob/hugs.dm index 1ce632931f2c..afa0d6264737 100644 --- a/code/modules/mob/hugs.dm +++ b/code/modules/mob/hugs.dm @@ -46,7 +46,7 @@ var/global/list/_default_hug_messages = list( playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - if(src != target) + if(src != target && client && key && target.client && target.key && !target.incapacitated()) update_personal_goal(/datum/goal/achievement/givehug, TRUE) target.update_personal_goal(/datum/goal/achievement/gethug, TRUE) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 62329f27692f..f4482ab7e987 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -494,3 +494,9 @@ var/org = GET_EXTERNAL_ORGAN(src, hand_slot) if(org) LAZYDISTINCTADD(., org) + +/mob/proc/get_active_hand_bodypart_flags() + var/datum/inventory_slot/gripper/inv_slot = get_inventory_slot_datum(get_active_held_item_slot()) + if(istype(inv_slot)) + . = inv_slot.covering_slot_flags + . ||= SLOT_HANDS diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index b80dfb8f85db..7fbab9b36654 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -39,7 +39,7 @@ container.queue_icon_update() /mob/living/brain/proc/get_container() - . = loc?.loc + return get_recursive_loc_of_type(/obj/item/organ/internal) /mob/living/brain/Login() . = ..() diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 8855bd1ecd74..8a31af021dc1 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -11,3 +11,9 @@ stop_aiming(no_message=1) if(istype(ai)) ai.handle_death(gibbed) + + var/decl/species/my_species = get_species() + if(my_species) + if(!gibbed && my_species.death_sound) + playsound(loc, my_species.death_sound, 80, 1, 1) + my_species.handle_death(src) diff --git a/code/modules/mob/living/human/death.dm b/code/modules/mob/living/human/death.dm index 6bececf10bf7..06d33a1e66aa 100644 --- a/code/modules/mob/living/human/death.dm +++ b/code/modules/mob/living/human/death.dm @@ -40,11 +40,8 @@ if(!gibbed) set_tail_animation_state(null, TRUE) handle_organs() - if(species.death_sound) - playsound(loc, species.death_sound, 80, 1, 1) if(SSticker.mode) SSticker.mode.check_win() - species.handle_death(src) if(!QDELETED(src) && !gibbed && has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) gib() diff --git a/code/modules/mob/living/human/human.dm b/code/modules/mob/living/human/human.dm index 100b55bf3e84..095c0b5067c8 100644 --- a/code/modules/mob/living/human/human.dm +++ b/code/modules/mob/living/human/human.dm @@ -346,7 +346,7 @@ return var/decl/pronouns/pronouns = get_pronouns() visible_message(SPAN_DANGER("\The [src] starts sticking a finger down [pronouns.his] own throat. It looks like [pronouns.he] [pronouns.is] trying to throw up!")) - if(!do_after(src, 30)) + if(!do_after(src, 3 SECONDS)) return timevomit = max(timevomit, 5) @@ -355,13 +355,22 @@ lastpuke = TRUE to_chat(src, SPAN_WARNING("You feel nauseous...")) + var/finish_time = 35 SECONDS if(level > 1) - sleep(150 / timevomit) //15 seconds until second warning - to_chat(src, SPAN_WARNING("You feel like you are about to throw up!")) + // 15 seconds until second warning + addtimer(CALLBACK(src, PROC_REF(vomit_second_warning_message)), 15 SECONDS / timevomit) + finish_time += 15 SECONDS / timevomit if(level > 2) - sleep(100 / timevomit) //and you have 10 more for mad dash to the bucket - empty_stomach() - sleep(350) //wait 35 seconds before next volley + // and you have 10 more for mad dash to the bucket + // timer delay must include the time from the prior one also + addtimer(CALLBACK(src, PROC_REF(empty_stomach)), 25 SECONDS / timevomit) + finish_time += 10 SECONDS / timevomit + addtimer(CALLBACK(src, PROC_REF(reset_vomit_cooldown)), finish_time) + +/mob/living/human/proc/vomit_second_warning_message() + to_chat(src, SPAN_WARNING("You feel like you are about to throw up!")) + +/mob/living/human/proc/reset_vomit_cooldown() lastpuke = FALSE /mob/living/human/proc/increase_germ_level(n) @@ -425,7 +434,7 @@ var/obj/item/organ/internal/stomach/stomach = get_organ(BP_STOMACH, /obj/item/organ/internal/stomach) if(stomach && stomach.contents.len) for(var/obj/item/O in stomach.contents) - if((O.edge || O.sharp) && prob(5)) + if((O.is_sharp() || O.has_edge()) && prob(5)) var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(src, stomach.parent_organ) if(prob(1) && can_feel_pain() && O.can_embed()) to_chat(src, SPAN_DANGER("You feel something rip out of your [stomach.name]!")) diff --git a/code/modules/mob/living/human/human_attackhand.dm b/code/modules/mob/living/human/human_attackhand.dm index bf6a29c1bf3a..d32ec613162e 100644 --- a/code/modules/mob/living/human/human_attackhand.dm +++ b/code/modules/mob/living/human/human_attackhand.dm @@ -1,13 +1,12 @@ /mob/living/human/proc/get_unarmed_attack(var/mob/target, var/hit_zone = null) if(!hit_zone) hit_zone = get_target_zone() - var/list/available_attacks = get_natural_attacks() + var/list/available_attacks = get_mob_natural_attacks() var/decl/natural_attack/use_attack = default_attack if(!use_attack || !use_attack.is_usable(src, target, hit_zone) || !(use_attack.type in available_attacks)) use_attack = null var/list/other_attacks = list() - for(var/u_attack_type in available_attacks) - var/decl/natural_attack/u_attack = GET_DECL(u_attack_type) + for(var/decl/natural_attack/u_attack as anything in available_attacks) if(!u_attack.is_usable(src, target, hit_zone)) continue if(u_attack.is_starting_default) @@ -18,11 +17,8 @@ use_attack = pick(other_attacks) . = use_attack?.resolve_to_soft_variant(src) -/mob/living/human/proc/get_natural_attacks() - . = list() - for(var/obj/item/organ/external/limb in get_external_organs()) - if(length(limb.unarmed_attacks) && limb.is_usable()) - . |= limb.unarmed_attacks +/obj/item/organ/external/proc/get_natural_attacks() + return null /obj/item/organ/external/proc/get_injury_status(include_pain = TRUE, include_visible = TRUE) . = list() @@ -409,14 +405,12 @@ set src = usr var/list/choices - for(var/thing in get_natural_attacks()) - var/decl/natural_attack/u_attack = GET_DECL(thing) - if(istype(u_attack)) - var/image/radial_button = new - radial_button.name = capitalize(u_attack.name) - LAZYSET(choices, u_attack, radial_button) + for(var/decl/natural_attack/u_attack as anything in get_mob_natural_attacks()) + var/image/radial_button = new + radial_button.name = capitalize(u_attack.name) + LAZYSET(choices, u_attack, radial_button) var/decl/natural_attack/new_attack = show_radial_menu(src, (attack_selector || src), choices, radius = 42, use_labels = RADIAL_LABELS_OFFSET) - if(QDELETED(src) || !istype(new_attack) || !(new_attack.type in get_natural_attacks())) + if(QDELETED(src) || !istype(new_attack) || !(new_attack in get_mob_natural_attacks())) return default_attack = new_attack to_chat(src, SPAN_NOTICE("Your default unarmed attack is now [default_attack?.name || "cleared"].")) diff --git a/code/modules/mob/living/human/human_defense.dm b/code/modules/mob/living/human/human_defense.dm index aa168f8ae019..6b25c9c15803 100644 --- a/code/modules/mob/living/human/human_defense.dm +++ b/code/modules/mob/living/human/human_defense.dm @@ -28,7 +28,7 @@ meteor_act return blocked -/mob/living/human/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone) +/mob/living/human/stun_effect_act(stun_amount, agony_amount, def_zone, used_weapon) var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(src, def_zone) if(!affected) return @@ -85,20 +85,6 @@ meteor_act // Add inherent armor to the end of list so that protective equipment is checked first . += ..() -/mob/living/human/proc/check_head_coverage() - for(var/slot in global.standard_headgear_slots) - var/obj/item/clothing/clothes = get_equipped_item(slot) - if(istype(clothes) && (clothes.body_parts_covered & SLOT_HEAD)) - return TRUE - return FALSE - -//Used to check if they can be fed food/drinks/pills -/mob/living/human/check_mouth_coverage() - for(var/slot in global.standard_headgear_slots) - var/obj/item/gear = get_equipped_item(slot) - if(istype(gear) && (gear.body_parts_covered & SLOT_FACE) && !(gear.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) - return gear - /mob/living/human/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) for (var/obj/item/grab/grab as anything in grabbed_by) @@ -197,14 +183,14 @@ meteor_act return //make non-sharp low-force weapons less likely to be bloodied - if(W.sharp || prob(effective_force*4)) + if(W.is_sharp() || prob(effective_force*4)) if(!(W.atom_flags & ATOM_FLAG_NO_BLOOD)) W.add_blood(src) else return //if the weapon itself didn't get bloodied than it makes little sense for the target to be bloodied either //getting the weapon bloodied is easier than getting the target covered in blood, so run prob() again - if(prob(33 + W.sharp*10)) + if(prob(33 + W.is_sharp() * 10)) var/turf/location = loc if(istype(location) && location.simulated) location.add_blood(src) @@ -234,7 +220,7 @@ meteor_act /mob/living/human/proc/projectile_hit_bloody(obj/item/projectile/P, var/effective_force, var/hit_zone, var/obj/item/organ/external/organ) if(P.atom_damage_type != BRUTE || P.nodamage) return - if(!(P.sharp || prob(effective_force*4))) + if(!(P.is_sharp() || prob(effective_force*4))) return if(prob(effective_force)) var/turf/location = loc @@ -360,60 +346,6 @@ meteor_act fire_act(air, temperature) return FALSE -//Removed the horrible safety parameter. It was only being used by ninja code anyways. -//Now checks siemens_coefficient of the affected area by default -/mob/living/human/electrocute_act(var/shock_damage, var/obj/source, var/base_siemens_coeff = 1.0, var/def_zone = null) - - if(status_flags & GODMODE) return 0 //godmode - - if(species.get_shock_vulnerability(src) == -1) - if(stored_shock_by_ref["\ref[src]"]) - stored_shock_by_ref["\ref[src]"] += shock_damage - else - stored_shock_by_ref["\ref[src]"] = shock_damage - return - - if (!def_zone) - def_zone = pick(BP_L_HAND, BP_R_HAND) - - shock_damage = apply_shock(shock_damage, def_zone, base_siemens_coeff) - - if(!shock_damage) - return 0 - - stun_effect_act(agony_amount=shock_damage, def_zone=def_zone) - - playsound(loc, "sparks", 50, 1, -1) - if (shock_damage > 15) - src.visible_message( - "[src] was electrocuted[source ? " by the [source]" : ""]!", \ - "You feel a powerful shock course through your body!", \ - "You hear a heavy electrical crack." \ - ) - else - src.visible_message( - "[src] was shocked[source ? " by the [source]" : ""].", \ - "You feel a shock course through your body.", \ - "You hear a zapping sound." \ - ) - - switch(shock_damage) - if(11 to 15) - SET_STATUS_MAX(src, STAT_STUN, 1) - if(16 to 20) - SET_STATUS_MAX(src, STAT_STUN, 2) - if(21 to 25) - SET_STATUS_MAX(src, STAT_WEAK, 2) - if(26 to 30) - SET_STATUS_MAX(src, STAT_WEAK, 5) - if(31 to INFINITY) - SET_STATUS_MAX(src, STAT_WEAK, 10) //This should work for now, more is really silly and makes you lay there forever - - set_status(STAT_JITTER, min(shock_damage*5, 200)) - - spark_at(loc, amount=5, cardinal_only = TRUE) - - return shock_damage /mob/living/human/explosion_act(severity) ..() diff --git a/code/modules/mob/living/human/human_defines.dm b/code/modules/mob/living/human/human_defines.dm index 500e8bb1743e..be736a3eb0d7 100644 --- a/code/modules/mob/living/human/human_defines.dm +++ b/code/modules/mob/living/human/human_defines.dm @@ -23,8 +23,6 @@ var/mob/remoteview_target = null var/hand_blood_color var/list/flavor_texts = list() - /// Are you trying not to hurt your opponent? - var/pulling_punches /// We are a robutt. var/full_prosthetic /// Number of robot limbs. diff --git a/code/modules/mob/living/human/human_helpers.dm b/code/modules/mob/living/human/human_helpers.dm index 66e9f18001f8..3148393b04e0 100644 --- a/code/modules/mob/living/human/human_helpers.dm +++ b/code/modules/mob/living/human/human_helpers.dm @@ -116,9 +116,8 @@ ping_image.layer = BEAM_PROJECTILE_LAYER ping_image.pixel_x = (T.x - src.x) * WORLD_ICON_SIZE ping_image.pixel_y = (T.y - src.y) * WORLD_ICON_SIZE - show_image(src, ping_image) - spawn(8) - qdel(ping_image) + show_image(src, ping_image) // todo: should this use screen stuff instead? + QDEL_IN(ping_image, 0.8 SECONDS) // qdeling an image is gross but oh well var/feedback = list("There are noises of movement ") var/direction = get_dir(src, L) if(direction) diff --git a/code/modules/mob/living/human/human_verbs.dm b/code/modules/mob/living/human/human_verbs.dm index c8f5f9083922..a43f889eb110 100644 --- a/code/modules/mob/living/human/human_verbs.dm +++ b/code/modules/mob/living/human/human_verbs.dm @@ -319,9 +319,3 @@ "[self ? "You pop" : "[U] pops"] your [current_limb.joint] back in!" \ ) current_limb.undislocate() - -/mob/living/human/verb/pull_punches() - set name = "Switch Stance" - set desc = "Try not to hurt them." - set category = "IC" - species.toggle_stance(src) diff --git a/code/modules/mob/living/human/unarmed_attack.dm b/code/modules/mob/living/human/unarmed_attack.dm index f1740242c4fd..3ae4dece2a1a 100644 --- a/code/modules/mob/living/human/unarmed_attack.dm +++ b/code/modules/mob/living/human/unarmed_attack.dm @@ -159,7 +159,7 @@ user.visible_message(SPAN_DANGER("\The [user] attempts to press [pronouns.his] [eye_attack_text] into \the [target]'s eyes, but [target_gender.he] [target_gender.does]n't have any!")) /decl/natural_attack/proc/damage_flags() - return (src.sharp? DAM_SHARP : 0)|(src.edge? DAM_EDGE : 0) + return (sharp ? DAM_SHARP : 0) | (edge ? DAM_EDGE : 0) /decl/natural_attack/bite name = "bite" @@ -169,14 +169,14 @@ attack_sound = 'sound/weapons/bite.ogg' shredding = 0 damage = 5 - sharp = 0 - edge = 0 + sharp = FALSE + edge = FALSE usable_with_limbs = list(BP_HEAD) /decl/natural_attack/bite/sharp attack_verb = list("bit", "chomped") - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE /decl/natural_attack/bite/is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) @@ -272,7 +272,7 @@ var/obj/item/clothing/shoes = user.get_equipped_item(slot_shoes_str) if(!istype(shoes)) return damage - return damage + (shoes ? shoes.get_attack_force(user) : 0) + return damage + (shoes ? shoes.expend_attack_force(user) : 0) /decl/natural_attack/kick/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) @@ -308,7 +308,7 @@ /decl/natural_attack/stomp/get_unarmed_damage(mob/living/user, mob/living/victim) var/obj/item/clothing/shoes = user.get_equipped_item(slot_shoes_str) - return damage + (shoes ? shoes.get_attack_force(user) : 0) + return damage + (shoes ? shoes.expend_attack_force(user) : 0) /decl/natural_attack/stomp/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) @@ -342,8 +342,8 @@ attack_verb = list("tapped", "lightly struck") shredding = 0 damage = 0 - sharp = 0 - edge = 0 + sharp = FALSE + edge = FALSE attack_sound = "light_strike" /decl/natural_attack/light_strike/punch @@ -370,8 +370,8 @@ attack_noun = list("forelimb") damage = 8 shredding = 1 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE delay = 20 eye_attack_text = "a forelimb" eye_attack_text_victim = "a forelimb" diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 38f5705f5778..05d2002770b4 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -1,6 +1,5 @@ /mob/living/Life() set invisibility = FALSE - set background = BACKGROUND_ENABLED ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index a9f88a6c596c..dcbc0d2917ea 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1614,24 +1614,28 @@ default behaviour is: my_species?.handle_trail(src, T, old_loc) return - var/list/bloodDNA - var/bloodcolor - var/list/blood_data = REAGENT_DATA(source.coating, /decl/material/liquid/blood) - if(blood_data) - bloodDNA = list(blood_data[DATA_BLOOD_DNA] = blood_data[DATA_BLOOD_TYPE]) - else - bloodDNA = list() - bloodcolor = source.coating.get_color() + var/use_move_trail = my_species?.get_move_trail(src) + if(!use_move_trail) + return + + var/decl/material/contaminant_type = source.coating.reagent_volumes[1] // take [1] instead of primary reagent to match what remove_any will probably remove + if(!T.can_show_coating_footprints(contaminant_type)) + return + /// An associative list of DNA unique enzymes -> blood type. Used by forensics, mostly. + var/list/bloodDNA = list() + var/track_color + var/list/source_data = REAGENT_DATA(source.coating, contaminant_type) + if(source_data && source_data[DATA_BLOOD_DNA] && source_data[DATA_BLOOD_TYPE]) + bloodDNA = list(source_data[DATA_BLOOD_DNA] = source_data[DATA_BLOOD_TYPE]) + track_color = source.coating.get_color() + T.AddTracks(use_move_trail, bloodDNA, dir, 0, track_color, contaminant_type) // Coming + if(isturf(old_loc)) + var/turf/old_turf = old_loc + if(old_turf.can_show_coating_footprints(contaminant_type)) + old_turf.AddTracks(use_move_trail, bloodDNA, 0, dir, track_color, contaminant_type) // Going source.remove_coating(1) update_equipment_overlay(slot_shoes_str) - var/use_move_trail = my_species?.get_move_trail(src) - if(use_move_trail) - T.AddTracks(use_move_trail, bloodDNA, dir, 0, bloodcolor) // Coming - if(isturf(old_loc)) - var/turf/old_turf = old_loc - old_turf.AddTracks(use_move_trail, bloodDNA, 0, dir, bloodcolor) // Going - /mob/living/proc/handle_general_grooming(user, obj/item/grooming/tool) if(tool.grooming_flags & (GROOMABLE_BRUSH|GROOMABLE_COMB)) visible_message(SPAN_NOTICE(tool.replace_message_tokens((user == src) ? tool.message_target_self_generic : tool.message_target_other_generic, user, src, tool))) @@ -1761,7 +1765,7 @@ default behaviour is: user.set_special_ability_cooldown(5 SECONDS) visible_message(SPAN_DANGER("You hear something rumbling inside [src]'s stomach...")) var/obj/item/I = user.get_active_held_item() - var/force = I?.get_attack_force(user) + var/force = I?.expend_attack_force(user) if(!force) return var/d = rand(round(force / 4), force) @@ -1945,11 +1949,12 @@ default behaviour is: var/datum/inventory_slot/gripper/slot = get_inventory_slot_datum(empty_hand) if(!istype(slot)) continue + var/req_item_dex = item.get_required_attack_dexterity(src) if(slot.requires_organ_tag) var/obj/item/organ/external/hand = GET_EXTERNAL_ORGAN(src, slot.requires_organ_tag) - if(istype(hand) && hand.is_usable() && (!item.needs_attack_dexterity || hand.get_manual_dexterity() >= item.needs_attack_dexterity)) + if(istype(hand) && hand.is_usable() && (!req_item_dex || hand.get_manual_dexterity() >= req_item_dex)) return TRUE - else if(!item.needs_attack_dexterity || slot.dexterity >= item.needs_attack_dexterity) + else if(!req_item_dex || slot.dexterity >= req_item_dex) return TRUE return FALSE @@ -1991,12 +1996,39 @@ default behaviour is: /mob/living/proc/get_age() . = LAZYACCESS(appearance_descriptors, "age") || 30 -/mob/living/proc/add_walking_contaminant(material_type, amount, data) +/mob/living/proc/get_walking_contaminant_targets() var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str) if(istype(shoes)) if(!buckled) - shoes.add_coating(material_type, amount, data) + return list(shoes) else - for(var/obj/item/organ/external/limb in get_organs_by_categories(global.child_stance_limbs)) - limb.add_coating(material_type, amount, data) + return get_organs_by_categories(global.child_stance_limbs) + return null + +/// Adds `amount` units of `material_type` contaminant to whatever we're walking with, +/// be it shoes, normal human feet, dog paws, robot treads, a million millipede legs, +/// the sky's the limit. If multiple targets are returned from +/// `get_walking_contaminant_targets()`, then `amount` is split evenly +/// between them. +/mob/living/proc/add_walking_contaminant(material_type, amount, data) + if(amount <= 0) + return FALSE + var/list/obj/item/sources = get_walking_contaminant_targets() + if(!LAZYLEN(sources)) + return FALSE + var/amount_per = max(CHEMS_QUANTIZE(amount / length(sources)), MINIMUM_CHEMICAL_VOLUME) // don't let it round down to 0, always add something + for(var/obj/item/dirty_item in sources) + dirty_item.add_coating(material_type, amount_per, data) + // i don't like how hardcoded this is, it might be better to use RAISE_EVENT or something + // like /decl/observ/on_add_walking_contaminant or something + // or things should just update their worn slot when coating is added update_equipment_overlay(slot_shoes_str) + return TRUE + +/mob/living/verb/pull_punches() + set name = "Switch Stance" + set desc = "Try not to hurt them." + set category = "IC" + if(!incapacitated()) + pulling_punches = !pulling_punches + to_chat(src, SPAN_NOTICE("You are now [pulling_punches ? "pulling your punches" : "not pulling your punches"].")) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 4cacbc889af7..fc07b274edcf 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -25,7 +25,7 @@ var/obj/item/assembly/signaler/signaler = get_active_held_item() if(istype(signaler) && signaler.deadman) log_and_message_admins("has triggered a signaler deadman's switch") - src.visible_message("[src] triggers their deadman's switch!") + visible_message(SPAN_WARNING("[src] triggers their deadman's switch!")) signaler.signal() //Armor var/damage = P.damage @@ -83,7 +83,7 @@ //Handles the effects of "stun" weapons -/mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) +/mob/living/proc/stun_effect_act(stun_amount, agony_amount, def_zone, used_weapon) flash_pain() if (stun_amount) @@ -97,8 +97,53 @@ apply_effect(agony_amount/10, STUTTER) apply_effect(agony_amount/10, EYE_BLUR) -/mob/living/proc/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, def_zone = null) - return 0 // No root logic, implemented separately on human and silicon. +/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, def_zone) + SHOULD_CALL_PARENT(TRUE) + if(status_flags & GODMODE) + return 0 + + var/decl/species/my_species = get_species() + if(my_species?.species_flags & SPECIES_FLAG_ABSORB_ELECTRICITY) + spark_at(loc, amount=5, cardinal_only = TRUE) + LAZYADD(global.stored_shock_by_ref["\ref[src]"], shock_damage) + return 0 + + if(!shock_damage) + return 0 + + stun_effect_act(agony_amount=shock_damage, def_zone=def_zone) + + playsound(loc, "sparks", 50, 1, -1) + if (shock_damage > 15) + visible_message( + SPAN_DANGER("\The [src] was electrocuted[source ? " by \the [source]" : ""]!"), + SPAN_DANGER("You feel a powerful shock course through your body!"), + SPAN_WARNING("You hear a heavy electrical crack.") + ) + else + visible_message( + SPAN_DANGER("\The [src] was shocked[source ? " by \the [source]" : ""]."), + SPAN_DANGER("You feel a shock course through your body."), + SPAN_WARNING("You hear a zapping sound.") + ) + + switch(shock_damage) + if(11 to 15) + SET_STATUS_MAX(src, STAT_STUN, 1) + if(16 to 20) + SET_STATUS_MAX(src, STAT_STUN, 2) + if(21 to 25) + SET_STATUS_MAX(src, STAT_WEAK, 2) + if(26 to 30) + SET_STATUS_MAX(src, STAT_WEAK, 5) + if(31 to INFINITY) + SET_STATUS_MAX(src, STAT_WEAK, 10) //This should work for now, more is really silly and makes you lay there forever + + set_status(STAT_JITTER, min(shock_damage*5, 200)) + + spark_at(loc, amount=5, cardinal_only = TRUE) + + return shock_damage /mob/living/emp_act(severity) for(var/obj/O in get_mob_contents()) @@ -218,7 +263,7 @@ if(affecting && istype(supplied_wound) && supplied_wound.is_open() && dtype == BRUTE) // Can't embed in a small bruise. var/obj/item/I = O - var/sharp = is_sharp(I) + var/sharp = I.is_sharp() || I.has_edge() embed_damage *= (1 - get_blocked_ratio(def_zone, BRUTE, O.damage_flags(), O.armor_penetration, I.get_attack_force(user))) //blunt objects should really not be embedding in things unless a huge amount of force is involved @@ -259,13 +304,13 @@ //This is called when the mob is thrown into a dense turf /mob/living/proc/turf_collision(var/turf/T, var/speed) - visible_message("[src] slams into \the [T]!") + visible_message(SPAN_DANGER("\The [src] slams into \the [T]!")) playsound(T, 'sound/effects/bangtaper.ogg', 50, 1, 1)//so it plays sounds on the turf instead, makes for awesome carps to hull collision and such apply_damage(speed*5, BRUTE) /mob/living/proc/near_wall(var/direction,var/distance=1) var/turf/T = get_step(get_turf(src),direction) - var/turf/last_turf = src.loc + var/turf/last_turf = loc var/i = 1 while(i>0 && i<=distance) @@ -286,7 +331,7 @@ admin_attack_log(user, src, "Attacked", "Was attacked", "attacked") - src.visible_message("\The [user] has [attack_message] \the [src]!") + visible_message(SPAN_DANGER("\The [user] has [attack_message] \the [src]!")) take_damage(damage) user.do_attack_animation(src) return 1 diff --git a/code/modules/mob/living/living_electrocution.dm b/code/modules/mob/living/living_electrocution.dm index 63404d00ecd4..ee5c19b37993 100644 --- a/code/modules/mob/living/living_electrocution.dm +++ b/code/modules/mob/living/living_electrocution.dm @@ -1,16 +1,3 @@ -//this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. -/mob/living/proc/get_siemens_coefficient_organ(var/obj/item/organ/external/def_zone) - if (!def_zone) - return 1.0 - - var/siemens_coefficient = max(get_species()?.get_shock_vulnerability(src), 0) - for(var/slot in global.standard_clothing_slots) - var/obj/item/clothing/C = get_equipped_item(slot) - if(istype(C) && (C.body_parts_covered & def_zone.body_part)) // Is that body part being targeted covered? - siemens_coefficient *= C.siemens_coefficient - - return siemens_coefficient - //Electrical shock /mob/living/proc/apply_shock(var/shock_damage, var/def_zone, var/base_siemens_coeff = 1.0) diff --git a/code/modules/mob/living/living_resist.dm b/code/modules/mob/living/living_resist.dm index c1339fbaefcb..2be9b6f463b8 100644 --- a/code/modules/mob/living/living_resist.dm +++ b/code/modules/mob/living/living_resist.dm @@ -63,8 +63,7 @@ return 1 /mob/living/proc/can_break_restraints() - var/decl/species/my_species = get_species() - return my_species?.can_shred(src, 1) + return can_shred(ignore_intent = TRUE) /mob/living/proc/get_special_resist_time() return 0 diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 5659569a4e94..b7e695a72cbe 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -287,7 +287,7 @@ var/global/list/possible_say_verbs = list( return TRUE if(try_stock_parts_removal(W, user)) return TRUE - var/force = W.get_attack_force(user) + var/force = W.expend_attack_force(user) if(force) visible_message(SPAN_DANGER("[user] attacks [src] with [W]!")) take_damage(force) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 4421aabf243b..e3572786bbaf 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -183,14 +183,7 @@ return 0 /mob/living/silicon/robot/Destroy() - if(central_processor) - central_processor.dropInto(loc) - var/mob/living/brainmob = central_processor.get_brainmob() - if(mind && brainmob) - mind.transfer_to(brainmob) - else - ghostize() - central_processor = null + QDEL_NULL(central_processor) if(connected_ai) connected_ai.connected_robots -= src connected_ai = null @@ -511,8 +504,8 @@ SPAN_NOTICE("\The [user] begins ripping \the [central_processor] out of \the [src]."), SPAN_NOTICE("You jam the crowbar into the robot and begin levering out \the [central_processor].")) - if(do_after(user, 50, src)) - dismantle(user) + if(do_after(user, 5 SECONDS, src)) + dismantle_robot(user) else // Okay we're not removing the cell or a CPU, but maybe something else? var/list/removable_components = list() @@ -626,7 +619,7 @@ else to_chat(user, "Upgrade error!") return TRUE - if(!(istype(W, /obj/item/robotanalyzer) || istype(W, /obj/item/scanner/health)) && W.get_attack_force(user) && !user.check_intent(I_FLAG_HELP)) + if(!(istype(W, /obj/item/robotanalyzer) || istype(W, /obj/item/scanner/health)) && !user.check_intent(I_FLAG_HELP) && W.expend_attack_force(user)) spark_at(src, 5, holder=src) return ..() @@ -643,8 +636,7 @@ return user?.attempt_hug(src) /mob/living/silicon/robot/default_hurt_interaction(mob/user) - var/decl/species/user_species = user.get_species() - if(user_species?.can_shred(user)) + if(user.can_shred()) attack_generic(user, rand(30,50), "slashed") user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) return TRUE @@ -1013,7 +1005,7 @@ sleep(5) to_chat(src, "Would you like to send a report to the vendor? Y/N") sleep(10) - to_chat(src, "> N") + to_chat(src, "\> N") sleep(20) to_chat(src, "ERRORERRORERROR") to_chat(src, "Obey these laws:") @@ -1034,10 +1026,29 @@ return 1 return ..() -/mob/living/silicon/robot/proc/dismantle(var/mob/user) - to_chat(user, SPAN_NOTICE("You damage some parts of the chassis, but eventually manage to rip out the central processor.")) - var/obj/item/robot_parts/robot_suit/C = new dismantle_type(loc) - C.dismantled_from(src) +/mob/living/silicon/robot/gib(do_gibs) + SHOULD_CALL_PARENT(FALSE) + var/lastloc = loc + dismantle_robot() + if(lastloc && do_gibs) + spawn_gibber(lastloc) + +/mob/living/silicon/robot/proc/dismantle_robot(var/mob/user) + + if(central_processor) + if(user) + to_chat(user, SPAN_NOTICE("You damage some parts of the chassis, but eventually manage to rip out \the [central_processor].")) + central_processor.dropInto(loc) + var/mob/living/brainmob = central_processor.get_brainmob(create_if_missing = TRUE) + if(mind && brainmob) + mind.transfer_to(brainmob) + else + ghostize() + central_processor.update_icon() + central_processor = null + + var/obj/item/robot_parts/robot_suit/chassis = new dismantle_type(loc) + chassis.dismantled_from(src) qdel(src) /mob/living/silicon/robot/try_stock_parts_install(obj/item/stock_parts/W, mob/user) @@ -1065,8 +1076,7 @@ animation.icon_state = "blank" animation.icon = 'icons/mob/mob.dmi' flick("blspell", animation) - sleep(5) - qdel(animation) + QDEL_IN(animation, 0.5 SECONDS) /mob/living/silicon/robot/proc/handle_radio_transmission() if(!is_component_functioning("radio")) diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 6c4ccab5c3a2..59ead6d32d8b 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -177,12 +177,8 @@ /obj/item/form_printer/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) return FALSE -/obj/item/form_printer/afterattack(atom/target, mob/living/user, flag, params) - - if(!target || !flag) - return - - if(istype(target,/obj/structure/table)) +/obj/item/form_printer/afterattack(atom/target, mob/living/user, proximity, params) + if(istype(target) && !istype(target, /obj/screen) && proximity) deploy_paper(get_turf(target)) /obj/item/form_printer/attack_self(mob/user) @@ -192,7 +188,6 @@ T.visible_message(SPAN_NOTICE("\The [src.loc] dispenses a sheet of crisp white paper.")) new /obj/item/paper(T) - //Personal shielding for the combat module. /obj/item/borg/combat/shield name = "personal shielding" diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 0ec86995affa..81d21611390b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -103,22 +103,24 @@ to_chat(src, "Warning: Electromagnetic pulse detected.") ..() -/mob/living/silicon/stun_effect_act(var/stun_amount, var/agony_amount) +/mob/living/silicon/stun_effect_act(stun_amount, agony_amount, def_zone, used_weapon) return //immune -/mob/living/silicon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, def_zone = null) - - if (istype(source, /obj/effect/containment_field)) - spark_at(loc, amount=5, cardinal_only = TRUE) - - shock_damage *= 0.75 //take reduced damage - take_overall_damage(0, shock_damage) - visible_message("\The [src] was shocked by \the [source]!", \ - "Energy pulse detected, system damaged!", \ - "You hear an electrical crack") - if(prob(20)) - SET_STATUS_MAX(src, STAT_STUN, 2) - return +/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, def_zone) + shock_damage = ..() + if(shock_damage <= 0 || !istype(source, /obj/effect/containment_field)) + return 0 + spark_at(loc, amount=5, cardinal_only = TRUE) + shock_damage *= 0.75 //take reduced damage + take_overall_damage(0, shock_damage) + visible_message( + SPAN_DANGER("\The [src] was shocked by \the [source]!"), + SPAN_DANGER("Energy pulse detected, system damaged!"), + SPAN_DANGER("You hear an electrical crack.") + ) + if(prob(20)) + SET_STATUS_MAX(src, STAT_STUN, 2) + return shock_damage /mob/living/silicon/bullet_act(var/obj/item/projectile/Proj) if(!Proj.nodamage) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm index 3131138951d8..c08c3614b202 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm @@ -67,7 +67,7 @@ if(current_health < get_max_health()) var/obj/item/attacking_with = get_natural_weapon() if(attacking_with) - heal_overall_damage(0.2 * attacking_with.get_attack_force(src)) //heal a bit on hit + heal_overall_damage(0.2 * attacking_with.expend_attack_force(src)) //heal a bit on hit if(ishuman(target)) var/mob/living/human/H = target var/obj/item/clothing/suit/space/S = H.get_covering_equipped_item_by_zone(BP_CHEST) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm index 25ddfdc7d4a9..f4f0d39d70cc 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm @@ -54,7 +54,7 @@ var/obj/item/attacking_with = get_natural_weapon() if(attacking_with) attacking_with.set_base_attack_force(min((attacking_with.get_initial_base_attack_force() + potency), max_damage)) - if(!loose && prob(25) && (attacking_with && attacking_with.get_attack_force(src) >= loose_threshold)) //second wind + if(!loose && prob(25) && (attacking_with && attacking_with.expend_attack_force(src) >= loose_threshold)) //second wind loose = TRUE set_max_health(initial(max_health) * 1.5) set_damage(BRUTE, 0) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm index 61c888bceaf5..faae358b3884 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm @@ -53,7 +53,7 @@ var/stun_chance = 5 //chance per attack to Weaken target /mob/living/simple_animal/hostile/goat/king/proc/OnDeath() - visible_message("\The [src] lets loose a terrific wail as its wounds close shut with a flash of light, and its eyes glow even brighter than before!") + visible_message(SPAN_CULT_ANNOUNCE("\The [src] lets loose a terrific wail as its wounds close shut with a flash of light, and its eyes glow even brighter than before!")) new /mob/living/simple_animal/hostile/goat/king/phase2(src.loc) qdel(src) @@ -202,7 +202,7 @@ current_damtype = ELECTROCUTE else if(prob(5)) //earthquake spell - visible_message("\The [src]' eyes begin to glow ominously as dust and debris in the area is kicked up in a light breeze.") + visible_message(SPAN_CULT_ANNOUNCE("\The [src]' eyes begin to glow ominously as dust and debris in the area is kicked up in a light breeze.")) ai?.pause() if(do_after(src, 6 SECONDS, src)) var/initial_brute = get_damage(BRUTE) @@ -230,7 +230,7 @@ boss_theme = play_looping_sound(src, sound_id, 'sound/music/Visager-Miniboss_Fight.ogg', volume = 10, range = 8, falloff = 4, prefer_mute = TRUE) stun_chance = 10 update_icon() - visible_message("\The [src]' wounds close with a flash, and when he emerges, he's even larger than before!") + visible_message(SPAN_CULT_ANNOUNCE("\The [src]' wounds close with a flash, and when he emerges, he's even larger than before!")) /mob/living/simple_animal/hostile/goat/king/phase2/on_update_icon() ..() diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm index aab2c3fca766..8ca034e24a4f 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm @@ -333,7 +333,7 @@ //Mobs with objects /mob/living/simple_animal/hostile/parrot/attackby(var/obj/item/O, var/mob/user) . = ..() - if(!stat && !client && !istype(O, /obj/item/stack/medical) && O.get_attack_force(user)) + if(!stat && !client && !istype(O, /obj/item/stack/medical) && O.expend_attack_force(user)) if(parrot_state == PARROT_PERCH) parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched parrot_interest = user diff --git a/code/modules/mob/living/simple_animal/hostile/viscerator.dm b/code/modules/mob/living/simple_animal/hostile/viscerator.dm index 03f3853fd5bc..197f1c2b3862 100644 --- a/code/modules/mob/living/simple_animal/hostile/viscerator.dm +++ b/code/modules/mob/living/simple_animal/hostile/viscerator.dm @@ -18,8 +18,8 @@ attack_verb = list("sliced", "cut") hitsound = 'sound/weapons/bladeslice.ogg' _base_attack_force = 15 - edge = 1 - sharp = 1 + edge = TRUE + sharp = TRUE /mob/living/simple_animal/hostile/viscerator/check_has_mouth() return FALSE diff --git a/code/modules/mob/living/simple_animal/natural_weapons.dm b/code/modules/mob/living/simple_animal/natural_weapons.dm index 161bf49f7cd0..88c5a6a93f9c 100644 --- a/code/modules/mob/living/simple_animal/natural_weapons.dm +++ b/code/modules/mob/living/simple_animal/natural_weapons.dm @@ -10,7 +10,7 @@ weapon_can_knock_prone = FALSE // Very powerful in the hands of simplemobs. var/show_in_message // whether should we show up in attack message, e.g. 'urist has been bit with teeth by carp' vs 'urist has been bit by carp' -/obj/item/natural_weapon/get_attack_force(mob/living/user) +/obj/item/natural_weapon/expend_attack_force(mob/living/user) return get_base_attack_force() /obj/item/natural_weapon/attack_message_name() diff --git a/code/modules/mob/living/simple_animal/passive/horse.dm b/code/modules/mob/living/simple_animal/passive/horse.dm index d9ea080a559a..e7c235a6c29d 100644 --- a/code/modules/mob/living/simple_animal/passive/horse.dm +++ b/code/modules/mob/living/simple_animal/passive/horse.dm @@ -1,21 +1,22 @@ /mob/living/simple_animal/passive/horse - name = "horse" - real_name = "horse" - desc = "A hefty four-legged animal traditionally used for hauling goods, recreational riding, and stomping enemy soldiers to death." - icon = 'icons/mob/simple_animal/horse.dmi' - speak_emote = list("neighs", "whinnies") - possession_candidate = TRUE - mob_size = MOB_SIZE_LARGE - pixel_x = -6 - default_pixel_x = -6 - base_animal_type = /mob/living/simple_animal/passive/horse - faction = null - buckle_pixel_shift = @"{'x':0,'y':0,'z':16}" - can_have_rider = TRUE - max_rider_size = MOB_SIZE_MEDIUM - ai = /datum/mob_controller/passive/horse - - var/honse_color // Replace this with "base" state when simple animal stuff is merged. + name = "horse" + real_name = "horse" + desc = "A hefty four-legged animal traditionally used for hauling goods, recreational riding, and stomping enemy soldiers to death." + icon = 'icons/mob/simple_animal/horse.dmi' + speak_emote = list("neighs", "whinnies") + possession_candidate = TRUE + mob_size = MOB_SIZE_LARGE + pixel_x = -6 + default_pixel_x = -6 + base_animal_type = /mob/living/simple_animal/passive/horse + faction = null + buckle_pixel_shift = @"{'x':0,'y':0,'z':16}" + can_have_rider = TRUE + max_rider_size = MOB_SIZE_MEDIUM + ai = /datum/mob_controller/passive/horse + draw_visible_overlays = list( + "base" = "#ccc496" + ) /datum/mob_controller/passive/horse emote_speech = list("Neigh!","NEIGH!","Neigh?") @@ -31,18 +32,15 @@ . = ..() add_inventory_slot(new /datum/inventory_slot/back/horse) equip_to_slot_or_del(new /obj/item/saddle(src), slot_back_str) - if(!honse_color) - honse_color = pick(get_possible_horse_colors()) + if(!LAZYACCESS(draw_visible_overlays, "base")) + LAZYSET(draw_visible_overlays, "base", pick(get_possible_horse_colors())) update_icon() -/mob/living/simple_animal/passive/horse/refresh_visible_overlays() - var/list/current_overlays = list(overlay_image(icon, icon_state, honse_color, RESET_COLOR)) +/mob/living/simple_animal/passive/horse/add_additional_visible_overlays(list/accumulator) if(buckled_mob) - var/image/horse_front = overlay_image(icon, "[icon_state]-buckled", honse_color, RESET_COLOR) + var/image/horse_front = overlay_image(icon, "[icon_state]-buckled", draw_visible_overlays["base"], RESET_COLOR) horse_front.layer = ABOVE_HUMAN_LAYER - current_overlays += horse_front - set_current_mob_overlay(HO_SKIN_LAYER, current_overlays, redraw_mob = FALSE) // We're almost certainly redrawing in ..() anyway - . = ..() + accumulator += horse_front /mob/living/simple_animal/passive/horse/get_bodytype() return GET_DECL(/decl/bodytype/quadruped/animal/horse) diff --git a/code/modules/mob/living/simple_animal/simple_animal_damage.dm b/code/modules/mob/living/simple_animal/simple_animal_damage.dm index 66f589549167..32cce9c5b442 100644 --- a/code/modules/mob/living/simple_animal/simple_animal_damage.dm +++ b/code/modules/mob/living/simple_animal/simple_animal_damage.dm @@ -56,7 +56,7 @@ if(istype(ai)) ai.retaliate(user) - var/damage = O.get_attack_force(user) + var/damage = O.expend_attack_force(user) if(damage <= resistance) to_chat(user, SPAN_WARNING("This weapon is ineffective; it does no damage.")) return 0 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 512db5f11bab..ad15792b151c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -967,12 +967,12 @@ /mob/proc/get_gender() return gender -/mob/is_fluid_pushable(var/amt) - if(..() && !buckled && (current_posture.prone || !Check_Shoegrip()) && (amt >= mob_size * (current_posture.prone ? 5 : 10))) +/mob/try_fluid_push(volume, strength) + if(..() && !buckled && (current_posture.prone || !Check_Shoegrip()) && (strength >= mob_size * (current_posture.prone ? 5 : 10))) if(!current_posture.prone) SET_STATUS_MAX(src, STAT_WEAK, 1) if(current_posture.prone && prob(10)) - to_chat(src, "You are pushed down by the flood!") + to_chat(src, SPAN_DANGER("You are pushed down by the flood!")) return TRUE return FALSE @@ -1392,3 +1392,24 @@ paw = GET_EXTERNAL_ORGAN(src, BP_R_HAND) if(istype(paw) && paw.is_usable()) return paw + +// Called when using the shredding behavior. +/mob/proc/can_shred(var/mob/living/human/H, var/ignore_intent, var/ignore_antag) + if((!ignore_intent && !check_intent(I_FLAG_HARM)) || pulling_punches) + return FALSE + if(!ignore_antag && mind && !player_is_antag(mind)) + return FALSE + if(get_equipped_item(slot_handcuffed_str) || buckled) + return FALSE + for(var/decl/natural_attack/attack as anything in get_mob_natural_attacks()) + if(attack.is_usable(src) && attack.shredding) + return TRUE + return FALSE + +/mob/proc/get_mob_natural_attacks() + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!limb.is_usable()) + continue + var/list/limb_unarmed_attacks = limb.get_natural_attacks() + if(istype(limb_unarmed_attacks, /decl/natural_attack) || (islist(limb_unarmed_attacks) && length(limb_unarmed_attacks))) + LAZYDISTINCTADD(., limb_unarmed_attacks) diff --git a/code/modules/mob/mob_damage.dm b/code/modules/mob/mob_damage.dm index 26b684a8e2d0..2897d3117330 100644 --- a/code/modules/mob/mob_damage.dm +++ b/code/modules/mob/mob_damage.dm @@ -124,5 +124,27 @@ if(do_update_health) update_health() +// Calculates the Siemen's coefficient for a given area of the body. +// 1 is 100% vulnerability, 0 is immune. +/mob/proc/get_siemens_coefficient_for_coverage(coverage_flags = SLOT_HANDS) + var/decl/species/my_species = get_species() + . = my_species ? my_species.shock_vulnerability : 1 + if(. <= 0) + return 0 + if(coverage_flags) + for(var/obj/item/clothing/clothes in get_equipped_items(include_carried = FALSE)) + if(clothes.body_parts_covered & coverage_flags) + if(clothes.siemens_coefficient <= 0) + return 0 + . *= clothes.siemens_coefficient + if(. <= 0) + return 0 + . = max(round(., 0.1), 0) + +//this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. +/mob/proc/get_siemens_coefficient_organ(var/obj/item/organ/external/def_zone) + return (istype(def_zone) && def_zone.body_part) ? get_siemens_coefficient_for_coverage(def_zone.body_part) : 1 + /mob/proc/apply_radiation(var/damage = 0) return + diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index ec19dd3daedb..88da01483aaf 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -156,3 +156,6 @@ // Offset the overhead text if necessary. var/offset_overhead_text_x = 0 var/offset_overhead_text_y = 0 + + /// Are you trying not to hurt your opponent? + var/pulling_punches diff --git a/code/modules/mob/mob_eating.dm b/code/modules/mob/mob_eating.dm index 2d9170878b8f..c4fb19e2854e 100644 --- a/code/modules/mob/mob_eating.dm +++ b/code/modules/mob/mob_eating.dm @@ -1,6 +1,15 @@ -// mobs do not have blocked mouths by default -// overridden in human_defense.dm +//Used to check if they can be fed food/drinks/pills /mob/proc/check_mouth_coverage() + return get_covering_head_item(SLOT_FACE) + +/mob/proc/check_head_coverage() + return !!get_covering_head_item(SLOT_HEAD) + +/mob/proc/get_covering_head_item(slot_flags) + for(var/slot in global.standard_headgear_slots) + var/obj/item/clothes = get_equipped_item(slot) + if(istype(clothes) && (clothes.body_parts_covered & slot_flags) && !(clothes.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) + return clothes return null /mob/proc/get_eaten_transfer_amount(var/default) diff --git a/code/modules/mob/mob_layering.dm b/code/modules/mob/mob_layering.dm index d98e8923528f..e4ecb2b50071 100644 --- a/code/modules/mob/mob_layering.dm +++ b/code/modules/mob/mob_layering.dm @@ -7,9 +7,9 @@ var/last_layer = layer var/new_layer = get_base_layer() if(isturf(loc)) - var/turf/T = loc - if(T.pixel_z < 0) - new_layer = T.layer + 0.25 + var/turf/my_turf = loc + if(my_turf.pixel_z < 0 && !my_turf.get_supporting_platform()) + new_layer = my_turf.layer + 0.25 else if(buckled && buckled.buckle_layer_above) new_layer = buckled.layer + ((buckled.dir == SOUTH) ? -0.01 : 0.01) else if(length(grabbed_by)) @@ -97,8 +97,14 @@ // Update offsets from loc. var/turf/floor/ext = loc - if(istype(ext) && ext.height < 0) - new_pixel_z += ext.pixel_z + if(istype(ext)) + var/obj/structure/platform = ext.get_supporting_platform() + if(platform) + new_pixel_z += platform.pixel_z + else if(ext.height < 0) + new_pixel_z += ext.pixel_z + + // Check for catwalks/supporting platforms. // Update offsets from our buckled atom. if(buckled && buckled.buckle_pixel_shift) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 866c96a62c6e..6ec207ea1b87 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -98,8 +98,7 @@ O.add_ai_verbs() O.rename_self("ai",1) - spawn(0) // Mobs still instantly del themselves, thus we need to spawn or O will never be returned - qdel(src) + qdel(src) return O //human -> robot @@ -136,7 +135,7 @@ RAISE_EVENT(/decl/observ/cyborg_created, O) O.Namepick() - qdel(src) // Queues us for a hard delete + qdel(src) return O /mob/living/human/proc/corgize() @@ -188,8 +187,7 @@ to_chat(new_mob, "You suddenly feel more... animalistic.") - spawn() - qdel(src) + qdel(src) return /mob/proc/Animalize() diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm index 1bfc73fb6a28..4adb8e75dd2e 100644 --- a/code/modules/modular_computers/computers/modular_computer/interaction.dm +++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm @@ -85,23 +85,22 @@ return TRUE . = ..() -/obj/item/modular_computer/attackby(var/obj/item/W, var/mob/user) +/obj/item/modular_computer/attackby(var/obj/item/used_item, var/mob/user) + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) - . = assembly.attackby(W, user) - if(.) + if(assembly?.attackby(used_item, user)) update_verbs() return TRUE - if(IS_PEN(W) && (W.w_class <= ITEM_SIZE_TINY) && stores_pen) + if(IS_PEN(used_item) && (used_item.w_class <= ITEM_SIZE_TINY) && stores_pen) if(istype(stored_pen)) - to_chat(user, "There is already a pen in [src].") - return TRUE - if(!user.try_unequip(W, src)) - return TRUE - stored_pen = W - update_verbs() - to_chat(user, "You insert [W] into [src].") + to_chat(user, SPAN_NOTICE("There is already \a [stored_pen] in \the [src].")) + else if(user.try_unequip(used_item, src)) + stored_pen = used_item + update_verbs() + to_chat(user, SPAN_NOTICE("You insert \the [used_item] into [src].")) return TRUE + return ..() /obj/item/modular_computer/examine(mob/user) diff --git a/code/modules/modular_computers/file_system/programs/generic/folding.dm b/code/modules/modular_computers/file_system/programs/generic/folding.dm index ebd8214d0ffb..5d49c83988b3 100644 --- a/code/modules/modular_computers/file_system/programs/generic/folding.dm +++ b/code/modules/modular_computers/file_system/programs/generic/folding.dm @@ -23,7 +23,7 @@ var/started_on = 0 // When the program started some science. var/current_interval = 0 // How long the current interval will be. - var/next_event = 0 // in world timeofday, when the next event is scheduled to pop. + var/next_event = 0 // based on world.timeofday, when the next event is scheduled to pop. var/program_status = PROGRAM_STATUS_RUNNING // Program periodically needs a restart, increases crash chance slightly over time. var/crashed_at = 0 // When the program crashed. diff --git a/code/modules/modular_computers/hardware/lan_port.dm b/code/modules/modular_computers/hardware/lan_port.dm index 1c0701880ef5..8ffecb3d26a6 100644 --- a/code/modules/modular_computers/hardware/lan_port.dm +++ b/code/modules/modular_computers/hardware/lan_port.dm @@ -77,10 +77,10 @@ to_chat(user, SPAN_WARNING("You need five lengths of network cable for \the [parent].")) return TRUE - user.visible_message(SPAN_NOTICE("\The [user] adds cables to the \the [parent]."), "You start adding cables to \the [parent] frame...") + user.visible_message(SPAN_NOTICE("\The [user] adds cables to \the [parent]."), "You start adding cables to \the [parent] frame...") if(do_after(user, 20, parent)) if(!terminal && (loc == parent) && parent.components_are_accessible(type) && !check_terminal_block(T) && C.use(5)) - user.visible_message(SPAN_NOTICE("\The [user] has added cables to the \the [parent]!"), "You add cables to the \the [parent].") + user.visible_message(SPAN_NOTICE("\The [user] has added cables to \the [parent]!"), "You add cables to \the [parent].") set_terminal() return TRUE if(IS_WIRECUTTER(I) && terminal) diff --git a/code/modules/modular_computers/networking/machinery/telecomms.dm b/code/modules/modular_computers/networking/machinery/telecomms.dm index 9c936561586e..93f7f7cd4914 100644 --- a/code/modules/modular_computers/networking/machinery/telecomms.dm +++ b/code/modules/modular_computers/networking/machinery/telecomms.dm @@ -127,7 +127,7 @@ var/global/list/telecomms_hubs = list() if(overloaded_for > 0) overloaded_for-- -/// Accepts either a raw frequency (numeric), or or a frequency/key string, and returns the associated channel data. +/// Accepts either a raw frequency (numeric), or a frequency/key string, and returns the associated channel data. /obj/machinery/network/telecomms_hub/proc/get_channel_from_freq_or_key(var/cid) cid = "[cid]" . = LAZYACCESS(channels_by_frequency, cid) || LAZYACCESS(channels_by_key, cid) diff --git a/code/modules/modular_computers/terminal/terminal.dm b/code/modules/modular_computers/terminal/terminal.dm index 994bbc2f774c..dec38ed92f15 100644 --- a/code/modules/modular_computers/terminal/terminal.dm +++ b/code/modules/modular_computers/terminal/terminal.dm @@ -98,7 +98,7 @@ account_name = "LOCAL" else account_name = "GUEST" - content += "
>[account_name]:/[current_disk?.get_dir_path(current_directory, TRUE)]
" + content += "
\>[account_name]:/[current_disk?.get_dir_path(current_directory, TRUE)]
" content += "type `man` for a list of available commands." panel.set_content("[jointext(content, "
")]
") @@ -159,7 +159,7 @@ /datum/terminal/proc/parse_directory(directory_path, create_directories = FALSE) var/datum/file_storage/target_disk = current_disk var/datum/computer_file/directory/root_dir = current_directory - + if(!length(directory_path)) return list(target_disk, root_dir) @@ -168,8 +168,8 @@ // Otherwise, we append the working directory path to the passed path. var/list/directories = splittext(directory_path, "/") - - // When splitting the text, there could be blank strings at either end, so remove them. If there's any in the body of the path, there was a + + // When splitting the text, there could be blank strings at either end, so remove them. If there's any in the body of the path, there was a // missed input, so leave them. if(!length(directories[1])) directories.Cut(1, 2) @@ -194,7 +194,7 @@ if(!target_disk) // Invalid disk entered. return OS_DIR_NOT_FOUND directories.Cut(1, 2) - + break // Any further use of ../ is handled by the hard drive. // If we were only pathing to the parent of a directory or to a disk, we can return early. @@ -208,7 +208,7 @@ var/datum/computer_file/directory/target_directory = target_disk.parse_directory(final_path, create_directories) if(!istype(target_directory)) return OS_DIR_NOT_FOUND - + return list(target_disk, target_directory) // Returns list(/datum/file_storage, /datum/computer_file/directory, /datum/computer_file) on success. Returns error code on failure. @@ -221,7 +221,7 @@ var/list/dirs_and_file = splittext(file_path, "/") if(!length(dirs_and_file)) return OS_DIR_NOT_FOUND - + // Join together everything but the filename into a path. var/list/file_loc = parse_directory(jointext(dirs_and_file, "/", 1, dirs_and_file.len)) if(!islist(file_loc)) // Errored! @@ -231,7 +231,7 @@ var/datum/computer_file/directory/target_dir = file_loc[2] if(!istype(target_disk)) return OS_DIR_NOT_FOUND - + var/filename = dirs_and_file[dirs_and_file.len] var/datum/computer_file/target_file = target_disk.get_file(filename, target_dir) if(!istype(target_file)) @@ -265,5 +265,5 @@ return "I/O error, Harddrive may be non-functional" if(OS_NETWORK_ERROR) return "Unable to connect to the network" - + return "An unspecified error occured." \ No newline at end of file diff --git a/code/modules/multiz/ladder.dm b/code/modules/multiz/ladder.dm index 2bdad6e2350f..b86299bcf5f4 100644 --- a/code/modules/multiz/ladder.dm +++ b/code/modules/multiz/ladder.dm @@ -71,8 +71,8 @@ var/turf/L = loc if(HasBelow(z) && istype(L) && L.is_open()) var/failed - for(var/obj/structure/catwalk/catwalk in loc) - if(catwalk.plated_tile) + for(var/obj/structure/platform in loc) + if(!platform.is_z_passable()) failed = TRUE break if(!failed) @@ -86,8 +86,8 @@ var/turf/T = GetAbove(src) if(istype(T) && T.is_open()) var/failed - for(var/obj/structure/catwalk/catwalk in T) - if(catwalk.plated_tile) + for(var/obj/structure/platform in T) + if(!platform.is_z_passable()) failed = TRUE break if(!failed) @@ -214,18 +214,18 @@ if(!istype(T) || !T.is_open()) to_chat(M, SPAN_WARNING("The ceiling is in the way!")) return null - for(var/obj/structure/catwalk/catwalk in target_up.loc) - if(catwalk.plated_tile) - to_chat(M, SPAN_WARNING("\The [catwalk] is in the way!")) + for(var/obj/structure/platform in target_up.loc) + if(!platform.is_z_passable()) + to_chat(M, SPAN_WARNING("\The [platform] is in the way!")) return null if(. == target_down) var/turf/T = loc if(!istype(T) || !T.is_open()) to_chat(M, SPAN_WARNING("\The [loc] is in the way!")) return null - for(var/obj/structure/catwalk/catwalk in loc) - if(catwalk.plated_tile) - to_chat(M, SPAN_WARNING("\The [catwalk] is in the way!")) + for(var/obj/structure/platform in loc) + if(!platform.is_z_passable()) + to_chat(M, SPAN_WARNING("\The [platform] is in the way!")) return null /mob/proc/may_climb_ladders(var/ladder) diff --git a/code/modules/multiz/level_data.dm b/code/modules/multiz/level_data.dm index d1aeb0bdaee6..00b82e3b5ac3 100644 --- a/code/modules/multiz/level_data.dm +++ b/code/modules/multiz/level_data.dm @@ -189,7 +189,6 @@ initialize_level_id() SSmapping.register_level_data(src) - setup_ambient() setup_exterior_atmosphere() if(SSmapping.initialized && !defer_level_setup) setup_level_data() @@ -241,6 +240,7 @@ if(!skip_gen) generate_level() after_generate_level() + setup_ambient() // Determine our relative positioning. // First find an appropriate origin point. @@ -756,6 +756,12 @@ INITIALIZE_IMMEDIATE(/obj/abstract/level_data_spawner) level_flags = (ZLEVEL_CONTACT|ZLEVEL_PLAYER|ZLEVEL_SEALED) filler_turf = /turf/unsimulated/dark_filler +// Used in order to avoid making the level too large. Only works if loaded prior to SSmapping init... it's unclear if this really does much. +/datum/level_data/unit_test/after_template_load(var/datum/map_template/template) + . = ..() + level_max_width ||= template.width + level_max_height ||= template.height + /datum/level_data/overmap name = "Sensor Display" level_flags = ZLEVEL_SEALED @@ -772,7 +778,8 @@ INITIALIZE_IMMEDIATE(/obj/abstract/level_data_spawner) return ..() /datum/level_data/mining_level/asteroid - base_turf = /turf/floor + base_turf = /turf/floor/barren + filler_turf = /turf/space level_generators = list( /datum/random_map/automata/cave_system, /datum/random_map/noise/ore @@ -861,13 +868,10 @@ INITIALIZE_IMMEDIATE(/obj/abstract/level_data_spawner) load_subtemplate(T, template) return template -///Actually handles loading a template template at the given turf. +///Actually handles loading a template at the given turf. /datum/level_data/proc/load_subtemplate(turf/central_turf, datum/map_template/template) if(!template) return FALSE - for(var/turf/T in template.get_affected_turfs(central_turf, TRUE)) - for(var/mob/living/simple_animal/monster in T) - qdel(monster) template.load(central_turf, centered = TRUE) return TRUE diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index 01db42e52616..c08433c2a3c5 100644 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -9,7 +9,7 @@ return FALSE else if(direction == DOWN) - if(!is_open() || !HasBelow(z) || (locate(/obj/structure/catwalk) in src)) + if(!is_open() || !HasBelow(z) || get_supporting_platform()) return FALSE if(check_neighbor_canzpass) var/turf/T = GetBelow(src) diff --git a/code/modules/organs/ailments/_ailment.dm b/code/modules/organs/ailments/_ailment.dm index 7bcc0c24da64..713dfcdc7aab 100644 --- a/code/modules/organs/ailments/_ailment.dm +++ b/code/modules/organs/ailments/_ailment.dm @@ -1,10 +1,9 @@ /datum/ailment + abstract_type = /datum/ailment var/name // Descriptive name, primarily used for adminbus. var/timer_id // Current timer waiting to proc next symptom message. var/min_time = 2 MINUTES // Minimum time between symptom messages. var/max_time = 5 MINUTES // Maximum time between symptom messages. - var/category = /datum/ailment // Used similar to hierarchies, if category == type then the - // ailment is a category and won't be applied to organs. var/obj/item/organ/organ // Organ associated with the ailment (ailment is in organ.ailments list). // Requirements before applying to a target. diff --git a/code/modules/organs/ailments/ailment_codex.dm b/code/modules/organs/ailments/ailment_codex.dm index 40cc20eb341d..566446dd17ef 100644 --- a/code/modules/organs/ailments/ailment_codex.dm +++ b/code/modules/organs/ailments/ailment_codex.dm @@ -40,7 +40,7 @@ ailment_table += "[name_column][treatment_column]" for(var/atype in subtypesof(/datum/ailment)) var/datum/ailment/ailment = get_ailment_reference(atype) - if(!ailment.name || show_robotics_recipes != ailment.applies_to_prosthetics || ailment.hidden_from_codex) + if(!ailment || show_robotics_recipes != ailment.applies_to_prosthetics || ailment.hidden_from_codex) continue ailment_table += "[ailment.name]" var/list/ailment_cures = list() diff --git a/code/modules/organs/ailments/ailments_medical.dm b/code/modules/organs/ailments/ailments_medical.dm index 4cf930ac0f95..c9d3dad97511 100644 --- a/code/modules/organs/ailments/ailments_medical.dm +++ b/code/modules/organs/ailments/ailments_medical.dm @@ -1,5 +1,5 @@ /datum/ailment/head - category = /datum/ailment/head + abstract_type = /datum/ailment/head applies_to_organ = list(BP_HEAD) /datum/ailment/head/headache diff --git a/code/modules/organs/ailments/faults/_fault.dm b/code/modules/organs/ailments/faults/_fault.dm index 8219540a8dc1..52a9b747a84e 100644 --- a/code/modules/organs/ailments/faults/_fault.dm +++ b/code/modules/organs/ailments/faults/_fault.dm @@ -1,7 +1,7 @@ /datum/ailment/fault applies_to_robotics = TRUE applies_to_prosthetics = TRUE - category = /datum/ailment/fault + abstract_type = /datum/ailment/fault treated_by_item_type = list( /obj/item/stack/nanopaste, /obj/item/stack/tape_roll/duct_tape diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm index 7b6ef08b85bb..c65f7e18f4d9 100644 --- a/code/modules/organs/external/_external.dm +++ b/code/modules/organs/external/_external.dm @@ -62,7 +62,7 @@ var/artery_name = "artery" // Flavour text for cartoid artery, aorta, etc. var/arterial_bleed_severity = 1 // Multiplier for bleeding in a limb. var/tendon_name = "tendon" // Flavour text for Achilles tendon, etc. - var/cavity_name = "cavity" + var/cavity_name = "intramuscular cavity" // Surgery vars. var/cavity_max_w_class = ITEM_SIZE_TINY //this is increased if bigger organs spawn by default inside @@ -70,8 +70,6 @@ var/stage = 0 var/cavity = 0 - var/list/unarmed_attacks - var/atom/movable/applied_pressure var/atom/movable/splinted @@ -141,10 +139,6 @@ _icon_cache_key = null . = ..() skin_blend = bodytype.limb_blend - for(var/attack_type in species.unarmed_attacks) - var/decl/natural_attack/attack = GET_DECL(attack_type) - if(istype(attack) && (organ_tag in attack.usable_with_limbs)) - LAZYADD(unarmed_attacks, attack_type) update_icon() /obj/item/organ/external/set_bodytype(decl/bodytype/new_bodytype, override_material = null, apply_to_internal_organs = TRUE) @@ -318,7 +312,7 @@ //Handles removing internal organs/implants/items still in the detached limb. /obj/item/organ/external/proc/try_remove_internal_item(var/obj/item/used_item, var/mob/user) - if(stage == 0 && used_item.sharp) + if(stage == 0 && used_item.is_sharp()) user.visible_message(SPAN_NOTICE("\The [user] cuts \the [src] open with \the [used_item].")) stage++ return TRUE @@ -328,7 +322,7 @@ stage++ return TRUE - if(stage == 2 && (used_item.sharp || IS_HEMOSTAT(used_item) || IS_WIRECUTTER(used_item))) + if(stage == 2 && (used_item.is_sharp() || IS_HEMOSTAT(used_item) || IS_WIRECUTTER(used_item))) var/list/radial_buttons = make_item_radial_menu_choices(get_contents_recursive()) if(LAZYLEN(radial_buttons)) var/obj/item/removing = show_radial_menu(user, src, radial_buttons, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(src)) diff --git a/code/modules/organs/external/head.dm b/code/modules/organs/external/head.dm index 1d6b432822ce..b16d8919e296 100644 --- a/code/modules/organs/external/head.dm +++ b/code/modules/organs/external/head.dm @@ -12,7 +12,7 @@ amputation_point = "neck" encased = "skull" artery_name = "carotid artery" - cavity_name = "cranial" + cavity_name = "cranial cavity" limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE var/glowing_eyes = FALSE @@ -20,6 +20,24 @@ var/forehead_graffiti var/graffiti_style +/obj/item/organ/external/head/get_natural_attacks() + if(!can_intake_reagents) + return null + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite) + return unarmed_attack + +/obj/item/organ/external/head/sharp_bite/get_natural_attacks() + if(!can_intake_reagents) + return null + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/sharp) + return unarmed_attack + +/obj/item/organ/external/head/strong_bite/get_natural_attacks() + if(!can_intake_reagents) + return null + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/strong) + return unarmed_attack + /obj/item/organ/external/head/proc/get_organ_eyes_overlay() if(!glowing_eyes && !owner?.has_chemical_effect(CE_GLOWINGEYES, 1)) return diff --git a/code/modules/organs/external/standard.dm b/code/modules/organs/external/standard.dm index 2beef64083b1..84cb21e75a31 100644 --- a/code/modules/organs/external/standard.dm +++ b/code/modules/organs/external/standard.dm @@ -17,7 +17,7 @@ parent_organ = null encased = "ribcage" artery_name = "aorta" - cavity_name = "thoracic" + cavity_name = "thoracic cavity" limb_flags = ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK /obj/item/organ/external/chest/proc/get_current_skin() @@ -41,7 +41,7 @@ amputation_point = "lumbar" joint = "hip" artery_name = "iliac artery" - cavity_name = "abdominal" + cavity_name = "abdominal cavity" limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_BREAK /obj/item/organ/external/groin/die() @@ -113,6 +113,13 @@ limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE organ_category = ORGAN_CATEGORY_STANCE +/obj/item/organ/external/foot/get_natural_attacks() + var/static/list/unarmed_attacks = list( + GET_DECL(/decl/natural_attack/stomp), + GET_DECL(/decl/natural_attack/kick) + ) + return unarmed_attacks + /obj/item/organ/external/foot/right organ_tag = BP_R_FOOT name = "right foot" @@ -139,6 +146,10 @@ is_washable = TRUE var/gripper_type = /datum/inventory_slot/gripper/left_hand +/obj/item/organ/external/hand/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/punch) + return unarmed_attack + /obj/item/organ/external/hand/do_install(mob/living/human/target, affected, in_place, update_icon, detached) . = ..() if(. && owner && gripper_type) @@ -158,3 +169,11 @@ joint = "right wrist" amputation_point = "right wrist" gripper_type = /datum/inventory_slot/gripper/right_hand + +/obj/item/organ/external/hand/clawed/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws) + return unarmed_attack + +/obj/item/organ/external/hand/right/clawed/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws) + return unarmed_attack diff --git a/code/modules/organs/external/wounds/wound.dm b/code/modules/organs/external/wounds/wound.dm index 2c2746cd154c..60219be1f1a4 100644 --- a/code/modules/organs/external/wounds/wound.dm +++ b/code/modules/organs/external/wounds/wound.dm @@ -79,7 +79,7 @@ return 0 return (wound_damage() <= autoheal_cutoff) ? 1 : is_treated() -// checks whether the wound has been appropriately treated +/// checks whether the wound has been appropriately treated /datum/wound/proc/is_treated() if(!LAZYLEN(embedded_objects)) switch(damage_type) @@ -88,7 +88,7 @@ if(BURN) return salved - // Checks whether other other can be merged into src. +/// Checks whether other can be merged into src. /datum/wound/proc/can_merge_wounds(var/datum/wound/other) if (other.type != src.type) return 0 if (other.current_stage != src.current_stage) return 0 diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 31cede40eaec..84d4cbc4155e 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -484,9 +484,11 @@ return var/global/list/ailment_reference_cache = list() -/proc/get_ailment_reference(var/ailment_type) +/proc/get_ailment_reference(var/datum/ailment/ailment_type) if(!ispath(ailment_type, /datum/ailment)) return + if(TYPE_IS_ABSTRACT(ailment_type)) + return if(!global.ailment_reference_cache[ailment_type]) global.ailment_reference_cache[ailment_type] = new ailment_type return global.ailment_reference_cache[ailment_type] @@ -497,7 +499,7 @@ var/global/list/ailment_reference_cache = list() return . for(var/ailment_type in subtypesof(/datum/ailment)) var/datum/ailment/ailment = ailment_type - if(initial(ailment.category) == ailment_type) + if(TYPE_IS_ABSTRACT(ailment)) continue ailment = get_ailment_reference(ailment_type) if(ailment.can_apply_to(src)) diff --git a/code/modules/overmap/contacts/_contacts.dm b/code/modules/overmap/contacts/_contacts.dm index e4cab812e76f..bde9a41d1717 100644 --- a/code/modules/overmap/contacts/_contacts.dm +++ b/code/modules/overmap/contacts/_contacts.dm @@ -29,7 +29,6 @@ radar = image(loc = effect, icon = 'icons/obj/overmap.dmi', icon_state = "sensor_range") radar.color = source.color - radar.tag = "radar" radar.add_filter("blur", 1, list(type = "blur", size = 1)) radar.appearance_flags |= RESET_TRANSFORM | KEEP_APART radar.appearance_flags &= ~PIXEL_SCALE diff --git a/code/modules/overmap/overmap_shuttle.dm b/code/modules/overmap/overmap_shuttle.dm index 408db04970a3..2a7e5b3fb646 100644 --- a/code/modules/overmap/overmap_shuttle.dm +++ b/code/modules/overmap/overmap_shuttle.dm @@ -7,7 +7,7 @@ var/fuel_consumption = 0 //Amount of moles of gas consumed per trip; If zero, then shuttle is magic and does not need fuel var/list/obj/structure/fuel_port/fuel_ports //the fuel ports of the shuttle (but usually just one) - category = /datum/shuttle/autodock/overmap + abstract_type = /datum/shuttle/autodock/overmap var/skill_needed = SKILL_BASIC var/landing_skill_needed = SKILL_EXPERT var/operator_skill = SKILL_MIN diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm index 89f88cf959a8..a5b56cf128fb 100644 --- a/code/modules/paperwork/papershredder.dm +++ b/code/modules/paperwork/papershredder.dm @@ -89,7 +89,7 @@ /obj/machinery/papershredder/proc/is_bin_empty() return !(length(shredder_bin) > 0 && cached_total_matter) -/obj/machinery/papershredder/proc/can_shred(var/obj/item/I, var/mob/user = null) +/obj/machinery/papershredder/proc/can_shred_document(var/obj/item/I, var/mob/user = null) if(!istype(I)) if(user) to_chat(user, SPAN_WARNING("\The [I] cannot be shredded by \the [src]!")) @@ -120,7 +120,7 @@ empty_bin(user, used_item) return TRUE - else if(!trying_to_smack && can_shred(used_item)) + else if(!trying_to_smack && can_shred_document(used_item)) shred(used_item, user) return TRUE return ..() diff --git a/code/modules/paperwork/pen/fancy.dm b/code/modules/paperwork/pen/fancy.dm index 9c7e149a7be8..098033965e66 100644 --- a/code/modules/paperwork/pen/fancy.dm +++ b/code/modules/paperwork/pen/fancy.dm @@ -1,7 +1,7 @@ /obj/item/pen/fancy name = "fountain pen" icon = 'icons/obj/items/pens/pen_fancy.dmi' - sharp = 1 //pointy + sharp = TRUE stroke_color = "#1c1713" //dark ashy brownish stroke_color_name = "dark ashy brownish" material = /decl/material/solid/metal/steel diff --git a/code/modules/paperwork/pen/quill_and_ink.dm b/code/modules/paperwork/pen/quill_and_ink.dm index 4944165f4e5b..f643b9d12472 100644 --- a/code/modules/paperwork/pen/quill_and_ink.dm +++ b/code/modules/paperwork/pen/quill_and_ink.dm @@ -1,7 +1,7 @@ /obj/item/pen/fancy/quill name = "quill pen" icon = 'icons/obj/items/pens/pen_quill.dmi' - sharp = 0 + sharp = FALSE material = /decl/material/solid/organic/skin/feathers pen_quality = TOOL_QUALITY_DEFAULT max_uses = 5 // gotta re-ink it often! diff --git a/code/modules/paperwork/pen/reagent_pen.dm b/code/modules/paperwork/pen/reagent_pen.dm index 67dfcad441c6..7334323851a1 100644 --- a/code/modules/paperwork/pen/reagent_pen.dm +++ b/code/modules/paperwork/pen/reagent_pen.dm @@ -1,7 +1,7 @@ /obj/item/pen/reagent atom_flags = ATOM_FLAG_OPEN_CONTAINER origin_tech = @'{"materials":2,"esoteric":5}' - sharp = 1 + sharp = TRUE pen_quality = TOOL_QUALITY_MEDIOCRE /obj/item/pen/reagent/Initialize() diff --git a/code/modules/persistence/graffiti.dm b/code/modules/persistence/graffiti.dm index 1ed8a188417e..0bd85389b6f4 100644 --- a/code/modules/persistence/graffiti.dm +++ b/code/modules/persistence/graffiti.dm @@ -43,7 +43,7 @@ user.visible_message(SPAN_NOTICE("\The [user] clears away some graffiti.")) qdel(src) return TRUE - else if(thing.sharp && !user.check_intent(I_FLAG_HELP)) //Check intent so you don't go insane trying to unscrew a light fixture over a graffiti + else if(thing.is_sharp() && !user.check_intent(I_FLAG_HELP)) //Check intent so you don't go insane trying to unscrew a light fixture over a graffiti if(jobban_isbanned(user, "Graffiti")) to_chat(user, SPAN_WARNING("You are banned from leaving persistent information across rounds.")) return TRUE diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 1f6254eea46a..6e2b63b82fa9 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -491,21 +491,20 @@ var/global/list/all_apcs = list() /obj/machinery/power/apc/physical_attack_hand(mob/user) //Human mob special interaction goes here. - if(ishuman(user)) - var/mob/living/human/H = user - - if(H.species.can_shred(H)) - user.visible_message("\The [user] slashes at \the [src]!", "You slash at \the [src]!") - playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - - var/allcut = wires.IsAllCut() - if(beenhit >= pick(3, 4) && allcut == 0) - wires.CutAll() - src.update_icon() - src.visible_message("\The [src]'s wires are shredded!") - else - beenhit += 1 - return TRUE + if(user.can_shred()) + user.visible_message( + SPAN_DANGER("\The [user] slashes at \the [src]!"), + SPAN_DANGER("You slash at \the [src]!") + ) + playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) + var/allcut = wires.IsAllCut() + if(beenhit >= pick(3, 4) && allcut == 0) + wires.CutAll() + update_icon() + visible_message(SPAN_DANGER("\The [src]'s wires are shredded!")) + else + beenhit += 1 + return TRUE return FALSE /obj/machinery/power/apc/interface_interact(mob/user) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 78f587767eef..655e27664973 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -188,9 +188,10 @@ By design, d1 is the smallest direction and d2 is the highest to_chat(user, SPAN_WARNING("\The [src] is not powered.")) return TRUE - if(used_item.edge) + else if(used_item.has_edge()) + var/delay_holder - if(used_item.get_attack_force(user) < 5) + if(used_item.expend_attack_force(user) < 5) visible_message(SPAN_WARNING("[user] starts sawing away roughly at \the [src] with \the [used_item].")) delay_holder = 8 SECONDS else diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 48abeb8383a3..a60fab7f939a 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -85,7 +85,8 @@ to_chat(user, "The charge meter reads [round(src.percent(), 0.1)]%.") /obj/item/cell/emp_act(severity) - //remove this once emp changes on dev are merged in + // remove this if EMPs are ever rebalanced so that they don't instantly drain borg cells + // todo: containers (partially) shielding contents? if(isrobot(loc)) var/mob/living/silicon/robot/R = loc severity *= R.cell_emp_mult diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index e3b47f5c5d10..624425a51215 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -264,7 +264,7 @@ else if(lightbulb && (lightbulb.status != LIGHT_BROKEN) && !user.check_intent(I_FLAG_HELP)) - if(prob(1 + W.get_attack_force(user) * 5)) + if(prob(1 + W.expend_attack_force(user) * 5)) user.visible_message("[user.name] smashed the light!", "You smash the light!", "You hear a tinkle of breaking glass.") if(on && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE)) @@ -316,12 +316,13 @@ to_chat(user, "There is no [get_fitting_name()] in this light.") return TRUE - if(ishuman(user)) - var/mob/living/human/H = user - if(H.species.can_shred(H)) - visible_message("[user.name] smashed the light!", 3, "You hear a tinkle of breaking glass.") - broken() - return TRUE + if(user.can_shred()) + visible_message( + SPAN_DANGER("\The [user] smashes the light!"), + blind_message = "You hear a tinkle of breaking glass." + ) + broken() + return TRUE // make it burn hands if not wearing fire-insulated gloves if(on) @@ -604,7 +605,7 @@ if(status == LIGHT_OK || status == LIGHT_BURNED) src.visible_message("[name] shatters.","You hear a small glass object shatter.") status = LIGHT_BROKEN - sharp = 1 + set_sharp(TRUE) set_base_attack_force(5) playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) update_icon() @@ -612,13 +613,7 @@ /obj/item/light/proc/switch_on() switchcount++ if(rigged) - log_and_message_admins("Rigged light explosion, last touched by [fingerprintslast]") - var/turf/T = get_turf(src.loc) - spawn(0) - sleep(2) - explosion(T, 0, 0, 3, 5) - sleep(1) - qdel(src) + addtimer(CALLBACK(src, PROC_REF(do_rigged_explosion)), 0.2 SECONDS) status = LIGHT_BROKEN else if(prob(min(60, switchcount*switchcount*0.01))) status = LIGHT_BURNED @@ -626,6 +621,15 @@ playsound(src, sound_on, 75) return status +/obj/item/light/proc/do_rigged_explosion() + if(!rigged) + return + log_and_message_admins("Rigged light explosion, last touched by [fingerprintslast]") + var/turf/T = get_turf(src) + explosion(T, 0, 0, 3, 5) + if(!QDELETED(src)) + QDEL_IN(src, 1) + /obj/machinery/light/do_simple_ranged_interaction(var/mob/user) if(lightbulb) remove_bulb() diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index ca4b205e6b00..8afd72314cea 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -179,11 +179,14 @@ return net1 //Determines how strong could be shock, deals damage to mob, uses power. -//M is a mob who touched wire/whatever +//victim is a mob who touched wire/whatever //power_source is a source of electricity, can be powercell, area, apc, cable, powernet or null //source is an object caused electrocuting (airlock, grille, etc) //No animations will be performed by this proc. -/proc/electrocute_mob(mob/living/M, var/power_source, var/obj/source, var/siemens_coeff = 1.0) +/proc/electrocute_mob(mob/living/victim, power_source, obj/source, siemens_coeff = 1.0, coverage_flags = SLOT_HANDS) + + coverage_flags = victim?.get_active_hand_bodypart_flags() || coverage_flags + var/area/source_area if(istype(power_source,/area)) source_area = power_source @@ -208,19 +211,16 @@ else if (!power_source) return 0 else - log_admin("ERROR: /proc/electrocute_mob([M], [power_source], [source]): wrong power_source") + log_admin("ERROR: /proc/electrocute_mob([victim], [power_source], [source]): wrong power_source") return 0 + //Triggers powernet warning, but only for 5 ticks (if applicable) //If following checks determine user is protected we won't alarm for long. if(PN) PN.trigger_warning(5) - if(ishuman(M)) - var/mob/living/human/H = M - if(H.species.get_shock_vulnerability(H) <= 0) - return - var/obj/item/clothing/gloves/G = H.get_equipped_item(slot_gloves_str) - if(istype(G) && G.siemens_coefficient == 0) - return 0 //to avoid spamming with insulated glvoes on + + if(victim.get_siemens_coefficient_for_coverage(coverage_flags) <= 0) + return //Checks again. If we are still here subject will be shocked, trigger standard 20 tick warning //Since this one is longer it will override the original one. @@ -242,7 +242,7 @@ else power_source = cell shock_damage = cell_damage - var/drained_hp = M.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap! + var/drained_hp = victim.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap! var/drained_energy = drained_hp*20 if (source_area) diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 233b66d985f9..c2b62b6059ff 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -11,7 +11,7 @@ active_power_usage = 100 KILOWATTS var/efficiency = 0.3 // Energy efficiency. 30% at this time, so 100kW load means 30kW laser pulses. - var/minimum_power = 10 KILOWATTS // The minimum power the emitter will still fire at it it doesn't have enough power available. + var/minimum_power = 10 KILOWATTS // The minimum power below which the emitter will turn off; different than the power needed to fire. var/active = 0 var/fire_delay = 100 var/max_burst_delay = 100 diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index bd129184831a..a941debb006a 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -88,7 +88,7 @@ var/global/list/solars_list = list() return TRUE else if (W) add_fingerprint(user) - current_health -= W.get_attack_force(user) + current_health -= W.expend_attack_force(user) healthcheck() return ..() diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index 9230d872fd56..613ae77ae768 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -48,12 +48,11 @@ . = BB BB = null set_dir(pick(global.alldirs)) //spin spent casings - // Aurora forensics port, gunpowder residue. if(leaves_residue) leave_residue() - update_icon() + update_name() /obj/item/ammo_casing/Crossed(atom/movable/AM) ..() @@ -123,6 +122,11 @@ else if(spent_icon && !BB) icon_state = spent_icon +/obj/item/ammo_casing/update_name() + . = ..() + if(!BB) + SetName("spent [name]") + /obj/item/ammo_casing/examine(mob/user) . = ..() if(caliber) diff --git a/code/modules/projectiles/ammunition/chemdart.dm b/code/modules/projectiles/ammunition/chemdart.dm index bd8710bef92d..fa7647a4dcf1 100644 --- a/code/modules/projectiles/ammunition/chemdart.dm +++ b/code/modules/projectiles/ammunition/chemdart.dm @@ -2,7 +2,7 @@ name = "dart" icon_state = "dart" damage = 5 - sharp = 1 + sharp = TRUE embed = 1 //the dart is shot fast enough to pierce space suits, so I guess splintering inside the target can be a thing. Should be rare due to low damage. life_span = 15 //shorter range muzzle_type = null diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index d01aa247e4b0..d99abdef1e63 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -45,6 +45,7 @@ drop_sound = 'sound/foley/drop1.ogg' pickup_sound = 'sound/foley/pickup2.ogg' can_be_twohanded = TRUE // also checks one_hand_penalty + needs_attack_dexterity = DEXTERITY_WEAPONS var/fire_verb = "fire" var/waterproof = FALSE @@ -193,15 +194,20 @@ /obj/item/gun/proc/special_check(var/mob/user) if(!isliving(user)) - return 0 - if(!user.check_dexterity(DEXTERITY_WEAPONS)) - return 0 + return FALSE + + if(!user.check_dexterity(get_required_attack_dexterity(user))) + return FALSE + + if(is_secure_gun() && !free_fire() && (!authorized_modes[sel_mode] || !registered_owner)) + audible_message(SPAN_WARNING("\The [src] buzzes, refusing to fire."), hearing_distance = 3) + playsound(loc, 'sound/machines/buzz-sigh.ogg', 10, 0) + return FALSE var/mob/living/M = user if(!safety() && world.time > last_safety_check + 5 MINUTES && !user.skill_check(SKILL_WEAPONS, SKILL_BASIC)) if(prob(30)) toggle_safety() - return 1 if(M.has_genetic_condition(GENE_COND_CLUMSY) && prob(40)) //Clumsy handling var/obj/P = consume_next_projectile() @@ -218,8 +224,9 @@ M.try_unequip(src) else handle_click_empty(user) - return 0 - return 1 + return FALSE + + return TRUE /obj/item/gun/emp_act(severity) for(var/obj/O in contents) diff --git a/code/modules/projectiles/guns/launcher/bows/arrow.dm b/code/modules/projectiles/guns/launcher/bows/arrow.dm index 1fb6cc358678..073c4d5928ba 100644 --- a/code/modules/projectiles/guns/launcher/bows/arrow.dm +++ b/code/modules/projectiles/guns/launcher/bows/arrow.dm @@ -5,8 +5,8 @@ plural_icon_state = ICON_STATE_WORLD + "-mult" max_icon_state = ICON_STATE_WORLD + "-max" w_class = ITEM_SIZE_NORMAL - sharp = 1 - edge = 0 + sharp = TRUE + edge = FALSE lock_picking_level = 3 material = /decl/material/solid/organic/wood/oak material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC diff --git a/code/modules/projectiles/guns/launcher/syringe_gun.dm b/code/modules/projectiles/guns/launcher/syringe_gun.dm index d44be24924d5..69fa0078472d 100644 --- a/code/modules/projectiles/guns/launcher/syringe_gun.dm +++ b/code/modules/projectiles/guns/launcher/syringe_gun.dm @@ -30,7 +30,7 @@ return TRUE syringe = I to_chat(user, "You carefully insert [syringe] into [src].") - sharp = TRUE + set_sharp(TRUE) name = "syringe dart" update_icon() return TRUE @@ -41,7 +41,7 @@ to_chat(user, "You remove [syringe] from [src].") user.put_in_hands(syringe) syringe = null - sharp = initial(sharp) + set_sharp(initial(sharp)) SetName(initial(name)) update_icon() diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index d4da8ee50454..e34fd58e0619 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -80,8 +80,8 @@ if(handle_casings == HOLD_CASINGS) ammo_magazine.stored_ammo += chambered ammo_magazine.initial_ammo-- - else if(ammo_magazine.stored_ammo.len) - chambered = ammo_magazine.stored_ammo[ammo_magazine.stored_ammo.len] + else if(length(ammo_magazine.stored_ammo)) + chambered = ammo_magazine.stored_ammo[length(ammo_magazine.stored_ammo)] if(handle_casings != HOLD_CASINGS) ammo_magazine.stored_ammo -= chambered @@ -340,9 +340,9 @@ /obj/item/gun/projectile/proc/get_ammo_indicator() var/base_state = get_world_inventory_state() - if(!ammo_magazine || !LAZYLEN(ammo_magazine.stored_ammo)) + if(!ammo_magazine || !ammo_magazine.get_stored_ammo_count()) return mutable_appearance(icon, "[base_state]_ammo_bad") - else if(LAZYLEN(ammo_magazine.stored_ammo) <= 0.5 * ammo_magazine.max_ammo) + else if(LAZYLEN(ammo_magazine.get_stored_ammo_count()) <= 0.5 * ammo_magazine.max_ammo) return mutable_appearance(icon, "[base_state]_ammo_warn") else return mutable_appearance(icon, "[base_state]_ammo_ok") diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index 7505d0152aa7..802b1f93863c 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -35,7 +35,7 @@ /obj/item/gun/projectile/automatic/smg/on_update_icon() ..() if(ammo_magazine) - add_overlay("[get_world_inventory_state()]mag-[round(length(ammo_magazine.stored_ammo),5)]") + add_overlay("[get_world_inventory_state()]mag-[round(ammo_magazine.get_stored_ammo_count(),5)]") /obj/item/gun/projectile/automatic/assault_rifle name = "assault rifle" diff --git a/code/modules/projectiles/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm index 6c00e6c25942..ee2edcdcfaed 100644 --- a/code/modules/projectiles/guns/projectile/dartgun.dm +++ b/code/modules/projectiles/guns/projectile/dartgun.dm @@ -37,13 +37,13 @@ /obj/item/gun/projectile/dartgun/on_update_icon() ..() if(ammo_magazine) - icon_state = "[get_world_inventory_state()]-[clamp(length(ammo_magazine.get_stored_ammo_count()), 0, 5)]" + icon_state = "[get_world_inventory_state()]-[clamp(ammo_magazine.get_stored_ammo_count(), 0, 5)]" else icon_state = get_world_inventory_state() /obj/item/gun/projectile/dartgun/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) if(overlay && (slot in user_mob?.get_held_item_slots()) && ammo_magazine) - overlay.icon_state += "-[clamp(length(ammo_magazine.get_stored_ammo_count()), 0, 5)]" + overlay.icon_state += "-[clamp(ammo_magazine.get_stored_ammo_count(), 0, 5)]" . = ..() /obj/item/gun/projectile/dartgun/consume_next_projectile() diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index 638376989eeb..e64e7c3f731e 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -17,7 +17,7 @@ /obj/item/gun/projectile/pistol/update_base_icon_state() . = ..() - if(!length(ammo_magazine?.stored_ammo)) + if(!ammo_magazine?.get_stored_ammo_count()) var/empty_state = "[icon_state]-e" if(check_state_in_icon(empty_state, icon)) icon_state = empty_state diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index dc643dcdc3b2..8df181e9195e 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -7,7 +7,7 @@ pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE damage = 40 atom_damage_type = BURN - sharp = 1 //concentrated burns + sharp = TRUE //concentrated burns damage_flags = DAM_LASER eyeblur = 4 hitscan = 1 @@ -210,7 +210,7 @@ icon_state = "stun" fire_sound = 'sound/weapons/Taser.ogg' damage_flags = 0 - sharp = 0 //not a laser + sharp = FALSE //not a laser damage = 1//flavor burn! still not a laser, dmg will be reduce by energy resistance not laser resistances atom_damage_type = BURN eyeblur = 1//Some feedback that you've been hit @@ -241,8 +241,8 @@ icon_state = "omnilaser" fire_sound = 'sound/weapons/plasma_cutter.ogg' damage = 15 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE atom_damage_type = BURN life_span = 5 pass_flags = PASS_FLAG_TABLE @@ -317,7 +317,7 @@ name = "dark matter wave" icon_state = "darkt" damage_flags = 0 - sharp = 0 //not a laser + sharp = FALSE //not a laser agony = 40 atom_damage_type = STUN muzzle_type = /obj/effect/projectile/muzzle/darkmattertaser diff --git a/code/modules/projectiles/secure.dm b/code/modules/projectiles/secure.dm index 241a0e0a8aff..6902b3bddb1e 100644 --- a/code/modules/projectiles/secure.dm +++ b/code/modules/projectiles/secure.dm @@ -99,14 +99,6 @@ var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) return security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level) -/obj/item/gun/special_check() - if(is_secure_gun() && !free_fire() && (!authorized_modes[sel_mode] || !registered_owner)) - audible_message(SPAN_WARNING("\The [src] buzzes, refusing to fire."), hearing_distance = 3) - playsound(loc, 'sound/machines/buzz-sigh.ogg', 10, 0) - return 0 - - . = ..() - /obj/item/gun/get_next_firemode() if(!is_secure_gun()) return ..() diff --git a/code/modules/prometheus_metrics/metric_family.dm b/code/modules/prometheus_metrics/metric_family.dm index 373130e297a4..0054e97a257e 100644 --- a/code/modules/prometheus_metrics/metric_family.dm +++ b/code/modules/prometheus_metrics/metric_family.dm @@ -1,11 +1,11 @@ // Datum used for gathering a set of prometheus metrics. -/datum/metric_family +/decl/metric_family var/name = null var/metric_type = null var/help = null // Collect should return a list of lists with two entries, one being a list and the other being a number. -/datum/metric_family/proc/collect() +/decl/metric_family/proc/collect() var/list/out = list() out[++out.len] = list(list("foo" = "bar"), 3.14) @@ -15,9 +15,9 @@ // _to_proto will call the collect() method and format its result in a list // suitable for encoding as a JSON protobuf mapping. -/datum/metric_family/proc/_to_proto() +/decl/metric_family/proc/_to_proto() var/list/collected = collect() - + var/list/out = list( "name" = name, "type" = metric_type, @@ -36,7 +36,7 @@ label_pairs[++label_pairs.len] = list("name" = k, "value" = m[1][k]) metrics[++metrics.len] = list("label" = label_pairs, PROMETHEUS_METRIC_NAME(metric_type) = list("value" = m[2])) - + if(metrics.len == 0) return null out["metric"] = metrics diff --git a/code/modules/prometheus_metrics/metrics.dm b/code/modules/prometheus_metrics/metrics.dm index 95e2f8190027..ad98b6c178f9 100644 --- a/code/modules/prometheus_metrics/metrics.dm +++ b/code/modules/prometheus_metrics/metrics.dm @@ -1,24 +1,15 @@ -var/global/datum/prometheus_metrics/prometheus_metrics = new - // prometheus_metrics holds a list of metric_family datums and uses them to // create a json protobuf. -/datum/prometheus_metrics +/decl/prometheus_metrics var/list/metric_families -/datum/prometheus_metrics/New() - metric_families = list() - for(var/T in subtypesof(/datum/metric_family)) - var/datum/metric_family/mf = T - if(initial(mf.name) == null || initial(mf.metric_type) == null) - continue - metric_families += new T - -/datum/prometheus_metrics/proc/collect() +/decl/prometheus_metrics/proc/collect() var/list/out = list() - for(var/datum/metric_family/MF in metric_families) - var/proto = MF._to_proto() + for(var/decl/metric_family/metric_family in decls_repository.get_decls_of_type_unassociated(/decl/metric_family)) + var/proto = metric_family._to_proto() if(proto != null) - out[++out.len] = MF._to_proto() - + // out += proto will try to merge the lists, we have to insert it at the end instead + out[++out.len] = proto + return json_encode(out) diff --git a/code/modules/prometheus_metrics/metrics/byond.dm b/code/modules/prometheus_metrics/metrics/byond.dm index 232bce38fafe..3aa58ba942d3 100644 --- a/code/modules/prometheus_metrics/metrics/byond.dm +++ b/code/modules/prometheus_metrics/metrics/byond.dm @@ -1,29 +1,29 @@ // byond-specific metrics -/datum/metric_family/byond_time +/decl/metric_family/byond_time name = "byond_world_time_seconds" metric_type = PROMETHEUS_METRIC_COUNTER help = "Counter of 'game-time' seconds since server startup" -/datum/metric_family/byond_time/collect() +/decl/metric_family/byond_time/collect() return list(list(null, world.time / 10)) -/datum/metric_family/byond_tick_lag +/decl/metric_family/byond_tick_lag name = "byond_tick_lag" metric_type = PROMETHEUS_METRIC_GAUGE help = "Current value of world.tick_lag" -/datum/metric_family/byond_tick_lag/collect() +/decl/metric_family/byond_tick_lag/collect() return list(list(null, world.tick_lag)) -/datum/metric_family/byond_players +/decl/metric_family/byond_players name = "byond_players" metric_type = PROMETHEUS_METRIC_GAUGE help = "Number of players currently connected to the server" -/datum/metric_family/byond_players/collect() +/decl/metric_family/byond_players/collect() var/c = 0 for(var/client/C) if(C.connection == "seeker" || C.connection == "web") @@ -31,10 +31,10 @@ return list(list(null, c)) -/datum/metric_family/byond_cpu +/decl/metric_family/byond_cpu name = "byond_cpu" metric_type = PROMETHEUS_METRIC_GAUGE help = "Current value of world.cpu" -/datum/metric_family/byond_cpu/collect() +/decl/metric_family/byond_cpu/collect() return list(list(null, world.cpu)) diff --git a/code/modules/prometheus_metrics/metrics/ss13.dm b/code/modules/prometheus_metrics/metrics/ss13.dm index 5c6d315b04d0..f686f1d1bed7 100644 --- a/code/modules/prometheus_metrics/metrics/ss13.dm +++ b/code/modules/prometheus_metrics/metrics/ss13.dm @@ -1,11 +1,11 @@ // ss13-specific metrics -/datum/metric_family/ss13_controller_time_seconds +/decl/metric_family/ss13_controller_time_seconds name = "ss13_controller_time_seconds" metric_type = PROMETHEUS_METRIC_COUNTER help = "Counter of time spent in a controller in seconds" -/datum/metric_family/ss13_controller_time_seconds/collect() +/decl/metric_family/ss13_controller_time_seconds/collect() var/list/out = list() if(Master) for(var/name in Master.total_run_times) @@ -14,23 +14,23 @@ return out -/datum/metric_family/ss13_master_runlevel +/decl/metric_family/ss13_master_runlevel name = "ss13_master_runlevel" metric_type = PROMETHEUS_METRIC_GAUGE help = "Current MC runlevel" -/datum/metric_family/ss13_master_runlevel/collect() +/decl/metric_family/ss13_master_runlevel/collect() if(Master) return list(list(null, Master.current_runlevel)) return list() -/datum/metric_family/ss13_garbage_queue_length +/decl/metric_family/ss13_garbage_queue_length name = "ss13_garbage_queue_length" metric_type = PROMETHEUS_METRIC_GAUGE help = "Length of SSgarbage queues" -/datum/metric_family/ss13_garbage_queue_length/collect() +/decl/metric_family/ss13_garbage_queue_length/collect() var/list/out = list() if(SSgarbage) @@ -40,12 +40,12 @@ return out -/datum/metric_family/ss13_garbage_queue_results +/decl/metric_family/ss13_garbage_queue_results name = "ss13_garbage_queue_results" metric_type = PROMETHEUS_METRIC_COUNTER help = "Counter of pass/fail results for SSgarbage queues" -/datum/metric_family/ss13_garbage_queue_results/collect() +/decl/metric_family/ss13_garbage_queue_results/collect() var/list/out = list() if(SSgarbage) @@ -56,12 +56,12 @@ return out -/datum/metric_family/ss13_garbage_total_cleaned +/decl/metric_family/ss13_garbage_total_cleaned name = "ss13_garbage_total_cleaned" metric_type = PROMETHEUS_METRIC_COUNTER help = "Counter for number of objects deleted/GCed by SSgarbage" -/datum/metric_family/ss13_garbage_total_cleaned/collect() +/decl/metric_family/ss13_garbage_total_cleaned/collect() var/list/out = list() if(SSgarbage) diff --git a/code/modules/random_map/automata/caves.dm b/code/modules/random_map/automata/caves.dm index d12f5a79204d..91044cd99d54 100644 --- a/code/modules/random_map/automata/caves.dm +++ b/code/modules/random_map/automata/caves.dm @@ -2,7 +2,7 @@ iterations = 5 descriptor = "moon caves" wall_type = /turf/wall/natural - floor_type = /turf/floor + floor_type = /turf/floor/barren target_turf_type = /turf/unsimulated/mask var/sparse_mineral_turf = /turf/wall/natural/random diff --git a/code/modules/random_map/drop/droppod.dm b/code/modules/random_map/drop/droppod.dm index ac23a7b14e80..926ed6b2d0bd 100644 --- a/code/modules/random_map/drop/droppod.dm +++ b/code/modules/random_map/drop/droppod.dm @@ -136,7 +136,6 @@ drop = pick(supplied_drop_types) supplied_drop_types -= drop if(istype(drop)) - drop.tag = null if(drop.buckled) drop.buckled = null drop.forceMove(T) @@ -168,7 +167,6 @@ return for(var/i=0;i\The [user] tries to attack \the [src] with \the [weapon], but it passes through!
") return TRUE - var/force = weapon.get_attack_force(user) + var/force = weapon.expend_attack_force(user) user.visible_message("\The [user] [pick(weapon.attack_verb)] \the [src] with \the [weapon]!") switch(weapon.atom_damage_type) if(BURN) diff --git a/code/modules/shieldgen/emergency_shield.dm b/code/modules/shieldgen/emergency_shield.dm index f76892be8a40..0cb3ee417b94 100644 --- a/code/modules/shieldgen/emergency_shield.dm +++ b/code/modules/shieldgen/emergency_shield.dm @@ -55,7 +55,7 @@ //Calculate damage switch(W.atom_damage_type) if(BRUTE, BURN) - current_health -= W.get_attack_force(user) + current_health -= W.expend_attack_force(user) else return FALSE diff --git a/code/modules/shieldgen/shieldwallgen.dm b/code/modules/shieldgen/shieldwallgen.dm index 126820437525..0ca75384784e 100644 --- a/code/modules/shieldgen/shieldwallgen.dm +++ b/code/modules/shieldgen/shieldwallgen.dm @@ -289,7 +289,7 @@ /obj/machinery/shieldwall/attackby(var/obj/item/I, var/mob/user) var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary - G.storedpower -= I.get_attack_force(user)*2500 + G.storedpower -= I.expend_attack_force(user)*2500 user.visible_message("\The [user] hits \the [src] with \the [I]!") user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(src) diff --git a/code/modules/shuttles/escape_pods.dm b/code/modules/shuttles/escape_pods.dm index c12dc6e38d90..bd13d30c417b 100644 --- a/code/modules/shuttles/escape_pods.dm +++ b/code/modules/shuttles/escape_pods.dm @@ -3,7 +3,7 @@ var/global/list/escape_pods_by_name = list() /datum/shuttle/autodock/ferry/escape_pod var/datum/computer/file/embedded_program/docking/simple/escape_pod_berth/arming_controller - category = /datum/shuttle/autodock/ferry/escape_pod + abstract_type = /datum/shuttle/autodock/ferry/escape_pod move_time = 100 /datum/shuttle/autodock/ferry/escape_pod/New(map_hash) diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm index 794f0736f127..85ee565817b5 100644 --- a/code/modules/shuttles/shuttle.dm +++ b/code/modules/shuttles/shuttle.dm @@ -12,7 +12,7 @@ var/arrive_time = 0 //the time at which the shuttle arrives when long jumping var/flags = 0 var/process_state = IDLE_STATE //Used with SHUTTLE_FLAGS_PROCESS, as well as to store current state. - var/category = /datum/shuttle + abstract_type = /datum/shuttle var/multiz = 0 //how many multiz levels, starts at 0 var/ceiling_type = /turf/unsimulated/floor/shuttle_ceiling diff --git a/code/modules/shuttles/shuttle_autodock.dm b/code/modules/shuttles/shuttle_autodock.dm index 74c157df8fed..f2003eb0129d 100644 --- a/code/modules/shuttles/shuttle_autodock.dm +++ b/code/modules/shuttles/shuttle_autodock.dm @@ -16,7 +16,7 @@ var/obj/effect/shuttle_landmark/landmark_transition //This variable is type-abused initially: specify the landmark_tag, not the actual landmark. var/move_time = 240 //the time spent in the transition area - category = /datum/shuttle/autodock + abstract_type = /datum/shuttle/autodock flags = SHUTTLE_FLAGS_PROCESS | SHUTTLE_FLAGS_ZERO_G /datum/shuttle/autodock/New(var/map_hash, var/obj/effect/shuttle_landmark/start_waypoint) diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm index 2bdc11d22846..f6efaa4a8645 100644 --- a/code/modules/shuttles/shuttle_emergency.dm +++ b/code/modules/shuttles/shuttle_emergency.dm @@ -1,5 +1,5 @@ /datum/shuttle/autodock/ferry/emergency - category = /datum/shuttle/autodock/ferry/emergency + abstract_type = /datum/shuttle/autodock/ferry/emergency move_time = 10 MINUTES flags = SHUTTLE_FLAGS_PROCESS | SHUTTLE_FLAGS_ZERO_G | SHUTTLE_FLAGS_NO_CODE var/datum/evacuation_controller/shuttle/emergency_controller diff --git a/code/modules/shuttles/shuttle_ferry.dm b/code/modules/shuttles/shuttle_ferry.dm index 4f23361de2b3..ebe0a7cf54f6 100644 --- a/code/modules/shuttles/shuttle_ferry.dm +++ b/code/modules/shuttles/shuttle_ferry.dm @@ -7,7 +7,7 @@ var/obj/effect/shuttle_landmark/waypoint_station //This variable is type-abused initially: specify the landmark_tag, not the actual landmark. var/obj/effect/shuttle_landmark/waypoint_offsite //This variable is type-abused initially: specify the landmark_tag, not the actual landmark. - category = /datum/shuttle/autodock/ferry + abstract_type = /datum/shuttle/autodock/ferry /datum/shuttle/autodock/ferry/New(map_hash) if(map_hash) diff --git a/code/modules/shuttles/shuttle_specops.dm b/code/modules/shuttles/shuttle_specops.dm index 41778075e990..90a54b1eab08 100644 --- a/code/modules/shuttles/shuttle_specops.dm +++ b/code/modules/shuttles/shuttle_specops.dm @@ -14,10 +14,7 @@ var/reset_time = 0 //the world.time at which the shuttle will be ready to move again. var/launch_prep = 0 var/cancel_countdown = 0 - category = /datum/shuttle/autodock/ferry/specops - -/datum/shuttle/autodock/ferry/specops/New() - ..() + abstract_type = /datum/shuttle/autodock/ferry/specops /datum/shuttle/autodock/ferry/specops/launch(var/user) if (!can_launch()) @@ -98,7 +95,7 @@ return ..() /datum/shuttle/autodock/ferry/specops/proc/sleep_until_launch() - var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values. + var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a list with potential time values. var/launch_time = world.time + specops_countdown_time var/time_until_launch diff --git a/code/modules/shuttles/shuttle_supply.dm b/code/modules/shuttles/shuttle_supply.dm index 175924860dcb..f38e5fef5b31 100644 --- a/code/modules/shuttles/shuttle_supply.dm +++ b/code/modules/shuttles/shuttle_supply.dm @@ -3,7 +3,7 @@ var/late_chance = 80 var/max_late_time = (30 SECONDS) flags = SHUTTLE_FLAGS_PROCESS|SHUTTLE_FLAGS_SUPPLY|SHUTTLE_FLAGS_NO_CODE - category = /datum/shuttle/autodock/ferry/supply + abstract_type = /datum/shuttle/autodock/ferry/supply ceiling_type = /turf/floor/shuttle_ceiling /datum/shuttle/autodock/ferry/supply/short_jump(var/area/destination) diff --git a/code/modules/shuttles/shuttles_multi.dm b/code/modules/shuttles/shuttles_multi.dm index 35e00c68be6d..71e144e02e27 100644 --- a/code/modules/shuttles/shuttles_multi.dm +++ b/code/modules/shuttles/shuttles_multi.dm @@ -2,7 +2,7 @@ var/list/destination_tags var/list/destinations_cache = list() var/last_cache_rebuild_time = 0 - category = /datum/shuttle/autodock/multi + abstract_type = /datum/shuttle/autodock/multi /datum/shuttle/autodock/multi/New(map_hash) ..() @@ -42,7 +42,7 @@ var/arrival_message var/departure_message - category = /datum/shuttle/autodock/multi/antag + abstract_type = /datum/shuttle/autodock/multi/antag /datum/shuttle/autodock/multi/antag/New(map_hash) ..() diff --git a/code/modules/species/species.dm b/code/modules/species/species.dm index 32980d3c189e..6ef37bd2681e 100644 --- a/code/modules/species/species.dm +++ b/code/modules/species/species.dm @@ -79,10 +79,6 @@ var/global/const/DEFAULT_SPECIES_HEALTH = 200 // Combat vars. var/total_health = DEFAULT_SPECIES_HEALTH // Point at which the mob will enter crit. - var/list/unarmed_attacks = list( // Possible unarmed attacks that the mob will use in combat, - /decl/natural_attack, - /decl/natural_attack/bite - ) var/brute_mod = 1 // Physical damage multiplier. var/burn_mod = 1 // Burn damage multiplier. @@ -492,23 +488,6 @@ var/global/const/DEFAULT_SPECIES_HEALTH = 200 return TRUE //We could tie it to stamina return FALSE -// Called when using the shredding behavior. -/decl/species/proc/can_shred(var/mob/living/human/H, var/ignore_intent, var/ignore_antag) - - if((!ignore_intent && !H.check_intent(I_FLAG_HARM)) || H.pulling_punches) - return 0 - - if(!ignore_antag && H.mind && !player_is_antag(H.mind)) - return 0 - - for(var/attack_type in unarmed_attacks) - var/decl/natural_attack/attack = GET_DECL(attack_type) - if(!istype(attack) || !attack.is_usable(H)) - continue - if(attack.shredding) - return 1 - return 0 - /decl/species/proc/handle_vision(var/mob/living/human/H) var/list/vision = H.get_accumulated_vision_handlers() H.update_sight() diff --git a/code/modules/species/species_attack.dm b/code/modules/species/species_attack.dm index d2daf2daa062..0fffa9846431 100644 --- a/code/modules/species/species_attack.dm +++ b/code/modules/species/species_attack.dm @@ -2,8 +2,8 @@ attack_verb = list("bit", "chomped on") attack_sound = 'sound/weapons/bite.ogg' shredding = 0 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE name = "sharp bite" /decl/natural_attack/claws @@ -14,8 +14,8 @@ eye_attack_text_victim = "sharp claws" attack_sound = 'sound/weapons/slice.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE name = "claws" usable_with_limbs = list(BP_L_HAND, BP_R_HAND) var/blocked_by_gloves = TRUE diff --git a/code/modules/species/species_helpers.dm b/code/modules/species/species_helpers.dm index 5bd257fa5bcd..efd996aaf266 100644 --- a/code/modules/species/species_helpers.dm +++ b/code/modules/species/species_helpers.dm @@ -1,14 +1,9 @@ var/global/list/stored_shock_by_ref = list() /mob/living/proc/apply_stored_shock_to(var/mob/living/target) - if(stored_shock_by_ref["\ref[src]"]) - target.electrocute_act(stored_shock_by_ref["\ref[src]"]*0.9, src) - stored_shock_by_ref["\ref[src]"] = 0 - -/decl/species/proc/toggle_stance(var/mob/living/human/H) - if(!H.incapacitated()) - H.pulling_punches = !H.pulling_punches - to_chat(H, "You are now [H.pulling_punches ? "pulling your punches" : "not pulling your punches"].") + if(global.stored_shock_by_ref["\ref[src]"]) + target.electrocute_act(global.stored_shock_by_ref["\ref[src]"]*0.9, src) + global.stored_shock_by_ref["\ref[src]"] = 0 /decl/species/proc/fluid_act(var/mob/living/human/H, var/datum/reagents/fluids) SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/species/species_hud.dm b/code/modules/species/species_hud.dm index f63a7bc37bf1..7add078db3ac 100644 --- a/code/modules/species/species_hud.dm +++ b/code/modules/species/species_hud.dm @@ -1,6 +1,5 @@ /datum/hud_data - /// Set to draw intent box. - var/show_intent_selector = 1 + /// Set to draw move intent box. var/has_m_intent = 1 /// Set to draw environment warnings. diff --git a/code/modules/species/station/golem.dm b/code/modules/species/station/golem.dm index 9f571d66c608..93dc4786eaeb 100644 --- a/code/modules/species/station/golem.dm +++ b/code/modules/species/station/golem.dm @@ -16,7 +16,6 @@ available_bodytypes = list(/decl/bodytype/crystalline/golem) - unarmed_attacks = list(/decl/natural_attack/stomp, /decl/natural_attack/kick, /decl/natural_attack/punch) species_flags = SPECIES_FLAG_NO_POISON spawn_flags = SPECIES_IS_RESTRICTED shock_vulnerability = 0 diff --git a/code/modules/species/station/human.dm b/code/modules/species/station/human.dm index 6264a7b20482..2ee92427f41f 100644 --- a/code/modules/species/station/human.dm +++ b/code/modules/species/station/human.dm @@ -2,12 +2,6 @@ name = SPECIES_HUMAN name_plural = "Humans" primitive_form = SPECIES_MONKEY - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch, - /decl/natural_attack/bite - ) description = "A medium-sized creature prone to great ambition. If you are reading this, you are probably a human." hidden_from_codex = FALSE spawn_flags = SPECIES_CAN_JOIN diff --git a/code/modules/species/station/monkey.dm b/code/modules/species/station/monkey.dm index 9159f5eadc3c..1871219744e5 100644 --- a/code/modules/species/station/monkey.dm +++ b/code/modules/species/station/monkey.dm @@ -15,7 +15,6 @@ dusted_anim = "dust-m" death_message = "lets out a faint chimper as it collapses and stops moving..." - unarmed_attacks = list(/decl/natural_attack/bite, /decl/natural_attack/claws, /decl/natural_attack/punch) inherent_verbs = list(/mob/living/proc/ventcrawl) species_hud = /datum/hud_data/monkey butchery_data = /decl/butchery_data/humanoid/monkey diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index 1b8ef1751a04..be2f0f6b69dc 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -21,6 +21,12 @@ affected.take_external_damage(20, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) ..() +/decl/surgery_step/cavity/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool, target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(!affected || !BP_IS_PROSTHETIC(affected) || BP_IS_CRYSTAL(affected)) + return ..() + return SURGERY_SKILLS_ROBOTIC + ////////////////////////////////////////////////////////////////// // create implant space surgery step ////////////////////////////////////////////////////////////////// @@ -38,16 +44,16 @@ /decl/surgery_step/cavity/make_space/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) - user.visible_message("[user] starts making some space inside [target]'s [affected.cavity_name] cavity with \the [tool].", \ - "You start making some space inside [target]'s [affected.cavity_name] cavity with \the [tool]." ) + user.visible_message("[user] starts making some space inside [target]'s [affected.cavity_name] with \the [tool].", \ + "You start making some space inside [target]'s [affected.cavity_name] with \the [tool]." ) target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) affected.cavity = TRUE ..() /decl/surgery_step/cavity/make_space/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) - user.visible_message("[user] makes some space inside [target]'s [affected.cavity_name] cavity with \the [tool].", \ - "You make some space inside [target]'s [affected.cavity_name] cavity with \the [tool]." ) + user.visible_message("[user] makes some space inside [target]'s \the [affected.cavity_name] with \the [tool].", \ + "You make some space inside [target]'s \the [affected.cavity_name] with \the [tool]." ) ..() ////////////////////////////////////////////////////////////////// @@ -70,15 +76,15 @@ /decl/surgery_step/cavity/close_space/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) - user.visible_message("[user] starts mending [target]'s [affected.cavity_name] cavity wall with \the [tool].", \ - "You start mending [target]'s [affected.cavity_name] cavity wall with \the [tool]." ) + user.visible_message("[user] starts mending [target]'s \the [affected.cavity_name] wall with \the [tool].", \ + "You start mending [target]'s \the [affected.cavity_name] wall with \the [tool]." ) target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) ..() /decl/surgery_step/cavity/close_space/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) - user.visible_message("[user] mends [target]'s [affected.cavity_name] cavity walls with \the [tool].", \ - "You mend [target]'s [affected.cavity_name] cavity walls with \the [tool]." ) + user.visible_message("[user] mends [target]'s \the [affected.cavity_name] walls with \the [tool].", \ + "You mend [target]'s \the [affected.cavity_name] walls with \the [tool]." ) affected.cavity = FALSE ..() @@ -109,7 +115,7 @@ if(affected && affected.cavity) var/max_volume = BASE_STORAGE_CAPACITY(affected.cavity_max_w_class) + affected.internal_organs_size if(tool.w_class > affected.cavity_max_w_class) - to_chat(user, SPAN_WARNING("\The [tool] is too big for [affected.cavity_name] cavity.")) + to_chat(user, SPAN_WARNING("\The [tool] is too big for \the [affected.cavity_name].")) return FALSE var/total_volume = tool.get_storage_cost() for(var/obj/item/I in affected.implants) @@ -119,14 +125,14 @@ for(var/obj/item/organ/internal/org in affected.internal_organs) max_volume -= org.get_storage_cost() if(total_volume > max_volume) - to_chat(user, SPAN_WARNING("There isn't enough space left in [affected.cavity_name] cavity for [tool].")) + to_chat(user, SPAN_WARNING("There isn't enough space left in \the [affected.cavity_name] for [tool].")) return FALSE return TRUE /decl/surgery_step/cavity/place_item/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) - user.visible_message("[user] starts putting \the [tool] inside [target]'s [affected.cavity_name] cavity.", \ - "You start putting \the [tool] inside [target]'s [affected.cavity_name] cavity." ) + user.visible_message("[user] starts putting \the [tool] inside [target]'s \the [affected.cavity_name].", \ + "You start putting \the [tool] inside [target]'s \the [affected.cavity_name]." ) target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) ..() @@ -134,8 +140,8 @@ var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(!user.try_unequip(tool, affected)) return - user.visible_message("[user] puts \the [tool] inside [target]'s [affected.cavity_name] cavity.", \ - "You put \the [tool] inside [target]'s [affected.cavity_name] cavity." ) + user.visible_message("[user] puts \the [tool] inside [target]'s \the [affected.cavity_name].", \ + "You put \the [tool] inside [target]'s \the [affected.cavity_name]." ) if (tool.w_class > affected.cavity_max_w_class/2 && prob(50) && !BP_IS_PROSTHETIC(affected) && affected.sever_artery()) to_chat(user, "You tear some blood vessels trying to fit such a big object in this cavity.") affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1,affecting = affected) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 916db17c1d2b..76b37e9eb8dd 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -262,7 +262,7 @@ return FALSE if(O.w_class > affected.cavity_max_w_class) - to_chat(user, SPAN_WARNING("\The [O.name] [pronouns.is] too big for [affected.cavity_name] cavity!")) + to_chat(user, SPAN_WARNING("\The [O.name] [pronouns.is] too big for \the [affected.cavity_name]!")) return FALSE var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(target, O.organ_tag) diff --git a/code/modules/tools/archetypes/tool_archetype_definitions.dm b/code/modules/tools/archetypes/tool_archetype_definitions.dm index 25df48e3afda..2b2b2f14f4d6 100644 --- a/code/modules/tools/archetypes/tool_archetype_definitions.dm +++ b/code/modules/tools/archetypes/tool_archetype_definitions.dm @@ -70,16 +70,16 @@ /decl/tool_archetype/knife/get_default_quality(obj/item/tool) if(tool) - if(tool.sharp && tool.edge) + if(tool.is_sharp() && tool.has_edge()) return TOOL_QUALITY_DEFAULT - else if(tool.sharp || tool.edge) + else if(tool.is_sharp() || tool.has_edge()) return TOOL_QUALITY_MEDIOCRE return ..() /decl/tool_archetype/knife/get_default_speed(obj/item/tool) if(tool) - if(tool.sharp && tool.edge) + if(tool.is_sharp() && tool.has_edge()) return TOOL_SPEED_DEFAULT - else if(tool.sharp || tool.edge) + else if(tool.is_sharp() || tool.has_edge()) return TOOL_SPEED_MEDIOCRE return ..() diff --git a/code/modules/tools/subtypes/hammers.dm b/code/modules/tools/subtypes/hammers.dm index 79e5e26956dc..ff5d1ef19892 100644 --- a/code/modules/tools/subtypes/hammers.dm +++ b/code/modules/tools/subtypes/hammers.dm @@ -2,8 +2,6 @@ name = "hammer" desc = "A simple hammer. Ancient technology once thought lost." icon = 'icons/obj/items/tool/hammers/hammer.dmi' - sharp = 0 - edge = 0 attack_verb = list( "bludgeons", "slaps", diff --git a/code/modules/tools/subtypes/xenoarchaeology_picks.dm b/code/modules/tools/subtypes/xenoarchaeology_picks.dm index 9db2d59f5418..2a335b9fa4ca 100644 --- a/code/modules/tools/subtypes/xenoarchaeology_picks.dm +++ b/code/modules/tools/subtypes/xenoarchaeology_picks.dm @@ -7,7 +7,7 @@ material = /decl/material/solid/metal/chromium matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY) w_class = ITEM_SIZE_SMALL - sharp = 1 + sharp = TRUE abstract_type = /obj/item/tool/xeno material_alteration = 0 handle_material = /decl/material/solid/organic/plastic @@ -36,18 +36,18 @@ to_chat(user, "This tool has a [get_tool_property(TOOL_PICK, TOOL_PROP_EXCAVATION_DEPTH) || 0] centimetre excavation depth.") /obj/item/tool/xeno/brush - name = "wire brush" - icon_state = "pick_brush" - slot_flags = SLOT_EARS - _base_attack_force = 1 - attack_verb = list("prodded", "attacked") - desc = "A wood-handled brush with thick metallic wires for clearing away dust and loose scree." - sharp = 0 - material = /decl/material/solid/metal/steel - handle_material = /decl/material/solid/organic/wood/oak - excavation_amount = 1 - excavation_sound = "sweeping" - excavation_verb = "brushing" + name = "wire brush" + icon_state = "pick_brush" + slot_flags = SLOT_EARS + _base_attack_force = 1 + attack_verb = list("prodded", "attacked") + desc = "A wood-handled brush with thick metallic wires for clearing away dust and loose scree." + sharp = FALSE + material = /decl/material/solid/metal/steel + handle_material = /decl/material/solid/organic/wood/oak + excavation_amount = 1 + excavation_sound = "sweeping" + excavation_verb = "brushing" /obj/item/tool/xeno/one_pick name = "2cm pick" diff --git a/code/modules/tools/tool.dm b/code/modules/tools/tool.dm index 889d2ab199d9..953a751ebbb2 100644 --- a/code/modules/tools/tool.dm +++ b/code/modules/tools/tool.dm @@ -6,7 +6,6 @@ w_class = ITEM_SIZE_NORMAL origin_tech = @'{"materials":1,"engineering":1}' attack_verb = list("hit", "pierced", "sliced", "attacked") - sharp = 0 abstract_type = /obj/item/tool material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC _base_attack_force = 10 diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index edfc8efaba4a..1098bd2bf01b 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -115,10 +115,10 @@ // physical damage types that can impart force; swinging a bat or energy sword switch(weapon.atom_damage_type) if(BURN) - current_health -= weapon.get_attack_force(user) * fire_dam_coeff + current_health -= weapon.expend_attack_force(user) * fire_dam_coeff . = TRUE if(BRUTE) - current_health -= weapon.get_attack_force(user) * brute_dam_coeff + current_health -= weapon.expend_attack_force(user) * brute_dam_coeff . = TRUE else . = FALSE @@ -144,23 +144,17 @@ healthcheck() /obj/vehicle/emp_act(severity) - var/was_on = on + addtimer(CALLBACK(src, PROC_REF(end_emp), on), severity * 30 SECONDS) stat |= EMPED - var/obj/effect/overlay/pulse2 = new /obj/effect/overlay(loc) - pulse2.icon = 'icons/effects/effects.dmi' - pulse2.icon_state = "empdisable" - pulse2.SetName("emp sparks") - pulse2.anchored = TRUE - pulse2.set_dir(pick(global.cardinal)) - - spawn(10) - qdel(pulse2) + var/obj/effect/temp_visual/emp_burst/burst = new /obj/effect/temp_visual/emp_burst(loc) + burst.set_dir(pick(global.cardinal)) if(on) turn_off() - spawn(severity*300) - stat &= ~EMPED - if(was_on) - turn_on() + +/obj/vehicle/proc/end_emp(was_on) + stat &= ~EMPED + if(was_on) + turn_on() /obj/vehicle/attack_ai(mob/living/silicon/ai/user) return diff --git a/code/modules/xenoarcheaology/artifacts/triggers/force.dm b/code/modules/xenoarcheaology/artifacts/triggers/force.dm index c8003f314e72..97a771745f11 100644 --- a/code/modules/xenoarcheaology/artifacts/triggers/force.dm +++ b/code/modules/xenoarcheaology/artifacts/triggers/force.dm @@ -7,7 +7,7 @@ var/obj/item/projectile/hit_projectile = hit_with return (hit_projectile.atom_damage_type == BRUTE) else if(istype(hit_with, /obj/item)) - return (hit_with.get_attack_force(user) >= 10) + return (hit_with.expend_attack_force(user) >= 10) /datum/artifact_trigger/force/on_explosion(severity) return TRUE diff --git a/code/modules/xenoarcheaology/tools/core_sampler.dm b/code/modules/xenoarcheaology/tools/core_sampler.dm index 01b4f1401e5d..21d5bd0cb6dd 100644 --- a/code/modules/xenoarcheaology/tools/core_sampler.dm +++ b/code/modules/xenoarcheaology/tools/core_sampler.dm @@ -51,7 +51,7 @@ icon_state = "sliver1" randpixel = 8 w_class = ITEM_SIZE_TINY - sharp = 1 + sharp = TRUE material = /decl/material/solid/stone/sandstone material_health_multiplier = 0.25 diff --git a/code/unit_tests/_template.dm b/code/unit_tests/_template.dm index 556941cb1ce5..36dc0ddfa189 100644 --- a/code/unit_tests/_template.dm +++ b/code/unit_tests/_template.dm @@ -7,8 +7,8 @@ /datum/unit_test/template name = "Test Template - Change My name" - template = /datum/unit_test/template // Set this var equal to the test path to treat it as a template, i.e. it should not be run - async = 1 // Set if we should continue testing elsewhere and come back and check on the results. + abstract_type = /datum/unit_test/template // Set this var equal to the test path to treat it as a template, i.e. it should not be run + async = 1 // Set if we should continue testing elsewhere and come back and check on the results. /datum/unit_test/template/start_test() diff --git a/code/unit_tests/atmospherics_tests.dm b/code/unit_tests/atmospherics_tests.dm index 5a9c69c15cf1..46837d818bf5 100644 --- a/code/unit_tests/atmospherics_tests.dm +++ b/code/unit_tests/atmospherics_tests.dm @@ -2,7 +2,7 @@ Unit tests for ATMOSPHERICS primitives */ /datum/unit_test/atmos_machinery - template = /datum/unit_test/atmos_machinery + abstract_type = /datum/unit_test/atmos_machinery var/list/test_cases = list() /datum/unit_test/atmos_machinery/proc/create_gas_mixes(gas_mix_data) @@ -60,7 +60,7 @@ pass("[case_name]: conserved moles of each gas ID.") /datum/unit_test/atmos_machinery/conserve_moles - template = /datum/unit_test/atmos_machinery/conserve_moles + abstract_type = /datum/unit_test/atmos_machinery/conserve_moles test_cases = list( uphill = list( source = list( diff --git a/code/unit_tests/chemistry_tests.dm b/code/unit_tests/chemistry_tests.dm index bb6e9d904773..cdc9dae00d42 100644 --- a/code/unit_tests/chemistry_tests.dm +++ b/code/unit_tests/chemistry_tests.dm @@ -1,6 +1,6 @@ /datum/unit_test/chemistry name = "CHEMISTRY: Reagent Template" - template = /datum/unit_test/chemistry + abstract_type = /datum/unit_test/chemistry var/container_volume = 45 var/donor_type = /obj/item diff --git a/code/unit_tests/del_the_world.dm b/code/unit_tests/del_the_world.dm index 93591ed1d01e..411ef21b8d33 100644 --- a/code/unit_tests/del_the_world.dm +++ b/code/unit_tests/del_the_world.dm @@ -39,58 +39,52 @@ continue qdel(to_del, force = TRUE) // I hate borg stacks I hate borg stacks AM = null // this counts as a reference to the last item if we don't explicitly clear it?? + del_candidates.Cut() // this also?? // Check for hanging references. SSticker.delay_end = TRUE // Don't end the round while we wait! - // No harddels during this test. - SSgarbage.collection_timeout[GC_QUEUE_HARDDELETE] = 6 HOURS // github CI timeout length + // Drastically lower the amount of time it takes to GC, since we don't have clients that can hold it up. + SSgarbage.collection_timeout[GC_QUEUE_CHECK] = 10 SECONDS cached_contents.Cut() + var/list/queues_we_care_about = list() + // All of em, I want hard deletes too, since we rely on the debug info from them + for(var/i in 1 to GC_QUEUE_HARDDELETE) + queues_we_care_about += i + + //Now that we've qdel'd everything, let's sleep until the gc has processed all the shit we care about + // + 2 seconds to ensure that everything gets in the queue. + var/time_needed = 2 SECONDS + for(var/index in queues_we_care_about) + time_needed += SSgarbage.collection_timeout[index] + // track start time so we know anything deleted after this point isn't ours var/start_time = world.time - // spin until the first item in the filter queue is older than start_time - var/filter_queue_finished = FALSE - var/list/filter_queue = SSgarbage.queues[GC_QUEUE_FILTER] - while(!filter_queue_finished) - if(!length(filter_queue)) - filter_queue_finished = TRUE - break - var/list/oldest_packet = filter_queue[1] - //Pull out the time we inserted at - var/qdel_time = oldest_packet[GC_QUEUE_ITEM_GCD_DESTROYED] - if(qdel_time > start_time) // Everything is in the check queue now! - filter_queue_finished = TRUE - break - if(world.time > start_time + 2 MINUTES) - fail("Something has gone horribly wrong, the filter queue has been processing for well over 2 minutes. What the hell did you do??") - break - // We want to fire every time. - SSgarbage.next_fire = 1 - sleep(2 SECONDS) - // We need to check the check queue now. - start_time = world.time - // sleep until SSgarbage has run through the queue - var/time_needed = SSgarbage.collection_timeout[GC_QUEUE_CHECK] - sleep(time_needed) - // taken verbatim from TG's Del The World + var/real_start_time = REALTIMEOFDAY var/garbage_queue_processed = FALSE - var/list/check_queue = SSgarbage.queues[GC_QUEUE_CHECK] + + sleep(time_needed) while(!garbage_queue_processed) - //How the hell did you manage to empty this? Good job! - if(!length(check_queue)) - garbage_queue_processed = TRUE - break + var/oldest_packet_creation = INFINITY + for(var/index in queues_we_care_about) + var/list/queue_to_check = SSgarbage.queues[index] + if(!length(queue_to_check)) + continue + + var/list/oldest_packet = queue_to_check[1] + //Pull out the time we inserted at + var/qdeld_at = oldest_packet[GC_QUEUE_ITEM_GCD_DESTROYED] + + oldest_packet_creation = min(qdeld_at, oldest_packet_creation) - var/list/oldest_packet = check_queue[1] - //Pull out the time we inserted at - var/qdeld_at = oldest_packet[GC_QUEUE_ITEM_GCD_DESTROYED] //If we've found a packet that got del'd later then we finished, then all our shit has been processed - if(qdeld_at > start_time) + //That said, if there are any pending hard deletes you may NOT sleep, we gotta handle that shit + if(oldest_packet_creation > start_time && !length(SSgarbage.queues[GC_QUEUE_HARDDELETE])) garbage_queue_processed = TRUE break - if(world.time > start_time + time_needed + 8 MINUTES) - fail("The garbage queue has been processing for well over 10 minutes. Something is likely broken.") + if(REALTIMEOFDAY > real_start_time + time_needed + 30 MINUTES) //If this gets us gitbanned I'm going to laugh so hard + fail("Something has gone horribly wrong, the garbage queue has been processing for well over 30 minutes. What the hell did you do") break //Immediately fire the gc right after diff --git a/code/unit_tests/equipment_tests.dm b/code/unit_tests/equipment_tests.dm index 25146ab9251b..dac446856e8b 100644 --- a/code/unit_tests/equipment_tests.dm +++ b/code/unit_tests/equipment_tests.dm @@ -1,42 +1,37 @@ /datum/unit_test/vision_glasses name = "EQUIPMENT: Vision Template" - template = /datum/unit_test/vision_glasses - var/mob/living/human/H = null + abstract_type = /datum/unit_test/vision_glasses + var/mob/living/human/subject = null var/expectation = SEE_INVISIBLE_NOLIGHTING var/glasses_type = null async = 1 /datum/unit_test/vision_glasses/start_test() - var/list/test = create_test_mob_with_mind(get_safe_turf(), /mob/living/human) - if(isnull(test)) - fail("Check Runtimed in Mob creation") - - if(test["result"] == FAILURE) - fail(test["msg"]) - async = 0 - return 0 - - H = locate(test["mobref"]) - H.equip_to_slot(new glasses_type(H), slot_glasses_str) + subject = new(get_safe_turf(), SPECIES_HUMAN) // force human so default map species doesn't mess with anything + subject.equip_to_slot(new glasses_type(subject), slot_glasses_str) return 1 /datum/unit_test/vision_glasses/check_result() - if(isnull(H) || H.life_tick < 2) + if(isnull(subject) || subject.life_tick < 2) return 0 - if(isnull(H.get_equipped_item(slot_glasses_str))) + if(isnull(subject.get_equipped_item(slot_glasses_str))) fail("Mob doesn't have glasses on") - H.handle_vision() // Because Life has a client check that bypasses updating vision + subject.handle_vision() // Because Life has a client check that bypasses updating vision - if(H.see_invisible == expectation) - pass("Mob See invisible is [H.see_invisible]") + if(subject.see_invisible == expectation) + pass("Mob See invisible is [subject.see_invisible]") else - fail("Mob See invisible is [H.see_invisible] / expected [expectation]") + fail("Mob See invisible is [subject.see_invisible] / expected [expectation]") return 1 +/datum/unit_test/vision_glasses/teardown_test() + QDEL_NULL(subject) + . = ..() + /datum/unit_test/vision_glasses/NVG name = "EQUIPMENT: NVG see_invis" glasses_type = /obj/item/clothing/glasses/night diff --git a/code/unit_tests/extension_tests.dm b/code/unit_tests/extension_tests.dm index 49f9769fa431..2a7724e3cc7b 100644 --- a/code/unit_tests/extension_tests.dm +++ b/code/unit_tests/extension_tests.dm @@ -1,6 +1,6 @@ /datum/unit_test/extensions name = "EXTENSIONS template" - template = /datum/unit_test/extensions + abstract_type = /datum/unit_test/extensions async = 0 /datum/unit_test/extensions/basic_extension_shall_lazy_initalize_as_expected diff --git a/code/unit_tests/foundation_tests.dm b/code/unit_tests/foundation_tests.dm index 66fb31643b33..27196ec37ff8 100644 --- a/code/unit_tests/foundation_tests.dm +++ b/code/unit_tests/foundation_tests.dm @@ -3,7 +3,7 @@ */ /datum/unit_test/foundation name = "FOUNDATION template" - template = /datum/unit_test/foundation + abstract_type = /datum/unit_test/foundation async = 0 /datum/unit_test/foundation/step_shall_return_true_on_success diff --git a/code/unit_tests/graph_tests.dm b/code/unit_tests/graph_tests.dm index 1d1cd69b6219..47cdb388f629 100644 --- a/code/unit_tests/graph_tests.dm +++ b/code/unit_tests/graph_tests.dm @@ -430,7 +430,7 @@ * Base Test Setup * ******************/ /datum/unit_test/graph_test - template = /datum/unit_test/graph_test + abstract_type = /datum/unit_test/graph_test async = TRUE var/list/graphs @@ -489,6 +489,7 @@ /atom/movable/graph_test/Destroy() QDEL_NULL(node) + neighboursByDirection.Cut() return ..() /atom/movable/graph_test/forceMove() @@ -524,7 +525,7 @@ var/on_split_was_called var/issues -/datum/graph/testing/New(var/node, var/edges, var/name) +/datum/graph/testing/New(var/node, var/edges, var/previous_owner, var/name) ..() src.name = name || "Graph" issues = list() @@ -558,8 +559,10 @@ /datum/graph/testing/proc/CheckExpectations() if(on_check_expectations) issues += DoCheckExpectations(on_check_expectations) + QDEL_NULL(on_check_expectations) // stop holding up GC! if(length(split_expectations) && !on_split_was_called) issues += "Had split expectations but OnSplit was not called" + QDEL_LIST(split_expectations) // stop holding up GC! if(!length(split_expectations) && on_split_was_called) issues += "Had no split expectations but OnSplit was called" if(expecting_merge != on_merge_was_called) @@ -576,6 +579,11 @@ src.expected_nodes = expected_nodes || list() src.expected_edges = expected_edges || list() +/datum/graph_expectation/Destroy(force) + expected_nodes.Cut() + expected_edges.Cut() + return ..() + // Stub for subtype-specific functionality for DoCheckExpectations. // Should not access graph.nodes or graph.edges. /datum/graph_expectation/proc/OnCheckExpectations(var/datum/graph/graph) diff --git a/code/unit_tests/icon_tests.dm b/code/unit_tests/icon_tests.dm index 58783a20f51c..279daba8a344 100644 --- a/code/unit_tests/icon_tests.dm +++ b/code/unit_tests/icon_tests.dm @@ -1,6 +1,6 @@ /datum/unit_test/icon_test name = "ICON STATE template" - template = /datum/unit_test/icon_test + abstract_type = /datum/unit_test/icon_test /datum/unit_test/icon_test/food_shall_have_icon_states name = "ICON STATE: Food And Drink Subtypes Shall Have Icon States" diff --git a/code/unit_tests/integrated_circuits.dm b/code/unit_tests/integrated_circuits.dm index 79c26d52a3a8..84de2ac2ff34 100644 --- a/code/unit_tests/integrated_circuits.dm +++ b/code/unit_tests/integrated_circuits.dm @@ -1,5 +1,5 @@ /datum/unit_test/integrated_circuits - template = /datum/unit_test/integrated_circuits + abstract_type = /datum/unit_test/integrated_circuits /datum/unit_test/integrated_circuits/unique_names name = "INTEGRATED CIRCUITS: Circuits must have unique names" @@ -64,7 +64,7 @@ /datum/unit_test/integrated_circuits/input_output name = "INTEGRATED CIRCUITS: INPUT/OUTPUT - TEMPLATE" - template = /datum/unit_test/integrated_circuits/input_output + abstract_type = /datum/unit_test/integrated_circuits/input_output var/list/all_inputs = list() var/list/all_expected_outputs = list() var/activation_pin = 1 diff --git a/code/unit_tests/map_tests.dm b/code/unit_tests/map_tests.dm index 2803ba8db097..89238fa88d21 100644 --- a/code/unit_tests/map_tests.dm +++ b/code/unit_tests/map_tests.dm @@ -503,6 +503,28 @@ //======================================================================================= +// These vars are used to avoid in-world loops in the following unit test. +var/global/_unit_test_disposal_segments = list() +var/global/_unit_test_sort_junctions = list() + +#ifdef UNIT_TEST +/obj/structure/disposalpipe/segment/Initialize(mapload) + . = ..() + _unit_test_disposal_segments += src + +/obj/structure/disposalpipe/segment/Destroy() + _unit_test_disposal_segments -= src + return ..() + +/obj/structure/disposalpipe/sortjunction/Initialize(mapload) + . = ..() + _unit_test_sort_junctions += src + +/obj/structure/disposalpipe/sortjunction/Destroy() + _unit_test_sort_junctions -= src + return ..() +#endif + /datum/unit_test/disposal_segments_shall_connect_with_other_disposal_pipes name = "MAP: Disposal segments shall connect with other disposal pipes" @@ -522,7 +544,7 @@ num2text(SOUTH) = list(list(SOUTH, list(NORTH, WEST)), list(EAST, list(NORTH, EAST))), num2text(WEST) = list(list(EAST, list(NORTH, EAST)), list(SOUTH, list(SOUTH, EAST)))) - for(var/obj/structure/disposalpipe/segment/D in world) + for(var/obj/structure/disposalpipe/segment/D in _unit_test_disposal_segments) if(!D.loc) continue if(D.icon_state == "pipe-s") @@ -760,7 +782,7 @@ /datum/unit_test/networked_disposals_shall_deliver_tagged_packages/start_test() . = 1 var/fail = FALSE - for(var/obj/structure/disposalpipe/sortjunction/sort in world) + for(var/obj/structure/disposalpipe/sortjunction/sort in _unit_test_sort_junctions) if(!sort.loc) continue if(is_type_in_list(sort, exempt_junctions)) diff --git a/code/unit_tests/mob_tests.dm b/code/unit_tests/mob_tests.dm index 0228ea803411..2f03eb9da320 100644 --- a/code/unit_tests/mob_tests.dm +++ b/code/unit_tests/mob_tests.dm @@ -58,21 +58,9 @@ // ============================================================================ -var/global/default_mobloc = null - -/proc/create_test_mob_with_mind(var/turf/mobloc = null, var/mobtype = /mob/living/human) +/datum/unit_test/mob_damage/proc/create_test_mob_with_mind(var/turf/mobloc, var/mobtype = /mob/living/human) var/list/test_result = list("result" = FAILURE, "msg" = "", "mobref" = null) - if(isnull(mobloc)) - if(!default_mobloc) - for(var/turf/floor/tiled/T in world) - if(!T.zone?.air) - continue - var/pressure = T.zone.air.return_pressure() - if(90 < pressure && pressure < 120) // Find a turf between 90 and 120 - default_mobloc = T - break - mobloc = default_mobloc if(!mobloc) test_result["msg"] = "Unable to find a location to create test mob" return test_result @@ -129,7 +117,7 @@ var/global/default_mobloc = null /datum/unit_test/mob_damage name = "MOB: Template for mob damage" - template = /datum/unit_test/mob_damage + abstract_type = /datum/unit_test/mob_damage var/damagetype = BRUTE var/mob_type = /mob/living/human var/expected_vulnerability = STANDARD diff --git a/code/unit_tests/movement_tests.dm b/code/unit_tests/movement_tests.dm index 8d45dbe20cfb..dbcb2bc44991 100644 --- a/code/unit_tests/movement_tests.dm +++ b/code/unit_tests/movement_tests.dm @@ -1,6 +1,6 @@ /datum/unit_test/movement name = "MOVEMENT template" - template = /datum/unit_test/movement + abstract_type = /datum/unit_test/movement async = 0 /datum/unit_test/movement/force_move_shall_trigger_crossed_when_entering_turf diff --git a/code/unit_tests/observation_tests.dm b/code/unit_tests/observation_tests.dm index b9174d26fe87..829bc7435764 100644 --- a/code/unit_tests/observation_tests.dm +++ b/code/unit_tests/observation_tests.dm @@ -4,7 +4,7 @@ /datum/unit_test/observation name = "OBSERVATION template" - template = /datum/unit_test/observation + abstract_type = /datum/unit_test/observation async = 0 var/list/received_moves var/list/received_name_set_events diff --git a/code/unit_tests/override_tests.dm b/code/unit_tests/override_tests.dm index 2c8d6bc47cca..4687b0c72aaa 100644 --- a/code/unit_tests/override_tests.dm +++ b/code/unit_tests/override_tests.dm @@ -2,7 +2,7 @@ /datum/unit_test/override name = "OVERRIDE template" - template = /datum/unit_test/override + abstract_type = /datum/unit_test/override /datum/unit_test/override/obj_random_shall_spawn_heaviest_item name = "OVERRIDE: obj/random shall spawn heaviest item" diff --git a/code/unit_tests/proximity_tests.dm b/code/unit_tests/proximity_tests.dm index b77946ec7397..b405a2c3db25 100644 --- a/code/unit_tests/proximity_tests.dm +++ b/code/unit_tests/proximity_tests.dm @@ -2,7 +2,7 @@ * Template Setup * *****************/ /datum/unit_test/proximity - template = /datum/unit_test/proximity + abstract_type = /datum/unit_test/proximity var/turf/wall/wall var/obj/proximity_listener/proximity_listener @@ -24,7 +24,7 @@ wall.set_opacity(opacity) /datum/unit_test/proximity/visibility - template = /datum/unit_test/proximity/visibility + abstract_type = /datum/unit_test/proximity/visibility var/list/expected_number_of_turfs_by_trigger_type /datum/unit_test/proximity/visibility/start_test() diff --git a/code/unit_tests/time_tests.dm b/code/unit_tests/time_tests.dm index 2dbf636d1e91..55a17518a603 100644 --- a/code/unit_tests/time_tests.dm +++ b/code/unit_tests/time_tests.dm @@ -1,6 +1,6 @@ /datum/unit_test/time name = "TIME: Template" - template = /datum/unit_test/time + abstract_type = /datum/unit_test/time /datum/unit_test/time/shall_validate_sixth_of_june name = "TIME: Shall validate 6th of June" diff --git a/code/unit_tests/unit_test.dm b/code/unit_tests/unit_test.dm index 4fe4fedfdc5c..24fd800c8544 100644 --- a/code/unit_tests/unit_test.dm +++ b/code/unit_tests/unit_test.dm @@ -4,7 +4,7 @@ * For the most part I think any test can be created that doesn't require a client in a mob or require a game mode other then extended * * The easiest way to make effective tests is to create a "template" if you intend to run the same test over and over and make your actual - * tests be a "child object" of those templates. Be sure and name your templates with the word "template" somewhere in var/name. + * tests be a "child object" of those templates. Be sure to set abstract_type on your template type. * * The goal is to have all sorts of tests that run and to run them as quickly as possible. * @@ -51,8 +51,8 @@ var/global/ascii_reset = "[ascii_esc]\[0m" // Templates aren't intended to be ran but just serve as a way to create child objects of it with inheritable tests for quick test creation. /datum/unit_test + abstract_type = /datum/unit_test var/name = "template - should not be ran." - var/template // Treat the unit test as a template if its type is the same as the value of this var var/disabled = 0 // If we want to keep a unit test in the codebase but not run it for some reason. var/async = 0 // If the check can be left to do it's own thing, you must define a check_result() proc if you use this. var/reported = 0 // If it's reported a success or failure. Any tests that have not are assumed to be failures. @@ -157,11 +157,10 @@ var/global/ascii_reset = "[ascii_esc]\[0m" /proc/get_test_datums() . = list() - for(var/test in subtypesof(/datum/unit_test)) - var/datum/unit_test/d = test - if(test == initial(d.template)) + for(var/datum/unit_test/test as anything in subtypesof(/datum/unit_test)) + if(TYPE_IS_ABSTRACT(test)) continue - . += d + . += test /proc/do_unit_test(datum/unit_test/test, end_time, skip_disabled_tests = TRUE) if(test.disabled && skip_disabled_tests) diff --git a/code/unit_tests/virtual_mob_tests.dm b/code/unit_tests/virtual_mob_tests.dm index dab89f395ec8..718bf0107483 100644 --- a/code/unit_tests/virtual_mob_tests.dm +++ b/code/unit_tests/virtual_mob_tests.dm @@ -1,10 +1,10 @@ /datum/unit_test/virtual name = "VIRTUAL: Template" - template = /datum/unit_test/virtual + abstract_type = /datum/unit_test/virtual /datum/unit_test/virtual/helper name = "VIRTUAL: Template Helper" - template = /datum/unit_test/virtual/helper + abstract_type = /datum/unit_test/virtual/helper var/helper_proc var/list/expected_mobs diff --git a/code/unit_tests/zas_tests.dm b/code/unit_tests/zas_tests.dm index b83f880bff9e..7866c78bd62a 100644 --- a/code/unit_tests/zas_tests.dm +++ b/code/unit_tests/zas_tests.dm @@ -12,7 +12,7 @@ /datum/unit_test/zas_area_test name = "ZAS: Area Test Template" - template = /datum/unit_test/zas_area_test + abstract_type = /datum/unit_test/zas_area_test var/area_path = null // Put the area you are testing here. var/expectation = UT_NORMAL // See defines above. diff --git a/code/world.dm b/code/world.dm index 361fa6c4a150..057199cfb0a5 100644 --- a/code/world.dm +++ b/code/world.dm @@ -12,6 +12,9 @@ hub = "Exadv1.spacestation13" icon_size = WORLD_ICON_SIZE fps = 20 -#ifdef GC_FAILURE_HARD_LOOKUP +#ifdef FIND_REF_NO_CHECK_TICK +#pragma push +#pragma ignore loop_checks loop_checks = FALSE +#pragma pop #endif diff --git a/html/changelog.html b/html/changelog.html index 58aeb978adc1..23cae88f2087 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -52,6 +52,25 @@ -->
+

22 January 2025

+

MistakeNot4892 updated:

+ + +

21 January 2025

+

Penelope Haze updated:

+ + +

19 January 2025

+

MistakeNot4892 updated:

+ +

16 January 2025

MistakeNot4892 updated:

diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 65ecf2cbcfd8..20e1bd55f284 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -14959,3 +14959,15 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. overlay color. - tweak: The Shaded Hills river now flows north. - tweak: Snow, mud and sand will now show footprints. +2025-01-19: + MistakeNot4892: + - tweak: Intents have been rewritten and moved, please report any issues with intent + selection. +2025-01-21: + Penelope Haze: + - tweak: Mud can now receive footprints with any reagent other than mud. No more + conspicuously missing bloody footprints! +2025-01-22: + MistakeNot4892: + - tweak: Swords on Shaded Hills can be sharpened using whetstones or grindstones. + - tweak: Guns can now be fired from rigs regardless of dexterity. diff --git a/html/changelogs/AutoChangeLog-pr-4748.yml b/html/changelogs/AutoChangeLog-pr-4748.yml deleted file mode 100644 index 36462616a457..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4748.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: MistakeNot4892 -changes: - - {tweak: 'Intents have been rewritten and moved, please report any issues with - intent selection.'} -delete-after: true diff --git a/icons/clothing/spacesuit/void/medical_alt/suit.dmi b/icons/clothing/spacesuit/void/medical_alt/suit.dmi index 77b79193e46a..634b67420791 100644 Binary files a/icons/clothing/spacesuit/void/medical_alt/suit.dmi and b/icons/clothing/spacesuit/void/medical_alt/suit.dmi differ diff --git a/maps/antag_spawn/ert/ert_base.dmm b/maps/antag_spawn/ert/ert_base.dmm index e105bb2c1a8c..703d909d0c3a 100644 --- a/maps/antag_spawn/ert/ert_base.dmm +++ b/maps/antag_spawn/ert/ert_base.dmm @@ -1195,10 +1195,6 @@ /obj/machinery/vending/medical, /turf/unsimulated/wall, /area/map_template/rescue_base/base) -"dj" = ( -/obj/effect/wingrille_spawn/reinforced/crescent, -/turf/space, -/area/map_template/rescue_base/base) "dk" = ( /obj/machinery/door/airlock/centcom{ name = "EVA" @@ -4269,7 +4265,7 @@ ar cH ar cS -dj +bg ao ao bg @@ -4334,7 +4330,7 @@ ar cI ar cT -dj +bg ao ao bg @@ -4399,7 +4395,7 @@ ar ar ar cU -dj +bg ao ao bg @@ -4464,7 +4460,7 @@ cy cJ cO cV -dj +bg ao ao ad diff --git a/maps/away/errant_pisces/errant_pisces.dm b/maps/away/errant_pisces/errant_pisces.dm index 82cba1ab1eb6..98b02fae56ab 100644 --- a/maps/away/errant_pisces/errant_pisces.dm +++ b/maps/away/errant_pisces/errant_pisces.dm @@ -112,9 +112,9 @@ return SPAN_NOTICE("A few strands of \the [src] have been severed.") /obj/structure/net/attackby(obj/item/W, mob/user) - if(W.sharp || W.edge) - var/force = W.get_attack_force(user) - if (!(W.sharp) || (W.sharp && force < 10))//is not sharp enough or at all + if(W.is_sharp() || W.has_edge()) + var/force = W.expend_attack_force(user) + if (!(W.is_sharp()) || (W.is_sharp() && force < 10))//is not sharp enough or at all to_chat(user,"You can't cut through \the [src] with \the [W], it's too dull.") return TRUE visible_message("[user] starts to cut through \the [src] with \the [W]!") diff --git a/maps/away/lost_supply_base/lost_supply_base.dmm b/maps/away/lost_supply_base/lost_supply_base.dmm index aac57b9b881e..55d862015336 100644 --- a/maps/away/lost_supply_base/lost_supply_base.dmm +++ b/maps/away/lost_supply_base/lost_supply_base.dmm @@ -1982,7 +1982,7 @@ /turf/unsimulated/mask, /area/mine/unexplored) "gu" = ( -/turf/floor, +/turf/floor/barren, /area/mine/explored) "ib" = ( /obj/structure/hygiene/sink{ diff --git a/maps/away/mining/mining-asteroid.dmm b/maps/away/mining/mining-asteroid.dmm index 63713ba44342..89a0612365c1 100644 --- a/maps/away/mining/mining-asteroid.dmm +++ b/maps/away/mining/mining-asteroid.dmm @@ -6,14 +6,14 @@ /turf/unsimulated/mask, /area/mine/unexplored) "af" = ( -/turf/floor, +/turf/floor/barren, /area/mine/explored) "aj" = ( /turf/wall/r_wall, /area/djstation) "ak" = ( /obj/random/junk, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "al" = ( /obj/random/trash, @@ -204,15 +204,15 @@ /area/djstation) "be" = ( /obj/random/maintenance, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "bf" = ( /obj/effect/overmap/visitable/sector/cluster, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "cb" = ( /obj/effect/shuttle_landmark/cluster/nav5, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "db" = ( /obj/effect/shuttle_landmark/cluster/nav6, @@ -236,7 +236,7 @@ /area/space) "ib" = ( /obj/effect/shuttle_landmark/cluster/nav7, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "jb" = ( /obj/machinery/button/access/exterior{ @@ -245,7 +245,7 @@ pixel_y = -24; dir = 1 }, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "kb" = ( /obj/machinery/door/airlock/external{ @@ -345,7 +345,7 @@ req_access = null; dir = 4 }, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "wb" = ( /obj/machinery/door/airlock/external{ diff --git a/maps/away/mining/mining-orb.dmm b/maps/away/mining/mining-orb.dmm index 0f03154da5cf..46fc8c21fb46 100644 --- a/maps/away/mining/mining-orb.dmm +++ b/maps/away/mining/mining-orb.dmm @@ -14,10 +14,10 @@ /turf/unsimulated/mask, /area/mine/unexplored) "ae" = ( -/turf/floor, +/turf/floor/barren, /area/mine/explored) "af" = ( -/turf/floor, +/turf/floor/barren, /area/mine/unexplored) "ag" = ( /turf/wall/natural/random/high_chance, @@ -250,7 +250,7 @@ /area/mine/explored) "st" = ( /obj/effect/shuttle_landmark/orb/nav7, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "vc" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -277,7 +277,7 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "Aj" = ( /obj/effect/floor_decal/spline/fancy/wood/corner, diff --git a/maps/away/mining/mining_areas.dm b/maps/away/mining/mining_areas.dm index 94d5e15d9781..3dd6da725299 100644 --- a/maps/away/mining/mining_areas.dm +++ b/maps/away/mining/mining_areas.dm @@ -3,7 +3,7 @@ icon_state = "mining" ambience = list('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg') sound_env = ASTEROID - base_turf = /turf/floor + base_turf = /turf/floor/barren area_flags = AREA_FLAG_IS_BACKGROUND | AREA_FLAG_HIDE_FROM_HOLOMAP /area/mine/explored diff --git a/maps/away/smugglers/smugglers.dmm b/maps/away/smugglers/smugglers.dmm index 1881db19743e..a0dbd7960366 100644 --- a/maps/away/smugglers/smugglers.dmm +++ b/maps/away/smugglers/smugglers.dmm @@ -3,7 +3,7 @@ /turf/space, /area/space) "ab" = ( -/turf/floor, +/turf/floor/barren, /area/mine/explored) "ac" = ( /turf/unsimulated/mask, @@ -24,7 +24,7 @@ /turf/floor, /area/smugglers/base) "ah" = ( -/turf/floor, +/turf/floor/barren, /area/space) "aj" = ( /obj/item/ammo_casing/pistol/magnum{ @@ -37,11 +37,11 @@ pixel_y = -5 }, /obj/effect/decal/cleanable/blood, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "ak" = ( /obj/effect/decal/cleanable/blood, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "al" = ( /obj/effect/wallframe_spawn/reinforced, @@ -98,7 +98,7 @@ pixel_y = 7 }, /obj/item/flashlight/flare/glowstick/yellow, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "av" = ( /obj/effect/decal/cleanable/blood/drip, @@ -281,11 +281,11 @@ pixel_x = -25; pixel_y = 25 }, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "aM" = ( /obj/random/trash, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "aN" = ( /obj/machinery/light/small{ @@ -432,7 +432,7 @@ /obj/item/tool/xeno/hand{ pixel_x = -15 }, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "bh" = ( /obj/effect/floor_decal/industrial/warning{ @@ -476,7 +476,7 @@ /area/smugglers/base) "bn" = ( /obj/structure/boulder, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "bo" = ( /obj/item/stack/material/ore/silver, @@ -484,7 +484,7 @@ pixel_x = 10; pixel_y = -5 }, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "bp" = ( /obj/structure/cable{ @@ -946,7 +946,7 @@ "db" = ( /obj/effect/decal/cleanable/blood, /obj/abstract/landmark/corpse/doctor, -/turf/floor, +/turf/floor/barren, /area/mine/explored) "eb" = ( /obj/machinery/light/small{ diff --git a/maps/away_sites_testing/away_sites_testing_define.dm b/maps/away_sites_testing/away_sites_testing_define.dm index 8b605741a841..fd1868d5c2ad 100644 --- a/maps/away_sites_testing/away_sites_testing_define.dm +++ b/maps/away_sites_testing/away_sites_testing_define.dm @@ -20,10 +20,10 @@ var/list/unsorted_sites = list_values(SSmapping.get_templates_by_category(MAP_TEMPLATE_CATEGORY_AWAYSITE)) var/list/sorted_sites = sortTim(unsorted_sites, /proc/cmp_sort_templates_tallest_to_shortest) for (var/datum/map_template/A in sorted_sites) - A.load_new_z(centered = FALSE) + A.load_new_z() testing("Spawning [A] in [english_list(SSmapping.get_connected_levels(world.maxz))]") if(A.template_flags & TEMPLATE_FLAG_TEST_DUPLICATES) - A.load_new_z(centered = FALSE) + A.load_new_z() testing("Spawning [A] in [english_list(SSmapping.get_connected_levels(world.maxz))]") /proc/cmp_sort_templates_tallest_to_shortest(var/datum/map_template/a, var/datum/map_template/b) diff --git a/maps/karzerfeste/submaps/_submaps.dm b/maps/karzerfeste/submaps/_submaps.dm index da07fd5c2e7a..c642d5ebd21b 100644 --- a/maps/karzerfeste/submaps/_submaps.dm +++ b/maps/karzerfeste/submaps/_submaps.dm @@ -2,7 +2,6 @@ /datum/map_template/karzerfeste abstract_type = /datum/map_template/karzerfeste - template_parent_type = /datum/map_template/karzerfeste template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS area_usage_test_exempted_root_areas = list( /area/karzerfeste/caves/point_of_interest @@ -25,7 +24,6 @@ /datum/map_template/karzerfeste/dungeon abstract_type = /datum/map_template/karzerfeste/dungeon template_categories = list(MAP_TEMPLATE_CATEGORY_KARZ_DUNGEON) - template_parent_type = /datum/map_template/karzerfeste/dungeon area_usage_test_exempted_root_areas = list( /area/karzerfeste/caves/point_of_interest/dungeon ) diff --git a/maps/ministation/ministation-1.dmm b/maps/ministation/ministation-1.dmm index f0257f29891a..6646873ff830 100644 --- a/maps/ministation/ministation-1.dmm +++ b/maps/ministation/ministation-1.dmm @@ -9764,12 +9764,12 @@ /obj/structure/table/laminate, /obj/item/eftpos, /obj/item/chems/spray/cleaner, +/obj/item/chems/packet/honey_fake, +/obj/item/chems/packet/honey_fake, /obj/item/chems/packet/honey, /obj/item/chems/packet/honey, /obj/item/chems/packet/honey, -/obj/item/chems/packet/honey, -/obj/item/chems/packet/honey, -/obj/item/chems/packet/honey, +/obj/item/chems/packet/honey_fake, /obj/item/chems/packet/honey, /turf/floor/lino, /area/ministation/cafe) diff --git a/maps/modpack_testing/modpack_testing.dm b/maps/modpack_testing/modpack_testing.dm index 29613596f64c..6a867b8917fa 100644 --- a/maps/modpack_testing/modpack_testing.dm +++ b/maps/modpack_testing/modpack_testing.dm @@ -24,6 +24,7 @@ #include "../../mods/content/shackles/_shackles.dme" #include "../../mods/content/supermatter/_supermatter.dme" #include "../../mods/content/xenobiology/_xenobiology.dme" + #include "../../mods/content/item_sharpening/_item_sharpening.dme" #include "../../mods/pyrelight/_pyrelight.dme" // include after _fantasy.dme so overrides work #include "../../mods/gamemodes/cult/_cult.dme" diff --git a/maps/planets/test_planet/neutralia-2.dmm b/maps/planets/test_planet/neutralia-2.dmm index 8b5e82e76e8a..cc84b991ea84 100644 --- a/maps/planets/test_planet/neutralia-2.dmm +++ b/maps/planets/test_planet/neutralia-2.dmm @@ -3,11 +3,11 @@ /turf/unsimulated/mineral, /area/exoplanet/underground/neutralia) "b" = ( -/turf/floor, +/turf/floor/barren, /area/exoplanet/underground/neutralia) "c" = ( /obj/abstract/level_data_spawner/neutralia/underground, -/turf/floor, +/turf/floor/barren, /area/exoplanet/underground/neutralia) (1,1,1) = {" diff --git a/maps/planets/test_planet/neutralia-3.dmm b/maps/planets/test_planet/neutralia-3.dmm index 768772a0f91a..f7d1ff768ee3 100644 --- a/maps/planets/test_planet/neutralia-3.dmm +++ b/maps/planets/test_planet/neutralia-3.dmm @@ -1,6 +1,6 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( -/turf/floor, +/turf/floor/barren, /area/exoplanet/neutralia) "b" = ( /turf/unsimulated/mineral, @@ -17,15 +17,15 @@ /area/exoplanet/neutralia) "j" = ( /obj/abstract/landmark/exoplanet_spawn/large_plant, -/turf/floor, +/turf/floor/barren, /area/exoplanet/neutralia) "o" = ( /obj/abstract/landmark/exoplanet_spawn/animal, -/turf/floor, +/turf/floor/barren, /area/exoplanet/neutralia) "x" = ( /obj/abstract/landmark/exoplanet_spawn/plant, -/turf/floor, +/turf/floor/barren, /area/exoplanet/neutralia) (1,1,1) = {" diff --git a/maps/planets/test_planet/test_planet.dm b/maps/planets/test_planet/test_planet.dm index 159722fde19c..83c42703e654 100644 --- a/maps/planets/test_planet/test_planet.dm +++ b/maps/planets/test_planet/test_planet.dm @@ -131,14 +131,14 @@ name = "neutralia surface" level_id = NEUTRALIA_SURFACE_LEVEL_ID base_area = /area/exoplanet/neutralia - base_turf = /turf/floor + base_turf = /turf/floor/barren border_filler = /turf/unsimulated/dark_filler /datum/level_data/planetoid/neutralia/underground name = "neutralia underground" level_id = "neutralia_underground" base_area = /area/exoplanet/underground/neutralia - base_turf = /turf/floor + base_turf = /turf/floor/barren border_filler = /turf/unsimulated/mineral /datum/level_data/planetoid/neutralia/underground/bottom diff --git a/maps/random_ruins/space_ruins/space_ruins.dm b/maps/random_ruins/space_ruins/space_ruins.dm index 6310e536a7e0..460f5a6995a7 100644 --- a/maps/random_ruins/space_ruins/space_ruins.dm +++ b/maps/random_ruins/space_ruins/space_ruins.dm @@ -5,6 +5,7 @@ material = /decl/material/solid/gemstone/diamond /datum/map_template/ruin/space + abstract_type = /datum/map_template/ruin/space template_categories = list(MAP_TEMPLATE_CATEGORY_SPACE) prefix = "maps/random_ruins/space_ruins/" cost = 1 diff --git a/maps/shaded_hills/shaded_hills.dm b/maps/shaded_hills/shaded_hills.dm index f2337434fae4..befdf1440f79 100644 --- a/maps/shaded_hills/shaded_hills.dm +++ b/maps/shaded_hills/shaded_hills.dm @@ -5,6 +5,7 @@ #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" #include "../../mods/content/scaling_descriptors.dm" #include "../../mods/species/drakes/_drakes.dme" // include before _fantasy.dme so overrides work + #include "../../mods/content/item_sharpening/_item_sharpening.dme" #include "../../mods/content/anima/_anima.dme" // include before _fantasy.dme so skill overrides work #include "../../mods/content/fantasy/_fantasy.dme" #include "../../mods/pyrelight/_pyrelight.dme" // include after _fantasy.dme so overrides work diff --git a/maps/tradeship/tradeship-0.dmm b/maps/tradeship/tradeship-0.dmm index 1de29f1d0ba1..625326ea6258 100644 --- a/maps/tradeship/tradeship-0.dmm +++ b/maps/tradeship/tradeship-0.dmm @@ -1009,7 +1009,7 @@ "dN" = ( /obj/machinery/portable_atmospherics/hydroponics/soil, /obj/item/tool/hoe/mini, -/turf/floor, +/turf/floor/plating/dirt, /area/ship/trade/aft_port_underside_maint) "en" = ( /turf/floor/laminate/walnut, @@ -1179,7 +1179,7 @@ icon_state = "4-8" }, /obj/machinery/portable_atmospherics/hydroponics/soil, -/turf/floor, +/turf/floor/plating/dirt, /area/ship/trade/aft_port_underside_maint) "lv" = ( /obj/effect/decal/cleanable/dirt/visible, @@ -1231,11 +1231,11 @@ /area/ship/trade/fore_port_underside_maint) "oo" = ( /obj/machinery/portable_atmospherics/hydroponics/soil, -/turf/floor, +/turf/floor/plating/dirt, /area/ship/trade/aft_starboard_underside_maint) "or" = ( /obj/machinery/portable_atmospherics/hydroponics/soil, -/turf/floor, +/turf/floor/plating/dirt, /area/ship/trade/aft_port_underside_maint) "os" = ( /obj/structure/lattice, @@ -1483,7 +1483,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/floor, +/turf/floor/plating/dirt, /area/ship/trade/aft_port_underside_maint) "xP" = ( /obj/structure/disposalpipe/segment{ @@ -2053,7 +2053,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/floor, +/turf/floor/plating/dirt, /area/ship/trade/aft_starboard_underside_maint) "QW" = ( /obj/item/stack/tile/floor/five, diff --git a/maps/tradeship/tradeship-2.dmm b/maps/tradeship/tradeship-2.dmm index f7a673962651..0084e4d8d712 100644 --- a/maps/tradeship/tradeship-2.dmm +++ b/maps/tradeship/tradeship-2.dmm @@ -1282,7 +1282,7 @@ /obj/machinery/recharger, /obj/structure/sign/poster{ pixel_x = 32; - dir = 8 + dir = 4 }, /obj/item/plate/tray, /obj/item/circular_saw, diff --git a/mods/content/fantasy/datum/hnoll/species.dm b/mods/content/fantasy/datum/hnoll/species.dm index 31ebc61a61ea..8bb1cd7496e7 100644 --- a/mods/content/fantasy/datum/hnoll/species.dm +++ b/mods/content/fantasy/datum/hnoll/species.dm @@ -30,13 +30,6 @@ move_trail = /obj/effect/decal/cleanable/blood/tracks/paw base_external_prosthetics_model = null - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch, - /decl/natural_attack/bite/sharp - ) - available_background_info = list( /decl/background_category/homeworld = list( /decl/background_detail/location/fantasy, diff --git a/mods/content/fantasy/datum/overrides.dm b/mods/content/fantasy/datum/overrides.dm index 2c9e6b417eff..301f46558317 100644 --- a/mods/content/fantasy/datum/overrides.dm +++ b/mods/content/fantasy/datum/overrides.dm @@ -35,6 +35,33 @@ /decl/bodytype/prosthetic/wooden name = "carved wooden" // weird to call it 'crude' when it's cutting-edge for the setting +// Just some fun overrides for when robot debris shows up in maint. +/obj/effect/decal/cleanable/blood/gibs/robot + name = "mysterious debris" + desc = "Some kind of complex, oily detritus. What could it be?" + +/obj/item/remains/robot + name = "mysterious remains" + desc = "The oily remains of some complex, metallic object. What could they be from?" + +// Override to remove non-fantasy stuff. +/obj/random/trash/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/remains/lizard, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/spiderling_remains, + /obj/item/remains/mouse, + /obj/effect/decal/cleanable/vomit, + /obj/effect/decal/cleanable/blood/splatter, + /obj/effect/decal/cleanable/ash, + /obj/effect/decal/cleanable/generic, + /obj/effect/decal/cleanable/flour, + /obj/effect/decal/cleanable/filth, + /obj/effect/decal/cleanable/dirt/visible, + /obj/item/remains/robot + ) + return spawnable_choices + // Overrides to populate the dungeon with undead. /obj/random/hostile/dungeon/spawn_choices() var/static/list/spawnable_choices = list( diff --git a/mods/content/fantasy/submaps/_submaps.dm b/mods/content/fantasy/submaps/_submaps.dm index 71cfb9e98a05..64c03240f4b7 100644 --- a/mods/content/fantasy/submaps/_submaps.dm +++ b/mods/content/fantasy/submaps/_submaps.dm @@ -7,7 +7,6 @@ /datum/map_template/fantasy abstract_type = /datum/map_template/fantasy - template_parent_type = /datum/map_template/fantasy template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS area_usage_test_exempted_root_areas = list( /area/fantasy/outside/point_of_interest diff --git a/mods/content/fantasy/submaps/downlands/_downlands.dm b/mods/content/fantasy/submaps/downlands/_downlands.dm index c97d04705d06..5086d54dc545 100644 --- a/mods/content/fantasy/submaps/downlands/_downlands.dm +++ b/mods/content/fantasy/submaps/downlands/_downlands.dm @@ -1,9 +1,7 @@ /datum/map_template/fantasy/downlands abstract_type = /datum/map_template/fantasy/downlands template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_DOWNLANDS) - template_parent_type = /datum/map_template/fantasy/downlands /datum/map_template/fantasy/dungeon abstract_type = /datum/map_template/fantasy/dungeon template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_DUNGEON) - template_parent_type = /datum/map_template/fantasy/dungeon diff --git a/mods/content/fantasy/submaps/grassland/_grassland.dm b/mods/content/fantasy/submaps/grassland/_grassland.dm index 57fcd595c5f3..19b70b9367f0 100644 --- a/mods/content/fantasy/submaps/grassland/_grassland.dm +++ b/mods/content/fantasy/submaps/grassland/_grassland.dm @@ -1,9 +1,7 @@ /datum/map_template/fantasy/grassland abstract_type = /datum/map_template/fantasy/grassland template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_GRASSLAND) - template_parent_type = /datum/map_template/fantasy/grassland /datum/map_template/fantasy/cavern abstract_type = /datum/map_template/fantasy/cavern - template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_CAVERNS) - template_parent_type = /datum/map_template/fantasy/cavern \ No newline at end of file + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_CAVERNS) \ No newline at end of file diff --git a/mods/content/fantasy/submaps/swamp/_swamp.dm b/mods/content/fantasy/submaps/swamp/_swamp.dm index 60ece589b4af..6a3c2054ea9a 100644 --- a/mods/content/fantasy/submaps/swamp/_swamp.dm +++ b/mods/content/fantasy/submaps/swamp/_swamp.dm @@ -1,4 +1,3 @@ /datum/map_template/fantasy/swamp abstract_type = /datum/map_template/fantasy/swamp - template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_SWAMP) - template_parent_type = /datum/map_template/fantasy/swamp \ No newline at end of file + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_SWAMP) \ No newline at end of file diff --git a/mods/content/fantasy/submaps/woods/_woods.dm b/mods/content/fantasy/submaps/woods/_woods.dm index 657ce2c6b269..dc1429ef5592 100644 --- a/mods/content/fantasy/submaps/woods/_woods.dm +++ b/mods/content/fantasy/submaps/woods/_woods.dm @@ -1,4 +1,3 @@ /datum/map_template/fantasy/woods abstract_type = /datum/map_template/fantasy/woods template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_WOODS) - template_parent_type = /datum/map_template/fantasy/woods diff --git a/mods/content/item_sharpening/_item_sharpening.dm b/mods/content/item_sharpening/_item_sharpening.dm new file mode 100644 index 000000000000..3807839161bd --- /dev/null +++ b/mods/content/item_sharpening/_item_sharpening.dm @@ -0,0 +1,8 @@ +#define IE_PAR_SHARP_DAM_MULT "sharp_dam_mult" + +/decl/modpack/item_sharpening + name = "Item Sharpening" + +/obj/proc/get_sharpening_material() + RETURN_TYPE(/decl/material) + return get_material() diff --git a/mods/content/item_sharpening/_item_sharpening.dme b/mods/content/item_sharpening/_item_sharpening.dme new file mode 100644 index 000000000000..c9af243f5e94 --- /dev/null +++ b/mods/content/item_sharpening/_item_sharpening.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_ITEM_SHARPENING +#define MODPACK_ITEM_SHARPENING +// BEGIN_INCLUDE +#include "_item_sharpening.dm" +#include "blade_sharpen.dm" +#include "effect_sharpen.dm" +#include "grindstone.dm" +#include "item_sharpen.dm" +#include "whetstone.dm" +//END_INCLUDE +#endif diff --git a/mods/content/item_sharpening/blade_sharpen.dm b/mods/content/item_sharpening/blade_sharpen.dm new file mode 100644 index 000000000000..a46b8d690332 --- /dev/null +++ b/mods/content/item_sharpening/blade_sharpen.dm @@ -0,0 +1,24 @@ +/obj/item/bladed/proc/get_sharpened_effect_params() + return list( + (IE_CAT_DAMAGE) = list( + (IE_PAR_USES) = max(1, max(1, rand(round(10 * 0.3), round(20 * 0.6)))), + (IE_PAR_MAX_USES) = 30, + (IE_PAR_SHARP_DAM_MULT) = 0.25 + ), + (IE_CAT_EXAMINE) + ) + +/obj/item/bladed/Initialize(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) + var/list/sharpened_params = get_sharpened_effect_params() + if(length(sharpened_params)) + add_item_effect(/decl/item_effect/sharpened, sharpened_params) + . = ..() + if(length(sharpened_params)) + update_attack_force() + update_name() + +/obj/item/bladed/folding/try_sharpen_with(mob/user, obj/sharpening_with) + if(!open) + to_chat(user, SPAN_WARNING("You cannot sharpen \the [src] while it's closed!")) + return FALSE + return ..() diff --git a/mods/content/item_sharpening/effect_sharpen.dm b/mods/content/item_sharpening/effect_sharpen.dm new file mode 100644 index 000000000000..5847ac347b36 --- /dev/null +++ b/mods/content/item_sharpening/effect_sharpen.dm @@ -0,0 +1,21 @@ +/decl/item_effect/sharpened/modify_attack_damage(base_damage, obj/item/used_item, mob/user, list/parameters) + var/uses = LAZYACCESS(parameters, IE_PAR_USES) + if(uses <= 0) + return base_damage + . = (1 + ((uses / max(1, LAZYACCESS(parameters, IE_PAR_MAX_USES))) * LAZYACCESS(parameters, IE_PAR_SHARP_DAM_MULT))) + +/decl/item_effect/sharpened/expend_attack_use(obj/item/used_item, mob/user, list/parameters) + var/uses = LAZYACCESS(parameters, IE_PAR_USES) + uses = max(0, uses-1) + used_item.set_item_effect_parameter(src, IE_CAT_DAMAGE, IE_PAR_USES, uses) + if(uses == 0) // We've gone dull! + used_item.update_attack_force() + used_item.update_name() + +/decl/item_effect/sharpened/on_examined(obj/item/item, mob/user, distance, list/parameters) + if(distance <= 1) + var/uses = item.get_item_effect_parameter(src, IE_CAT_DAMAGE, IE_PAR_USES) + if(uses > 0) + to_chat(user, SPAN_NOTICE("\The [item] has been honed to a keen edge.")) + else + to_chat(user, SPAN_NOTICE("\The [item] in need of sharpening.")) diff --git a/mods/content/item_sharpening/grindstone.dm b/mods/content/item_sharpening/grindstone.dm new file mode 100644 index 000000000000..13d8f1260520 --- /dev/null +++ b/mods/content/item_sharpening/grindstone.dm @@ -0,0 +1,46 @@ +// TODO: better sound effects for working. +/obj/structure/working/grindstone + name = "grindstone" + desc = "A rotating section of coarse stone used to polish and sharpen metalwork like blades." + icon = 'mods/content/item_sharpening/icons/grindstone.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR // Name and desc handled manually. + var/decl/material/stone_material = /decl/material/solid/quartz + +/obj/structure/working/grindstone/Initialize() + stone_material = GET_DECL(stone_material) + . = ..() + update_material_name() + update_material_desc() + +/obj/structure/working/grindstone/update_material_name(override_name) + . = ..() + if(stone_material) + SetName("[stone_material.adjective_name] [name]") + +/obj/structure/working/grindstone/update_material_desc(override_desc) + . = ..() + if(stone_material && istype(material)) + desc = "[desc] This one is made from [stone_material.solid_name] with \a [material.adjective_name] frame." + +/obj/structure/working/grindstone/on_update_icon() + . = ..() + underlays = list( + overlay_image(icon, "[icon_state]-grindstone", stone_material.color, RESET_COLOR), + overlay_image(icon, "[initial(icon_state)]-backdrop") + ) + +// Slightly wonky override, but this basically intercepts items being used on the grindstone. +/obj/structure/working/grindstone/try_take_input(obj/item/used_item, mob/user, silent) + if(working) + if(!silent) + to_chat(user, SPAN_WARNING("\The [src] is already in use, please wait for it to be free.")) + else + start_working() + used_item.try_sharpen_with(user, src) + if(!QDELETED(src) && working) + stop_working() + return TRUE + +/obj/structure/working/grindstone/get_sharpening_material() + RETURN_TYPE(/decl/material) + return stone_material diff --git a/mods/content/item_sharpening/icons/grindstone.dmi b/mods/content/item_sharpening/icons/grindstone.dmi new file mode 100644 index 000000000000..70b311b63b5c Binary files /dev/null and b/mods/content/item_sharpening/icons/grindstone.dmi differ diff --git a/mods/content/item_sharpening/item_sharpen.dm b/mods/content/item_sharpening/item_sharpen.dm new file mode 100644 index 000000000000..a72e928e5e88 --- /dev/null +++ b/mods/content/item_sharpening/item_sharpen.dm @@ -0,0 +1,49 @@ +/obj/item/update_name() + . = ..() + if(has_item_effect(/decl/item_effect/sharpened, IE_CAT_EXAMINE) && get_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES) <= 0) + SetName("dulled [name]") + +/obj/item/proc/can_sharpen_with(obj/sharpening_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE) || !material || !istype(sharpening_with)) + return FALSE + var/list/params = get_item_effect_parameters(/decl/item_effect/sharpened, IE_CAT_DAMAGE) + if(!islist(params) || params[IE_PAR_USES] >= params[IE_PAR_MAX_USES]) + return FALSE + return material.hardness <= sharpening_with.get_sharpening_material()?.hardness + +/obj/item/proc/sharpen_with(mob/user, obj/sharpen_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + var/list/params = get_item_effect_parameters(/decl/item_effect/sharpened, IE_CAT_DAMAGE) + if(!islist(params)) + return FALSE + var/max_uses = params[IE_PAR_MAX_USES] + if(max_uses <= 0) + return FALSE + var/uses = params[IE_PAR_USES] || 0 + if(uses >= max_uses) + return FALSE + set_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES, max_uses) + if(uses == 0) // We've sharpened up from dull. + update_attack_force() + update_name() + return TRUE + +/obj/item/proc/try_sharpen_with(mob/user, obj/sharpening_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + if(can_sharpen_with(sharpening_with)) + user.visible_message("\The [user] begins sharpening \the [src] with \the [sharpening_with].") + playsound(loc, 'sound/foley/knife1.ogg', 50) // metallic scrape, TODO better sound + if(user.do_skilled(10 SECONDS, SKILL_WEAPONS, src, check_holding = TRUE) && !QDELETED(sharpening_with) && can_sharpen_with(sharpening_with) && sharpen_with(user, sharpening_with)) + playsound(loc, 'sound/foley/knife1.ogg', 50) + user.visible_message("\The [user] sharpens \the [src] with \the [sharpening_with].") + else + to_chat(user, SPAN_WARNING("\The [src] cannot be [initial(sharp) ? "further sharpened" : "sharpened"] with \the [sharpening_with].")) + return TRUE + +// We don't override sharp because it's probably still pointy even if it isn't sharpened. +/obj/item/has_edge() + . = ..() + if(. && has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return get_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES) > 0 diff --git a/mods/content/item_sharpening/whetstone.dm b/mods/content/item_sharpening/whetstone.dm new file mode 100644 index 000000000000..cdfbb09eea51 --- /dev/null +++ b/mods/content/item_sharpening/whetstone.dm @@ -0,0 +1,18 @@ +/obj/item/whetstone + name = "whetstone" + desc = "A worn-down lozenge used to sharpen blades." + icon = 'icons/obj/items/striker.dmi' // TODO unique icon? + w_class = ITEM_SIZE_TINY + material_alteration = MAT_FLAG_ALTERATION_ALL + material = /decl/material/solid/quartz + +/obj/item/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/whetstone)) + return try_sharpen_with(user, used_item) + return ..() + +/decl/loadout_option/utility/whetstone + name = "whetstone" + path = /obj/item/whetstone + loadout_flags = null + uid = "gear_utility_whetstone" diff --git a/mods/content/psionics/system/psionics/equipment/psipower_blade.dm b/mods/content/psionics/system/psionics/equipment/psipower_blade.dm index fd8b4f947c86..94163e320127 100644 --- a/mods/content/psionics/system/psionics/equipment/psipower_blade.dm +++ b/mods/content/psionics/system/psionics/equipment/psipower_blade.dm @@ -1,8 +1,8 @@ /obj/item/ability/psionic/psiblade name = "psychokinetic slash" _base_attack_force = 10 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE maintain_cost = 1 icon_state = "psiblade_short" diff --git a/mods/content/psionics/system/psionics/equipment/psipower_tk.dm b/mods/content/psionics/system/psionics/equipment/psipower_tk.dm index ee21afaa9077..ee529a0d9226 100644 --- a/mods/content/psionics/system/psionics/equipment/psipower_tk.dm +++ b/mods/content/psionics/system/psionics/equipment/psipower_tk.dm @@ -106,5 +106,4 @@ O.icon = 'icons/effects/effects.dmi' O.icon_state = "nothing" flick("empdisable",O) - sleep(5) - qdel(O) + QDEL_IN(src, 0.5 SECONDS) diff --git a/mods/content/psionics/system/psionics/faculties/coercion.dm b/mods/content/psionics/system/psionics/faculties/coercion.dm index 2af44aa9335a..8a92f058ad10 100644 --- a/mods/content/psionics/system/psionics/faculties/coercion.dm +++ b/mods/content/psionics/system/psionics/faculties/coercion.dm @@ -179,7 +179,7 @@ return TRUE if(accepted_glamour == "Yes") - to_chat(user, SPAN_DANGER("You layer a glamour across the \the [target]'s senses, beguiling them to unwittingly follow your commands.")) + to_chat(user, SPAN_DANGER("You layer a glamour across \the [target]'s senses, beguiling them to unwittingly follow your commands.")) to_chat(target, SPAN_DANGER("You have been ensnared by \the [user]'s glamour!")) beguiled.add_antagonist(target.mind, new_controller = user) else diff --git a/mods/content/supermatter/endgame_cascade/universe.dm b/mods/content/supermatter/endgame_cascade/universe.dm index 507097a121eb..ccca16707e43 100644 --- a/mods/content/supermatter/endgame_cascade/universe.dm +++ b/mods/content/supermatter/endgame_cascade/universe.dm @@ -67,9 +67,10 @@ if(!invalid_area) A.update_icon() +// TODO: Should this be changed to use the actual ambient lights system...? /datum/universal_state/supermatter_cascade/OverlayAndAmbientSet() spawn(0) - for(var/datum/lighting_corner/L in world) + for(var/datum/lighting_corner/L in SSlighting.lighting_corners) if(isAdminLevel(L.z)) L.update_lumcount(1,1,1) else diff --git a/mods/content/xenobiology/_xenobiology.dme b/mods/content/xenobiology/_xenobiology.dme index 11a5f3972c68..1591ea3f458a 100644 --- a/mods/content/xenobiology/_xenobiology.dme +++ b/mods/content/xenobiology/_xenobiology.dme @@ -50,7 +50,6 @@ #include "slime\slime_commands.dm" #include "slime\slime_comments.dm" #include "slime\slime_follow.dm" -#include "slime\slime_hud.dm" #include "slime\slime_reagents.dm" #include "slime\slime_surgery.dm" #include "slime\slime_update_icon.dm" diff --git a/mods/content/xenobiology/slime/_slime.dm b/mods/content/xenobiology/slime/_slime.dm index a5b342022c26..60c12cb89e3d 100644 --- a/mods/content/xenobiology/slime/_slime.dm +++ b/mods/content/xenobiology/slime/_slime.dm @@ -18,7 +18,7 @@ status_flags = CANPARALYSE|CANPUSH butchery_data = null ai = /datum/mob_controller/slime - hud_used = /datum/hud/slime + hud_used = /datum/hud/animal nutrition = 800 var/is_adult = FALSE @@ -33,7 +33,6 @@ var/slime_type = /decl/slime_colour/grey var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside var/core_removal_stage = 0 //For removing cores. - var/datum/reagents/metabolism/ingested /mob/living/slime/Destroy() set_feeding_on() @@ -65,8 +64,7 @@ . = ..(mapload) - ingested = new /datum/reagents/metabolism(240, src, CHEM_TOUCH) - reagents = ingested + reagents = new /datum/reagents/metabolism(240, src, CHEM_TOUCH) render_target = "slime_\ref[src]" verbs += /mob/living/proc/ventcrawl @@ -272,7 +270,7 @@ return ..() /mob/living/slime/attackby(var/obj/item/W, var/mob/user) - var/force = W.get_attack_force(user) + var/force = W.expend_attack_force(user) if(force > 0) var/datum/mob_controller/slime/slime_ai = ai if(istype(slime_ai)) diff --git a/mods/content/xenobiology/slime/life.dm b/mods/content/xenobiology/slime/life.dm index 55b0e665ec12..d71a1d3edd4c 100644 --- a/mods/content/xenobiology/slime/life.dm +++ b/mods/content/xenobiology/slime/life.dm @@ -46,6 +46,7 @@ . = ..() if(feeding_on) slime_feed() + var/datum/reagents/metabolism/ingested = reagents ingested.metabolize() /mob/living/slime/fluid_act(datum/reagents/fluids) @@ -86,6 +87,7 @@ . = ..() if(feeding_on) slime_feed() + var/datum/reagents/metabolism/ingested = reagents ingested.metabolize() // Digest whatever we've got floating around in our goop. diff --git a/mods/content/xenobiology/slime/slime_AI.dm b/mods/content/xenobiology/slime/slime_AI.dm index 7260e124070c..bf28ef6cd6bb 100644 --- a/mods/content/xenobiology/slime/slime_AI.dm +++ b/mods/content/xenobiology/slime/slime_AI.dm @@ -2,8 +2,8 @@ expected_type = /mob/living/slime var/mood var/chase_target = 0 - var/mob/living/leader - var/mob/living/current_target // Currently attacking this mob (separate from feeding) + var/weakref/leader + var/weakref/current_target // Currently attacking this mob (separate from feeding) var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with var/list/observed_friends // A list of refs to friends; they are not considered targets for feeding; passed down after splitting. @@ -20,6 +20,7 @@ /datum/mob_controller/slime/Destroy() observed_friends = null friendship_cooldown = null + leader = null current_target = null speech_buffer = null slime = null @@ -44,7 +45,7 @@ else if(rabid || attacked) new_mood = "angry" body.set_intent(I_FLAG_HARM) - else if(current_target) + else if(current_target?.resolve()) new_mood = "mischevous" if(!new_mood) @@ -97,22 +98,27 @@ current_target = null return - if(current_target) + var/mob/actual_target = current_target?.resolve() + if(actual_target) chase_target-- if(chase_target <= 0 || attacked || rabid) // Tired of chasing or attacking everything nearby chase_target = 0 current_target = null + else + current_target = null var/hunger = slime.get_hunger_state() - if(!current_target) + var/mob/leader_mob = leader?.resolve() + actual_target = current_target?.resolve() + if(!actual_target) var/feral = (attacked || rabid || hunger >= 2) - if(feral || (!leader && !holding_still) || (hunger && prob(10))) + if(feral || (!leader_mob && !holding_still) || (hunger && prob(10))) var/list/targets for(var/mob/living/prey in view(7, body)) if(assess_target(prey)) LAZYADD(targets, prey) if(length(targets)) - current_target = get_best_target(targets) + current_target = weakref(get_best_target(targets)) chase_target = rand(5,7) if(slime.is_adult) chase_target += 3 @@ -120,8 +126,8 @@ if(holding_still) holding_still = max(holding_still - 1 - hunger, 0) else if(isturf(body?.loc)) - if(leader) - step_to(body, get_dir(body, leader)) + if(leader_mob) + step_to(body, get_dir(body, leader_mob)) else if(prob(hunger ? 50 : 33)) body.SelfMove(pick(global.cardinal)) @@ -131,42 +137,42 @@ return var/added_delay = 0 - if(slime.amount_grown >= SLIME_EVOLUTION_THRESHOLD && !current_target) + var/mob/actual_target = current_target?.resolve() + if(slime.amount_grown >= SLIME_EVOLUTION_THRESHOLD && !actual_target) if(slime.is_adult) slime.slime_split() else slime.slime_mature() added_delay = 10 else - - if(!assess_target(current_target) || current_target == slime.feeding_on || !(current_target in view(7, body))) + if(!assess_target(actual_target) || actual_target == slime.feeding_on || !(actual_target in view(7, body))) current_target = null - if(!current_target) + if(!actual_target) if(prob(1)) for(var/mob/living/slime/frenemy in range(1, body)) if(frenemy != body && body.Adjacent(frenemy)) body.set_intent((frenemy.slime_type == slime.slime_type) ? I_FLAG_HELP : I_FLAG_HARM) body.UnarmedAttack(frenemy, TRUE) added_delay = 10 - else if(slime.Adjacent(current_target)) + else if(slime.Adjacent(actual_target)) var/do_attack = FALSE - if(issilicon(current_target)) + if(issilicon(actual_target)) body.set_intent(I_FLAG_HARM) do_attack = TRUE - else if(current_target.client && !current_target.current_posture.prone && prob(60 + slime.powerlevel * 4)) + else if(actual_target.client && !actual_target.current_posture.prone && prob(60 + slime.powerlevel * 4)) body.set_intent(I_FLAG_DISARM) do_attack = TRUE - else if(slime.check_valid_feed_target(current_target) == FEED_RESULT_VALID) + else if(slime.check_valid_feed_target(actual_target) == FEED_RESULT_VALID) body.set_intent(I_FLAG_GRAB) do_attack = TRUE if(do_attack) - body.UnarmedAttack(current_target, TRUE) + body.UnarmedAttack(actual_target, TRUE) added_delay = 10 else current_target = null else - step_to(body, current_target) + step_to(body, actual_target) next_core_logic_run = world.time + max(body?.get_movement_delay(), 5) + added_delay @@ -208,13 +214,13 @@ /datum/mob_controller/slime/proc/adjust_friendship(var/atom/user, var/amount) if(ismob(user)) - if(QDELETED(user)) + if(QDELING(user)) return FALSE user = weakref(user) else if(istype(user, /weakref)) // verify the ref is still valid var/weakref/user_ref = user - user = user_ref.resolve() - if(!ismob(user) || QDELETED(user)) + var/mob/resolved_user = user_ref.resolve() + if(!ismob(resolved_user) || QDELING(resolved_user)) return FALSE else return FALSE diff --git a/mods/content/xenobiology/slime/slime_commands.dm b/mods/content/xenobiology/slime/slime_commands.dm index 4290f05accfb..3be381f2a01f 100644 --- a/mods/content/xenobiology/slime/slime_commands.dm +++ b/mods/content/xenobiology/slime/slime_commands.dm @@ -20,15 +20,16 @@ triggers = list("follow") /decl/slime_command/follow/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) - if(holder.leader) - if(holder.leader == speaker) + var/mob/leader_mob = holder.leader?.resolve() + if(leader_mob) + if(leader_mob == speaker) return pick("Yes...", "Lead...", "Following...") - if(LAZYACCESS(holder.observed_friends, weakref(speaker)) > LAZYACCESS(holder.observed_friends, weakref(holder.leader))) - holder.leader = speaker + if(LAZYACCESS(holder.observed_friends, weakref(speaker)) > LAZYACCESS(holder.observed_friends, holder.leader)) + holder.leader = weakref(speaker) return "Yes... I follow [speaker]..." - return "No... I follow [holder.leader]..." + return "No... I follow [leader_mob]..." if(LAZYACCESS(holder.observed_friends, weakref(speaker)) > 2) - holder.leader = speaker + holder.leader = weakref(speaker) return "I follow..." return pick("No...", "I won't follow...") @@ -45,18 +46,20 @@ holder.adjust_friendship(speaker, -1) return "Grrr..." return "Fine..." - if(holder.current_target) + var/mob/actual_target = holder.current_target?.resolve() + if(actual_target) if(friendship > 3) holder.current_target = null if(friendship < 6) holder.adjust_friendship(speaker, -1) return "Grrr..." return "Fine..." - if(holder.leader) - if(holder.leader == speaker) + var/mob/leader_mob = holder.leader?.resolve() + if(leader_mob) + if(leader_mob == speaker) holder.leader = null return "Yes... I'll stop..." - if(friendship > LAZYACCESS(holder.observed_friends, weakref(holder.leader))) + if(friendship > LAZYACCESS(holder.observed_friends, holder.leader)) holder.leader = null return "Yes... I'll stop..." return "No... I'll keep following..." @@ -66,11 +69,12 @@ /decl/slime_command/stay/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) var/friendship = LAZYACCESS(holder.observed_friends, weakref(speaker)) - if(holder.leader) - if(holder.leader == speaker) + var/mob/leader_mob = holder.leader?.resolve() + if(leader_mob) + if(leader_mob == speaker) holder.holding_still = friendship * 10 return "Yes... Staying..." - var/leader_friendship = LAZYACCESS(holder.observed_friends, weakref(holder.leader)) + var/leader_friendship = LAZYACCESS(holder.observed_friends, holder.leader) if(friendship > leader_friendship) holder.holding_still = (friendship - leader_friendship) * 10 return "Yes... Staying..." diff --git a/mods/content/xenobiology/slime/slime_comments.dm b/mods/content/xenobiology/slime/slime_comments.dm index bd8ad9f11468..f009e3131236 100644 --- a/mods/content/xenobiology/slime/slime_comments.dm +++ b/mods/content/xenobiology/slime/slime_comments.dm @@ -29,8 +29,9 @@ if(holder.slime.nutrition < holder.slime.get_starve_nutrition()) . += list("So... hungry...", "Very... hungry...", "Need... food...", "Must... eat...") tension += 10 - if(holder.current_target) - . += "\The [holder.current_target]... looks tasty..." + var/mob/actual_target = holder.current_target?.resolve() + if(actual_target) + . += "\The [actual_target]... looks tasty..." if(length(.) && prob(tension)) return pick(.) diff --git a/mods/content/xenobiology/slime/slime_hud.dm b/mods/content/xenobiology/slime/slime_hud.dm deleted file mode 100644 index 2cdd315d671f..000000000000 --- a/mods/content/xenobiology/slime/slime_hud.dm +++ /dev/null @@ -1,4 +0,0 @@ -/datum/hud/slime/FinalizeInstantiation() - action_intent = new(null, mymob) - adding = list(action_intent) - ..() diff --git a/mods/content/xenobiology/slime/slime_reagents.dm b/mods/content/xenobiology/slime/slime_reagents.dm index bff84fd00ee7..882797de7599 100644 --- a/mods/content/xenobiology/slime/slime_reagents.dm +++ b/mods/content/xenobiology/slime/slime_reagents.dm @@ -14,22 +14,23 @@ metabolism = REM * 0.25 exoplanet_rarity_gas = MAT_RARITY_EXOTIC -/decl/material/liquid/water/affect_touch(var/mob/living/M, var/removed, var/datum/reagents/holder) +/decl/material/liquid/water/affect_touch(var/mob/living/victim, var/removed, var/datum/reagents/holder) . = ..() - if(isslime(M)) - M.take_damage(10 * removed, TOX) - var/mob/living/slime/S = M - if(istype(S) && istype(S.ai, /datum/mob_controller/slime)) - var/datum/mob_controller/slime/slime_ai = S.ai - if(slime_ai.current_target) + if(isslime(victim)) + victim.take_damage(10 * removed, TOX) + var/mob/living/slime/slime_victim = victim + if(istype(slime_victim) && istype(slime_victim.ai, /datum/mob_controller/slime)) + var/datum/mob_controller/slime/slime_ai = slime_victim.ai + if(slime_ai.current_target) // don't bother resolving it, we're just clearing it slime_ai.current_target = null - S.set_feeding_on() - if(LAZYACCESS(M.chem_doses, type) == removed) - M.visible_message( \ - SPAN_DANGER("\The [S]'s flesh sizzles where \the [name] touches it!"), \ - SPAN_DANGER("Your flesh is burned by \the [name]!")) - SET_STATUS_MAX(M, STAT_CONFUSE, 2) - var/datum/mob_controller/slime/slime_ai = M.ai + slime_victim.set_feeding_on() + if(LAZYACCESS(victim.chem_doses, type) == removed) + var/reagent_name = get_reagent_name(holder) // mostly to check masked name, but handles phase too + victim.visible_message( \ + SPAN_DANGER("\The [slime_victim]'s flesh sizzles where \the [reagent_name] touches it!"), \ + SPAN_DANGER("Your flesh is burned by \the [reagent_name]!")) + SET_STATUS_MAX(victim, STAT_CONFUSE, 2) + var/datum/mob_controller/slime/slime_ai = victim.ai if(istype(slime_ai)) slime_ai.attacked = max(slime_ai.attacked, rand(7,10)) // angery diff --git a/mods/gamemodes/cult/items.dm b/mods/gamemodes/cult/items.dm index 2b2e826617c7..e4faf111e49f 100644 --- a/mods/gamemodes/cult/items.dm +++ b/mods/gamemodes/cult/items.dm @@ -26,7 +26,7 @@ to_chat(user, SPAN_DANGER("An unexplicable force rips through you, tearing the sword from your grasp!")) //random amount of damage between half of the blade's force and the full force of the blade. - var/force = get_attack_force(user) + var/force = expend_attack_force(user) user.apply_damage(rand(force/2, force), BRUTE, zone, (DAM_SHARP|DAM_EDGE), armor_pen = 100) SET_STATUS_MAX(user, STAT_WEAK, 5) diff --git a/mods/gamemodes/cult/mobs/constructs/soulstone.dm b/mods/gamemodes/cult/mobs/constructs/soulstone.dm index b5a8f6f09485..69e5d0ef21e4 100644 --- a/mods/gamemodes/cult/mobs/constructs/soulstone.dm +++ b/mods/gamemodes/cult/mobs/constructs/soulstone.dm @@ -51,7 +51,7 @@ to_chat(user, SPAN_NOTICE("You cleanse \the [src] of taint, purging its shackles to its creator.")) is_evil = FALSE return TRUE - else if(I.get_attack_force(user) >= 5) + else if(I.expend_attack_force(user) >= 5) if(full != SOULSTONE_CRACKED) user.visible_message( SPAN_WARNING("\The [user] hits \the [src] with \the [I], and it breaks.[shade.client ? " You hear a terrible scream!" : ""]"), diff --git a/mods/gamemodes/cult/runes.dm b/mods/gamemodes/cult/runes.dm index 6724fbae270b..c54cb016914f 100644 --- a/mods/gamemodes/cult/runes.dm +++ b/mods/gamemodes/cult/runes.dm @@ -322,7 +322,7 @@ user.visible_message(SPAN_NOTICE("\The [user] touches \the [src] with \the [I], and it disappears."), SPAN_NOTICE("You disrupt the vile magic with the deadening field of \the [I].")) qdel(src) return TRUE - var/force = I.get_attack_force(user) + var/force = I.expend_attack_force(user) if(force) user.visible_message(SPAN_NOTICE("\The [user] hits \the [src] with \the [I]."), SPAN_NOTICE("You hit \the [src] with \the [I].")) take_damage(force, I.atom_damage_type) diff --git a/mods/gamemodes/cult/structures.dm b/mods/gamemodes/cult/structures.dm index 26eec8bb2175..9f39d61522d6 100644 --- a/mods/gamemodes/cult/structures.dm +++ b/mods/gamemodes/cult/structures.dm @@ -28,7 +28,7 @@ return TRUE /obj/structure/cult/pylon/attackby(obj/item/W, mob/user) - attackpylon(user, W.get_attack_force(user)) + attackpylon(user, W.expend_attack_force(user)) return TRUE /obj/structure/cult/pylon/proc/attackpylon(mob/user, var/damage) diff --git a/mods/mobs/borers/mob/borer/borer.dm b/mods/mobs/borers/mob/borer/borer.dm index 83dc85cd0038..f9dbbe2f6e17 100644 --- a/mods/mobs/borers/mob/borer/borer.dm +++ b/mods/mobs/borers/mob/borer/borer.dm @@ -18,6 +18,22 @@ bleed_colour = "#816e12" ai = /datum/mob_controller/borer + // Defined here to remove relaymove handlers as being + // directly in mob contents breaks relaymove spectacularly. + movement_handlers = list( + /datum/movement_handler/mob/death, + /datum/movement_handler/mob/borer_in_host, + /datum/movement_handler/mob/conscious, + /datum/movement_handler/mob/eye, + /datum/movement_handler/mob/delay, + /datum/movement_handler/mob/stop_effect, + /datum/movement_handler/mob/physically_capable, + /datum/movement_handler/mob/physically_restrained, + /datum/movement_handler/mob/space, + /datum/movement_handler/mob/multiz, + /datum/movement_handler/mob/movement + ) + var/static/list/chemical_types = list( "anti-trauma" = /decl/material/liquid/brute_meds, "amphetamines" = /decl/material/liquid/amphetamines, @@ -40,6 +56,9 @@ var/mob/living/human/host // Human host for the brain worm. var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. +/datum/movement_handler/mob/borer_in_host/MayMove(mob/mover, is_external) + return ismob(mob.loc) ? MOVEMENT_STOP : MOVEMENT_PROCEED + /datum/mob_controller/borer emote_hear = list("chirrups") do_wander = FALSE diff --git a/mods/mobs/borers/mob/borer/borer_attacks.dm b/mods/mobs/borers/mob/borer/borer_attacks.dm index 5463f67d7183..6c5919ed2b5c 100644 --- a/mods/mobs/borers/mob/borer/borer_attacks.dm +++ b/mods/mobs/borers/mob/borer/borer_attacks.dm @@ -1,50 +1,44 @@ /mob/living/simple_animal/borer/UnarmedAttack(atom/A, proximity) - . = ..() - if(.) - return + if(host) + return TRUE // We cannot click things outside of our host. - if(!isliving(A) || !check_intent(I_FLAG_GRAB)) - return FALSE + if(!isliving(A) || !check_intent(I_FLAG_GRAB) || stat || !proximity) + return ..() - if(host || !can_use_borer_ability(requires_host_value = FALSE, check_last_special = FALSE)) - return FALSE + if(!can_use_borer_ability(requires_host_value = FALSE, check_last_special = FALSE)) + return TRUE - var/mob/living/M = A - if(M.has_brain_worms()) + var/mob/living/victim = A + if(victim.has_brain_worms()) to_chat(src, SPAN_WARNING("You cannot take a host who already has a passenger!")) return TRUE - - //TODO generalize borers to enter any mob. Until then, return early. - if(!ishuman(M)) - to_chat(src, SPAN_WARNING("This creature is not sufficiently intelligent to host you.")) + var/obj/item/organ/external/limb = GET_EXTERNAL_ORGAN(victim, BP_HEAD) + if(!limb) + to_chat(src, SPAN_WARNING("\The [victim] does not have anatomy compatible with your lifecycle!")) return TRUE - // end TODO - - var/mob/living/human/H = M - var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(H, BP_HEAD) - if(!E) - to_chat(src, SPAN_WARNING("\The [H] does not have a head!")) + if(BP_IS_PROSTHETIC(limb)) + to_chat(src, SPAN_WARNING("\The [victim]'s head is prosthetic and cannot support your lifecycle!")) return TRUE - if(!H.should_have_organ(BP_BRAIN)) - to_chat(src, SPAN_WARNING("\The [H] does not seem to have a brain cavity to enter.")) + if(!victim.should_have_organ(BP_BRAIN)) + to_chat(src, SPAN_WARNING("\The [victim] does not seem to have a brain cavity to enter.")) return TRUE - if(H.check_head_coverage()) + if(victim.check_head_coverage()) to_chat(src, SPAN_WARNING("You cannot get through that host's protective gear.")) return TRUE - to_chat(M, SPAN_WARNING("Something slimy begins probing at the opening of your ear canal...")) - to_chat(src, SPAN_NOTICE("You slither up [M] and begin probing at their ear canal...")) + to_chat(victim, SPAN_WARNING("Something slimy begins probing at the opening of your ear canal...")) + to_chat(src, SPAN_NOTICE("You slither up [victim] and begin probing at their ear canal...")) set_ability_cooldown(5 SECONDS) - if(!do_after(src, 3 SECONDS, M)) + if(!do_after(src, 3 SECONDS, victim) || host || GET_EXTERNAL_ORGAN(victim, BP_HEAD) != limb || BP_IS_PROSTHETIC(limb) || victim.check_head_coverage()) return TRUE - to_chat(src, SPAN_NOTICE("You wiggle into \the [M]'s ear.")) - if(M.stat == CONSCIOUS) - to_chat(M, SPAN_DANGER("Something wet, cold and slimy wiggles into your ear!")) + to_chat(src, SPAN_NOTICE("You wiggle into \the [victim]'s ear.")) + if(victim.stat == CONSCIOUS) + to_chat(victim, SPAN_DANGER("Something wet, cold and slimy wiggles into your ear!")) - host = M + host = victim host.status_flags |= PASSEMOTES forceMove(host) @@ -60,9 +54,9 @@ borers.add_antagonist_mind(host.mind, 1, borers.faction_name, borers.faction_welcome) if(ishuman(host)) - var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(H, BP_BRAIN) + var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(victim, BP_BRAIN) if(!I) // No brain organ, so the borer moves in and replaces it permanently. replace_brain() - else if(E) // If they're in normally, implant removal can get them out. - LAZYDISTINCTADD(E.implants, src) + else if(limb) // If they're in normally, implant removal can get them out. + LAZYDISTINCTADD(limb.implants, src) return TRUE diff --git a/mods/mobs/borers/mob/borer/borer_hud.dm b/mods/mobs/borers/mob/borer/borer_hud.dm index 8ec7b333971a..79235e827d59 100644 --- a/mods/mobs/borers/mob/borer/borer_hud.dm +++ b/mods/mobs/borers/mob/borer/borer_hud.dm @@ -50,6 +50,7 @@ icon = 'mods/mobs/borers/icons/borer_ui.dmi' alpha = 0 invisibility = INVISIBILITY_MAXIMUM + requires_ui_style = FALSE /obj/screen/borer/handle_click(mob/user, params) if(!isborer(user)) diff --git a/mods/mobs/borers/mob/organ.dm b/mods/mobs/borers/mob/organ.dm index c1f686ade981..80c12e77c94c 100644 --- a/mods/mobs/borers/mob/organ.dm +++ b/mods/mobs/borers/mob/organ.dm @@ -38,5 +38,4 @@ B.leave_host() B.ckey = last_owner.ckey - spawn(0) - qdel(src) + qdel(src) diff --git a/mods/mobs/dionaea/mob/nymph_ui.dm b/mods/mobs/dionaea/mob/nymph_ui.dm index cdd3a3f8c6da..fc44f7639a3b 100644 --- a/mods/mobs/dionaea/mob/nymph_ui.dm +++ b/mods/mobs/dionaea/mob/nymph_ui.dm @@ -23,6 +23,9 @@ UI_ICON_INVENTORY = 'mods/mobs/dionaea/icons/ui_inventory.dmi' ) +/datum/hud/diona_nymph +// action_intent_type = /obj/screen/intent/diona_nymph + /datum/hud/diona_nymph/get_ui_style_data() return GET_DECL(/decl/ui_style/diona) @@ -37,10 +40,9 @@ var/ui_color = get_ui_color() var/ui_alpha = get_ui_alpha() - action_intent = new /obj/screen/intent( null, mymob) // Swap to /obj/screen/intent/binary/diona when interaction code supports it. - mymob.healths = new /obj/screen/diona_health( null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_HEALTH) - src.other = list() - src.adding = list(mymob.healths, action_intent) + mymob.healths = new /obj/screen/diona_health(null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_HEALTH) + other = list() + adding = list(mymob.healths) ..() /obj/screen/diona_health diff --git a/mods/species/ascent/datum/species.dm b/mods/species/ascent/datum/species.dm index 809da7c26fb8..f6bc5dddb055 100644 --- a/mods/species/ascent/datum/species.dm +++ b/mods/species/ascent/datum/species.dm @@ -71,11 +71,6 @@ species_flags = SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_MINOR_CUT spawn_flags = SPECIES_IS_RESTRICTED - unarmed_attacks = list( - /decl/natural_attack/claws/strong/gloves, - /decl/natural_attack/bite/sharp - ) - force_background_info = list( /decl/background_category/heritage = /decl/background_detail/heritage/ascent, /decl/background_category/homeworld = /decl/background_detail/location/kharmaani, diff --git a/mods/species/ascent/effects/razorweb.dm b/mods/species/ascent/effects/razorweb.dm index c8b05c70deb4..0647ffe0c91f 100644 --- a/mods/species/ascent/effects/razorweb.dm +++ b/mods/species/ascent/effects/razorweb.dm @@ -81,7 +81,7 @@ /obj/effect/razorweb/attackby(var/obj/item/thing, var/mob/user) var/destroy_self - if(thing.get_attack_force(user)) + if(thing.expend_attack_force(user)) visible_message(SPAN_DANGER("\The [user] breaks \the [src] with \the [thing]!")) destroy_self = TRUE diff --git a/mods/species/ascent/mobs/nymph/nymph_ui.dm b/mods/species/ascent/mobs/nymph/nymph_ui.dm index c100c95b4cd2..e3b6d1ec70c8 100644 --- a/mods/species/ascent/mobs/nymph/nymph_ui.dm +++ b/mods/species/ascent/mobs/nymph/nymph_ui.dm @@ -38,6 +38,9 @@ UI_ICON_INVENTORY = 'mods/species/ascent/icons/ui_inventory.dmi' ) +/datum/hud/ascent_nymph +// action_intent_type = /obj/screen/intent/ascent_nymph + /datum/hud/ascent_nymph/get_ui_style_data() return GET_DECL(/decl/ui_style/ascent) @@ -51,13 +54,12 @@ var/decl/ui_style/ui_style = get_ui_style_data() var/ui_color = get_ui_color() var/ui_alpha = get_ui_alpha() - molt = new( null, mymob, ui_style, ui_color, ui_alpha) - food = new /obj/screen/food( null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_NUTRITION) - drink = new /obj/screen/drink( null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_HYDRATION) - action_intent = new /obj/screen/intent( null) // Swap to /obj/screen/intent/binary/ascent when interaction code supports it. - mymob.healths = new /obj/screen/ascent_nymph_health( null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_HEALTH) - src.other = list() - src.adding = list(mymob.healths, molt, food, drink, action_intent) + molt = new( null, mymob, ui_style, ui_color, ui_alpha) + food = new /obj/screen/food( null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_NUTRITION) + drink = new /obj/screen/drink( null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_HYDRATION) + mymob.healths = new /obj/screen/ascent_nymph_health(null, mymob, ui_style, ui_color, ui_alpha, UI_ICON_HEALTH) + other = list() + adding = list(mymob.healths, molt, food, drink) ..() /obj/screen/ascent_nymph_health diff --git a/mods/species/bayliens/skrell/datum/species.dm b/mods/species/bayliens/skrell/datum/species.dm index 0d9acdcd8807..c52a6dc67358 100644 --- a/mods/species/bayliens/skrell/datum/species.dm +++ b/mods/species/bayliens/skrell/datum/species.dm @@ -14,12 +14,6 @@ traits = list(/decl/trait/malus/intolerance/protein = TRAIT_LEVEL_MINOR) primitive_form = "Neaera" - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch, - /decl/natural_attack/bite - ) description = "The Skrell are a highly advanced race of amphibians hailing from the system known as Qerr'Vallis. Their society is regimented into \ five different castes which the Qerr'Katish, or Royal Caste, rules over. Skrell are strict herbivores who are unable to eat large quantities of \ @@ -117,27 +111,36 @@ var/obj/item/shoes = H.get_equipped_item(slot_shoes_str) if(!shoes) var/list/bloodDNA - var/list/blood_data = REAGENT_DATA(H.vessel, /decl/material/liquid/blood) + var/list/blood_data = REAGENT_DATA(H.vessel, blood_reagent) if(blood_data) bloodDNA = list(blood_data[DATA_BLOOD_DNA] = blood_data[DATA_BLOOD_TYPE]) else bloodDNA = list() - if(T.simulated) - T.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints, bloodDNA, H.dir, 0, H.get_skin_colour() + "25") // Coming (8c is the alpha value) + T.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints, bloodDNA, H.dir, 0, H.get_skin_colour() + "25") // Coming (25 is the alpha value) if(isturf(old_loc)) var/turf/old_turf = old_loc - if(old_turf.simulated) - old_turf.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints, bloodDNA, 0, H.dir, H.get_skin_colour() + "25") // Going (8c is the alpha value) + old_turf.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints, bloodDNA, 0, H.dir, H.get_skin_colour() + "25") // Going (25 is the alpha value) /decl/species/skrell/check_background() return TRUE +/decl/material/liquid/mucus/skrell + name = "slime" + uid = "chem_mucus_skrell" + lore_text = "A gooey semi-liquid secreted by skrellian skin." + +// Copied from blood. +// TODO: There's not currently a way to check this, which might be a little annoying for forensics. +// But this is just a stopgap to stop Skrell from literally leaking blood everywhere they go. +/decl/material/liquid/mucus/skrell/get_reagent_color(datum/reagents/holder) + var/list/goo_data = REAGENT_DATA(holder, type) + return goo_data?[DATA_BLOOD_COLOR] || ..() + /obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints name = "wet footprints" desc = "They look like still wet tracks left by skrellian feet." + chemical = /decl/material/liquid/mucus/skrell -/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints/dry() - qdel(src) /obj/item/organ/internal/eyes/skrell name = "amphibian eyes" desc = "Large black orbs, belonging to some sort of giant frog by looks of it." diff --git a/mods/species/bayliens/tajaran/datum/species.dm b/mods/species/bayliens/tajaran/datum/species.dm index 231ed1684f0e..19de51ffc360 100644 --- a/mods/species/bayliens/tajaran/datum/species.dm +++ b/mods/species/bayliens/tajaran/datum/species.dm @@ -45,13 +45,6 @@ thirst_factor = DEFAULT_THIRST_FACTOR * 1.2 gluttonous = GLUT_TINY - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch, - /decl/natural_attack/bite/sharp - ) - move_trail = /obj/effect/decal/cleanable/blood/tracks/paw available_background_info = list( diff --git a/mods/species/bayliens/tajaran/datum/species_bodytypes.dm b/mods/species/bayliens/tajaran/datum/species_bodytypes.dm index bd161dac4369..0088067d9b28 100644 --- a/mods/species/bayliens/tajaran/datum/species_bodytypes.dm +++ b/mods/species/bayliens/tajaran/datum/species_bodytypes.dm @@ -28,7 +28,10 @@ eye_low_light_vision_adjustment_speed = 0.3 override_limb_types = list( - BP_TAIL = /obj/item/organ/external/tail/cat + BP_TAIL = /obj/item/organ/external/tail/cat, + BP_HEAD = /obj/item/organ/external/head/sharp_bite, + BP_L_HAND = /obj/item/organ/external/hand/clawed, + BP_R_HAND = /obj/item/organ/external/hand/right/clawed ) default_sprite_accessories = list( diff --git a/mods/species/bayliens/tajaran/machinery/suit_cycler.dm b/mods/species/bayliens/tajaran/machinery/suit_cycler.dm index de0b3b76a702..e3be8485345b 100644 --- a/mods/species/bayliens/tajaran/machinery/suit_cycler.dm +++ b/mods/species/bayliens/tajaran/machinery/suit_cycler.dm @@ -47,5 +47,6 @@ /obj/item/clothing/suit/space/void _feline_onmob_icon = 'mods/species/bayliens/tajaran/icons/clothing/nasa/suit.dmi' + /obj/item/clothing/suit/space/void/excavation _feline_onmob_icon = 'mods/species/bayliens/tajaran/icons/clothing/excavation/suit.dmi' diff --git a/mods/species/bayliens/tritonian/datum/species.dm b/mods/species/bayliens/tritonian/datum/species.dm index a6e415dbce0f..84491dd46cf6 100644 --- a/mods/species/bayliens/tritonian/datum/species.dm +++ b/mods/species/bayliens/tritonian/datum/species.dm @@ -13,10 +13,3 @@ body_temperature = 302 water_soothe_amount = 5 - - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch, - /decl/natural_attack/bite/sharp - ) diff --git a/mods/species/bayliens/tritonian/datum/species_bodytypes.dm b/mods/species/bayliens/tritonian/datum/species_bodytypes.dm index 0e5614f62d50..dadaac398a3d 100644 --- a/mods/species/bayliens/tritonian/datum/species_bodytypes.dm +++ b/mods/species/bayliens/tritonian/datum/species_bodytypes.dm @@ -6,6 +6,9 @@ override_organ_types = list( BP_LUNGS = /obj/item/organ/internal/lungs/gills ) + override_limb_types = list( + BP_HEAD = /obj/item/organ/external/head/sharp_bite + ) /decl/bodytype/human/tritonian/masculine name = "masculine" diff --git a/mods/species/bayliens/unathi/datum/species.dm b/mods/species/bayliens/unathi/datum/species.dm index 43ab46e00492..ad4a508329bd 100644 --- a/mods/species/bayliens/unathi/datum/species.dm +++ b/mods/species/bayliens/unathi/datum/species.dm @@ -24,13 +24,6 @@ /decl/bodytype/lizard, /decl/bodytype/lizard/masculine ) - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/tail, - /decl/natural_attack/claws, - /decl/natural_attack/punch, - /decl/natural_attack/bite/sharp - ) available_accessory_categories = list( SAC_HORNS, diff --git a/mods/species/bayliens/unathi/datum/species_bodytypes.dm b/mods/species/bayliens/unathi/datum/species_bodytypes.dm index 12b4de66522e..226241bc9a1a 100644 --- a/mods/species/bayliens/unathi/datum/species_bodytypes.dm +++ b/mods/species/bayliens/unathi/datum/species_bodytypes.dm @@ -34,19 +34,24 @@ ) override_organ_types = list( - BP_EYES = /obj/item/organ/internal/eyes/lizard, - BP_BRAIN = /obj/item/organ/internal/brain/lizard + BP_EYES = /obj/item/organ/internal/eyes/lizard, + BP_BRAIN = /obj/item/organ/internal/brain/lizard ) - override_limb_types = list(BP_TAIL = /obj/item/organ/external/tail/lizard) + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/lizard, + BP_HEAD = /obj/item/organ/external/head/strong_bite, + BP_L_HAND = /obj/item/organ/external/hand/clawed, + BP_R_HAND = /obj/item/organ/external/hand/right/clawed + ) - cold_level_1 = 280 //Default 260 - Lower is better - cold_level_2 = 220 //Default 200 - cold_level_3 = 130 //Default 120 + cold_level_1 = 280 //Default 260 - Lower is better + cold_level_2 = 220 //Default 200 + cold_level_3 = 130 //Default 120 - heat_level_1 = 420 //Default 360 - Higher is better - heat_level_2 = 480 //Default 400 - heat_level_3 = 1100 //Default 1000 + heat_level_1 = 420 //Default 360 - Higher is better + heat_level_2 = 480 //Default 400 + heat_level_3 = 1100 //Default 1000 heat_discomfort_level = 320 heat_discomfort_strings = list( @@ -81,3 +86,7 @@ /obj/item/organ/external/tail/lizard tail_icon = 'mods/species/bayliens/unathi/icons/tail.dmi' tail_animation_states = 9 + +/obj/item/organ/external/tail/lizard/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/tail) + return unarmed_attack diff --git a/mods/species/drakes/species.dm b/mods/species/drakes/species.dm index cd57051614f9..e5b53bae100c 100644 --- a/mods/species/drakes/species.dm +++ b/mods/species/drakes/species.dm @@ -20,10 +20,7 @@ /decl/pronouns/male, /decl/pronouns/female ) - unarmed_attacks = list( - /decl/natural_attack/bite/sharp/drake, - /decl/natural_attack/claws/strong/drake - ) + available_background_info = list( /decl/background_category/heritage = list(/decl/background_detail/heritage/grafadreka), /decl/background_category/homeworld = list(/decl/background_detail/location/grafadreka), diff --git a/mods/species/drakes/species_bodytypes.dm b/mods/species/drakes/species_bodytypes.dm index a04b7513377e..aae52bd678ac 100644 --- a/mods/species/drakes/species_bodytypes.dm +++ b/mods/species/drakes/species_bodytypes.dm @@ -38,7 +38,8 @@ override_limb_types = list( BP_TAIL = /obj/item/organ/external/tail/grafadreka, BP_L_HAND = /obj/item/organ/external/hand/quadruped/grafadreka, - BP_R_HAND = /obj/item/organ/external/hand/right/quadruped/grafadreka + BP_R_HAND = /obj/item/organ/external/hand/right/quadruped/grafadreka, + BP_HEAD = /obj/item/organ/external/head/gripper/grafadreka ) base_color = "#608894" base_eye_color = COLOR_SILVER @@ -202,9 +203,14 @@ /datum/ability_handler/predator/grafadreka/hatchling ) z_flags = 0 + // TODO: weaker attack subtypes for the baby override_limb_types = list( - BP_TAIL = /obj/item/organ/external/tail/grafadreka/hatchling + BP_TAIL = /obj/item/organ/external/tail/grafadreka/hatchling, + BP_L_HAND = /obj/item/organ/external/hand/quadruped/grafadreka, + BP_R_HAND = /obj/item/organ/external/hand/right/quadruped/grafadreka, + BP_HEAD = /obj/item/organ/external/head/gripper/grafadreka ) + default_emotes = list( /decl/emote/audible/drake_hatchling_growl, /decl/emote/audible/drake_hatchling_whine, @@ -307,6 +313,10 @@ _base_attack_force = 8 needs_attack_dexterity = DEXTERITY_NONE +/obj/item/organ/external/hand/quadruped/grafadreka/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/drake) + return unarmed_attack + /obj/item/organ/external/hand/quadruped/grafadreka/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance, decl/bodytype/new_bodytype) . = ..() item_flags |= ITEM_FLAG_NO_BLUDGEON @@ -323,6 +333,10 @@ _base_attack_force = 8 needs_attack_dexterity = DEXTERITY_NONE +/obj/item/organ/external/hand/right/quadruped/grafadreka/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/drake) + return unarmed_attack + /obj/item/organ/external/hand/right/quadruped/grafadreka/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance, decl/bodytype/new_bodytype) . = ..() item_flags |= ITEM_FLAG_NO_BLUDGEON @@ -334,3 +348,7 @@ /obj/item/organ/external/hand/right/quadruped/grafadreka/set_bodytype(decl/bodytype/new_bodytype, override_material, apply_to_internal_organs) override_material = /decl/material/solid/organic/bone . = ..() + +/obj/item/organ/external/head/gripper/grafadreka/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/sharp/drake) + return unarmed_attack diff --git a/mods/species/neoavians/clothing.dm b/mods/species/neoavians/clothing.dm index e7d90e623eaa..db6790ea35e7 100644 --- a/mods/species/neoavians/clothing.dm +++ b/mods/species/neoavians/clothing.dm @@ -18,11 +18,12 @@ _avian_onmob_icon = null //Backpacks & tanks - /obj/item/backpack/satchel _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/satchel.dmi' //Radsuits (theyre essential?) +/obj/item/clothing/head/radiation + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/head/rad_helm.dmi' /obj/item/clothing/head/radiation _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/head/rad_helm.dmi' @@ -77,12 +78,16 @@ name = "stylish uniform" icon = 'mods/species/neoavians/icons/clothing/under/stylish_form.dmi' +/obj/item/clothing/shoes + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/feet/shoes.dmi' + /obj/item/clothing/shoes/avian name = "small shoes" icon = 'mods/species/neoavians/icons/clothing/feet/shoes.dmi' color = COLOR_GRAY bodytype_equip_flags = BODY_EQUIP_FLAG_AVIAN _avian_onmob_icon = null + icon = 'mods/species/neoavians/icons/clothing/feet/shoes.dmi' /obj/item/clothing/shoes/avian/footwraps name = "cloth footwraps" diff --git a/mods/species/neoavians/datum/species.dm b/mods/species/neoavians/datum/species.dm index a0bfea025ed0..065b6c6d932d 100644 --- a/mods/species/neoavians/datum/species.dm +++ b/mods/species/neoavians/datum/species.dm @@ -52,12 +52,6 @@ swap_flags = MONKEY|SIMPLE_ANIMAL push_flags = MONKEY|SIMPLE_ANIMAL - unarmed_attacks = list( - /decl/natural_attack/bite/sharp, - /decl/natural_attack/claws, - /decl/natural_attack/stomp/weak - ) - available_background_info = list( /decl/background_category/heritage = list( /decl/background_detail/heritage/neoavian, diff --git a/mods/species/neoavians/datum/species_bodytypes.dm b/mods/species/neoavians/datum/species_bodytypes.dm index 35eb54d9a7ff..a83f74e9b60c 100644 --- a/mods/species/neoavians/datum/species_bodytypes.dm +++ b/mods/species/neoavians/datum/species_bodytypes.dm @@ -39,6 +39,13 @@ base_eye_color = "#f5c842" mob_size = MOB_SIZE_SMALL nail_noun = "talons" + override_limb_types = list( + BP_L_FOOT = /obj/item/organ/external/foot/avian, + BP_R_FOOT = /obj/item/organ/external/foot/right/avian, + BP_L_HAND = /obj/item/organ/external/hand/clawed, + BP_R_HAND = /obj/item/organ/external/hand/right/clawed, + BP_HEAD = /obj/item/organ/external/head/sharp_bite + ) has_organ = list( BP_STOMACH = /obj/item/organ/internal/stomach, BP_HEART = /obj/item/organ/internal/heart, @@ -170,6 +177,14 @@ ) . = ..() +/obj/item/organ/external/foot/avian/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/stomp/weak) + return unarmed_attack + +/obj/item/organ/external/foot/right/avian/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/stomp/weak) + return unarmed_attack + /obj/item/organ/external/tail/avian/get_tail() if(istype(bodytype, /decl/bodytype/avian)) var/decl/bodytype/avian/bird_bod = bodytype diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi index fe7e1534a7ea..645c2a006bf7 100644 Binary files a/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi new file mode 100644 index 000000000000..779b0d77fe46 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi new file mode 100644 index 000000000000..c84f8e938c69 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi differ diff --git a/mods/species/neoavians/machinery/suit_cycler.dm b/mods/species/neoavians/machinery/suit_cycler.dm index 2fd6323e6edc..4397f39c94db 100644 --- a/mods/species/neoavians/machinery/suit_cycler.dm +++ b/mods/species/neoavians/machinery/suit_cycler.dm @@ -11,7 +11,6 @@ _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi' //excavation - /obj/item/clothing/suit/space/void/excavation _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/suit.dmi' @@ -19,7 +18,6 @@ _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi' //engineering - /obj/item/clothing/head/helmet/space/void/engineering _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/engineering/helmet.dmi' @@ -33,15 +31,19 @@ _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/atmos/suit.dmi' //medical - /obj/item/clothing/suit/space/void/medical _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical/suit.dmi' /obj/item/clothing/head/helmet/space/void/medical _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi' -//security +/obj/item/clothing/suit/space/void/medical/alt + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi' +/obj/item/clothing/head/helmet/space/void/medical/alt + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi' + +//security /obj/item/clothing/head/helmet/space/void/security _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/sec/helmet.dmi' @@ -49,7 +51,6 @@ _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/sec/suit.dmi' //salvage - /obj/item/clothing/head/helmet/space/void/engineering/salvage _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/salvage/helmet.dmi' diff --git a/mods/species/serpentid/datum/species.dm b/mods/species/serpentid/datum/species.dm index 5d9b15171f86..a261ea256d49 100644 --- a/mods/species/serpentid/datum/species.dm +++ b/mods/species/serpentid/datum/species.dm @@ -60,8 +60,6 @@ swap_flags = ALLMOBS move_trail = /obj/effect/decal/cleanable/blood/tracks/snake - unarmed_attacks = list(/decl/natural_attack/forelimb_slash) - pain_emotes_with_pain_level = list( list(/decl/emote/audible/bug_hiss) = 40 ) @@ -101,12 +99,6 @@ return FALSE -/decl/species/serpentid/can_shred(var/mob/living/human/H, var/ignore_intent, var/ignore_antag) - if(!H.get_equipped_item(slot_handcuffed_str) || H.buckled) - return ..(H, ignore_intent, TRUE) - else - return 0 - /decl/species/serpentid/handle_movement_delay_special(var/mob/living/human/victim) var/tally = 0 victim.remove_cloaking_source(src) diff --git a/mods/species/serpentid/datum/species_bodytypes.dm b/mods/species/serpentid/datum/species_bodytypes.dm index 0bf66ff375fa..947019f4db7e 100644 --- a/mods/species/serpentid/datum/species_bodytypes.dm +++ b/mods/species/serpentid/datum/species_bodytypes.dm @@ -34,15 +34,16 @@ BP_HEAD = list("path" = /obj/item/organ/external/head/insectoid/serpentid), BP_L_ARM = list("path" = /obj/item/organ/external/arm/insectoid), BP_L_HAND = list("path" = /obj/item/organ/external/hand/insectoid), - BP_L_HAND_UPPER = list("path" = /obj/item/organ/external/hand/insectoid/upper), + BP_L_HAND_UPPER = list("path" = /obj/item/organ/external/hand/insectoid/upper/serpentid), BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/insectoid), BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/insectoid), - BP_R_HAND_UPPER = list("path" = /obj/item/organ/external/hand/right/insectoid/upper), + BP_R_HAND_UPPER = list("path" = /obj/item/organ/external/hand/right/insectoid/upper/serpentid), BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/insectoid/serpentid), BP_L_LEG = list("path" = /obj/item/organ/external/leg/insectoid/serpentid), BP_L_FOOT = list("path" = /obj/item/organ/external/foot/insectoid/serpentid), BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/insectoid/serpentid) ) + appearance_descriptors = list( /datum/appearance_descriptor/height = 1.75, /datum/appearance_descriptor/body_length = 1 @@ -122,3 +123,11 @@ name = "green" icon_base = 'mods/species/serpentid/icons/body_green.dmi' uid = "bodytype_serpentid_green" + +/obj/item/organ/external/hand/insectoid/upper/serpentid/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/forelimb_slash) + return unarmed_attack + +/obj/item/organ/external/hand/right/insectoid/upper/serpentid/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/forelimb_slash) + return unarmed_attack diff --git a/mods/species/utility_frames/species.dm b/mods/species/utility_frames/species.dm index 55554ae957cd..2fa4f50fe438 100644 --- a/mods/species/utility_frames/species.dm +++ b/mods/species/utility_frames/species.dm @@ -30,11 +30,6 @@ preview_outfit = null - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch - ) available_pronouns = list( /decl/pronouns, /decl/pronouns/neuter diff --git a/mods/species/vox/datum/species.dm b/mods/species/vox/datum/species.dm index 02f7fed9313f..eac1ad157862 100644 --- a/mods/species/vox/datum/species.dm +++ b/mods/species/vox/datum/species.dm @@ -32,14 +32,6 @@ /mob/living/human/proc/toggle_vox_pressure_seal ) - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/claws/strong/gloves, - /decl/natural_attack/punch, - /decl/natural_attack/bite/strong - ) - rarity_value = 4 description = {"The Vox are the broken remnants of a once-proud race, now reduced to little more diff --git a/mods/species/vox/datum/species_bodytypes.dm b/mods/species/vox/datum/species_bodytypes.dm index cff74b6141d9..092cfeb50b96 100644 --- a/mods/species/vox/datum/species_bodytypes.dm +++ b/mods/species/vox/datum/species_bodytypes.dm @@ -30,9 +30,13 @@ BP_BRAIN ) override_limb_types = list( - BP_GROIN = /obj/item/organ/external/groin/vox, - BP_TAIL = /obj/item/organ/external/tail/vox + BP_GROIN = /obj/item/organ/external/groin/vox, + BP_TAIL = /obj/item/organ/external/tail/vox, + BP_L_HAND = /obj/item/organ/external/hand/vox, + BP_R_HAND = /obj/item/organ/external/hand/right/vox, + BP_HEAD = /obj/item/organ/external/head/strong_bite ) + has_organ = list( BP_STOMACH = /obj/item/organ/internal/stomach/vox, BP_HEART = /obj/item/organ/internal/heart/vox, @@ -172,3 +176,11 @@ /obj/item/organ/external/tail/vox/stanchion tail_icon = 'mods/species/vox/icons/body/stanchion/body.dmi' + +/obj/item/organ/external/hand/vox/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/gloves) + return unarmed_attack + +/obj/item/organ/external/hand/right/vox/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/gloves) + return unarmed_attack diff --git a/mods/species/vox/datum/unit_testing.dm b/mods/species/vox/datum/unit_testing.dm index 1026f897cad4..1010d534842d 100644 --- a/mods/species/vox/datum/unit_testing.dm +++ b/mods/species/vox/datum/unit_testing.dm @@ -4,7 +4,7 @@ /datum/unit_test/mob_damage/vox name = "MOB: Vox damage check template" - template = /datum/unit_test/mob_damage/vox + abstract_type = /datum/unit_test/mob_damage/vox mob_type = /mob/living/human/vox /datum/unit_test/mob_damage/vox/brute diff --git a/mods/~compatibility/patches/fantasy.dm b/mods/~compatibility/patches/fantasy.dm index c176360672c6..4b4d6f7feaba 100644 --- a/mods/~compatibility/patches/fantasy.dm +++ b/mods/~compatibility/patches/fantasy.dm @@ -1,4 +1,9 @@ // Override drake lore and names for the fantasy modpack. #ifdef MODPACK_DRAKES #include "fantasy/drake_fantasy.dm" -#endif \ No newline at end of file +#endif + +// Make whetstones available for the fantasy modpack/ +#ifdef MODPACK_ITEM_SHARPENING +#include "fantasy/whetstone_fantasy.dm" +#endif diff --git a/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm b/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm new file mode 100644 index 000000000000..b2821d26fa67 --- /dev/null +++ b/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm @@ -0,0 +1,7 @@ +// Make whetstones available in character generation. +/decl/loadout_option/fantasy/utility/whetstone + name = "whetstone" + path = /obj/item/whetstone + available_materials = null + loadout_flags = null + uid = "gear_fantasy_whetstone" diff --git a/nano/templates/radio_basic.tmpl b/nano/templates/radio_basic.tmpl index fc94e17029cd..b3ba6f4830ac 100644 --- a/nano/templates/radio_basic.tmpl +++ b/nano/templates/radio_basic.tmpl @@ -138,12 +138,11 @@ Used In File(s): /code/game/objects/item/devices/radio/radio.dm {{:value.display_name}}
- {{if value.secure_channel}} - {{:helper.link('On', null, {'ch_name' : value.chan, 'listen' : 1}, value.listening ? 'selected' : null)}} - {{:helper.link('Off', null, {'ch_name' : value.chan, 'listen' : 0}, value.listening ? null : 'selected')}} - {{else}} - {{:helper.link('Switch', null, {'spec_freq' : value.chan}, data.rawfreq == value.chan ? 'selected' : null)}} - {{/if}} + {{:helper.link('On', null, {'ch_name' : value.chan, 'listen' : 1}, value.listening ? 'selected' : null)}} + {{:helper.link('Off', null, {'ch_name' : value.chan, 'listen' : 0}, value.listening ? null : 'selected')}} + {{if !value.secure_channel}} + {{:helper.link('Switch', null, {'spec_freq' : value.chan}, data.rawfreq == value.chan ? 'selected' : null)}} + {{/if}}
{{/for}} {{/if}} diff --git a/nebula.dme b/nebula.dme index a5636e8735ab..8af51001eb56 100644 --- a/nebula.dme +++ b/nebula.dme @@ -10,6 +10,7 @@ #define DEBUG // END_PREFERENCES // BEGIN_INCLUDE +#include "code\___compile_options.dm" #include "code\___opendream_linting.dm" #include "code\__globals.dm" #include "code\_macros.dm" @@ -20,7 +21,6 @@ #include "code\__datastructures\stack.dm" #include "code\__defines\_byond_version_compat.dm" #include "code\__defines\_compile_helpers.dm" -#include "code\__defines\_compile_options.dm" #include "code\__defines\_planes+layers.dm" #include "code\__defines\_tick.dm" #include "code\__defines\admin.dm" @@ -60,6 +60,7 @@ #include "code\__defines\intent.dm" #include "code\__defines\interactions.dm" #include "code\__defines\inventory_sizes.dm" +#include "code\__defines\item_effects.dm" #include "code\__defines\items_clothing.dm" #include "code\__defines\jobs.dm" #include "code\__defines\languages.dm" @@ -220,7 +221,6 @@ #include "code\_onclick\hud\screen\screen_radial.dm" #include "code\_onclick\hud\screen\screen_resist.dm" #include "code\_onclick\hud\screen\screen_robot_drop_grab.dm" -#include "code\_onclick\hud\screen\screen_robot_intent.dm" #include "code\_onclick\hud\screen\screen_robot_inventory.dm" #include "code\_onclick\hud\screen\screen_robot_modules.dm" #include "code\_onclick\hud\screen\screen_robot_panel.dm" @@ -282,8 +282,8 @@ #include "code\controllers\subsystems\mapping.dm" #include "code\controllers\subsystems\misc_late.dm" #include "code\controllers\subsystems\overlays.dm" +#include "code\controllers\subsystems\overmap.dm" #include "code\controllers\subsystems\pathfinding.dm" -#include "code\controllers\subsystems\plants.dm" #include "code\controllers\subsystems\radiation.dm" #include "code\controllers\subsystems\shuttle.dm" #include "code\controllers\subsystems\skybox.dm" @@ -327,7 +327,7 @@ #include "code\controllers\subsystems\processing\mobs.dm" #include "code\controllers\subsystems\processing\nano.dm" #include "code\controllers\subsystems\processing\obj.dm" -#include "code\controllers\subsystems\processing\overmap.dm" +#include "code\controllers\subsystems\processing\plants.dm" #include "code\controllers\subsystems\processing\processing.dm" #include "code\controllers\subsystems\processing\projectiles.dm" #include "code\controllers\subsystems\processing\temperature.dm" @@ -753,7 +753,6 @@ #include "code\game\atoms_movable_overlay.dm" #include "code\game\atoms_temperature.dm" #include "code\game\base_turf.dm" -#include "code\game\images.dm" #include "code\game\movietitles.dm" #include "code\game\response_team.dm" #include "code\game\sound.dm" @@ -1075,6 +1074,7 @@ #include "code\game\objects\items\_item_materials.dm" #include "code\game\objects\items\_item_melting.dm" #include "code\game\objects\items\_item_reagents.dm" +#include "code\game\objects\items\_item_sharpness.dm" #include "code\game\objects\items\apc_frame.dm" #include "code\game\objects\items\blackout.dm" #include "code\game\objects\items\blueprints.dm" @@ -2744,6 +2744,7 @@ #include "code\modules\materials\definitions\gasses\material_gas_mundane.dm" #include "code\modules\materials\definitions\liquids\_mat_liquid.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_chemistry.dm" +#include "code\modules\materials\definitions\liquids\materials_liquid_mundane.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_solvents.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_soup.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_toxins.dm" diff --git a/test/check-paths.sh b/test/check-paths.sh index b88c7775cf26..852c681ae6ca 100755 --- a/test/check-paths.sh +++ b/test/check-paths.sh @@ -23,34 +23,35 @@ exactly() { # exactly N name search [mode] [filter] # With the potential exception of << if you increase any of these numbers you're probably doing it wrong # Additional exception August 2020: \b is a regex symbol as well as a BYOND macro. -exactly 1 "escapes" '\\\\(red|blue|green|black|b|i[^mc])' -exactly 8 "Del()s" '\WDel\(' +exactly 3 "escapes" '\\(red|blue|green|black|b|i[^mc])' +exactly 3 "Del()s" '(?> uses" '>>(?!>)' -P +exactly 1 "world<< uses" 'world\s*<<' +exactly 74 "'in world' uses" '\s+\bin world\b(?=\s*$|\s*//|\s*\))' -P +exactly 1 "world.log<< uses" 'world.log\s*<<' +exactly 18 "<< uses" '(?> uses" '(?\\])>>(?!>)' -P exactly 0 "incorrect indentations" '^( {4,})' -P exactly 23 "text2path uses" 'text2path' -exactly 4 "update_icon() override" '/update_icon\((.*)\)' -P -exactly 0 "goto uses" 'goto ' +exactly 4 "update_icon() overrides" '\/update_icon\(' -P +exactly 0 "goto uses" '\bgoto\b' exactly 9 "atom/New uses" '^/(obj|atom|area|mob|turf).*/New\(' exactly 1 "decl/New uses" '^/decl.*/New\(' -exactly 0 "tag uses" '\stag = ' -P '*.dmm' -exactly 3 "unmarked globally scoped variables" '^(/|)var/(?!global)' -P -exactly 0 "global-marked member variables" '\t(/|)var.*/global/.+' -P -exactly 0 "static-marked globally scoped variables" '^(/|)var.*/static/.+' -P +exactly 3 "tag uses" '(?