diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 67ac1eca98f..15f4a756de8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -21,7 +21,7 @@ add: Added more things del: Removed old things tweak: tweaked a few things balance: rebalanced something -fix: fixed a few things +bugfix: fixed a few things soundadd: added a new sound thingy sounddel: removed an old sound thingy imageadd: added some icons and images diff --git a/SpacemanDMM.toml b/SpacemanDMM.toml index 1dcd669c09f..879c739a9bc 100644 --- a/SpacemanDMM.toml +++ b/SpacemanDMM.toml @@ -10,3 +10,44 @@ disallow_relative_proc_definitions = true [debugger] engine = "auxtools" + +[diagnostics] +# Raised by DreamChecker +disabled_directive = "error" +sets_directive_twice = "error" +invalid_lint_directive_value = "error" +invalid_set_value = "error" +unknown_linter_setting = "error" +override_missing_keyword_arg = "error" +must_not_override = "error" +must_call_parent = "error" +final_var = "error" +private_proc = "error" +protected_proc = "error" +private_var = "error" +protected_var = "error" +must_be_pure = "error" +must_not_sleep = "error" +redefined_proc = "off" +ambiguous_in_lhs = "error" +ambiguous_not_bitwise = "error" +no_typehint_implicit_new = "error" +field_access_static_type = "error" +proc_call_static_type = "error" +proc_has_no_parent = "error" +no_operator_overload = "error" +unreachable_code = "error" +control_condition_static = "error" +if_condition_determinate = "error" +loop_condition_determinate = "error" + +# Raised by Lexer +integer_precision_loss = "error" + +# Raised by Parser +duplicate_include = "error" +macro_redefined = "error" +macro_undefined_no_definition = "error" + +# Raised by Object Tree +override_precedes_definition = "error" diff --git a/code/__defines/ZAS.dm b/code/__defines/ZAS.dm index 94d15e28462..fa25d2f16a5 100644 --- a/code/__defines/ZAS.dm +++ b/code/__defines/ZAS.dm @@ -1,3 +1,18 @@ + +/* + Uncomment this to enable ZAS debugging tools. While ghosted, you will see a visualization of the atmos status of turfs. + Green turfs are zones that are existing happily. + Yellow-orange turfs are a zone that has recently been merged into another zone. + Red turfs are turfs are an invalidated zone. Invalid zones are zones that were destroyed. + White/overlay-less turfs are turfs that are the origin point of a zone. This is completely useless information. + Purple outlines indicate the turf was marked for an update by SSair, and is in its processing list. + In addition, all ZAS-related datums and turfs will have a "verbose" var. Set this to 1 using View Variables to get robust to_chat()s about activity. + Finally, this is a friendly reminder that using Debug Verbs gives access to the Zone Info and Test ZAS Connection verbs when you right click a turf. + + Addendum: + There are additional debug overlays that use ZAS_ZONE_BLOCKER and ZAS_DIRECTIONAL_BLOCKER. + They take priority over standard overlays, displaying directional airflow, and are generally not needed so they are commented out by default. +*/ //#define ZASDBG #define MULTIZAS diff --git a/code/__defines/_tick.dm b/code/__defines/_tick.dm index 63f8b443420..2c33329a612 100644 --- a/code/__defines/_tick.dm +++ b/code/__defines/_tick.dm @@ -20,6 +20,8 @@ /// runs stoplag if tick_usage is above the limit #define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 ) +#define UNTIL(X) while(!(X)) stoplag() + //"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks //percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio) //collapsed to percent_of_tick_used * tick_lag diff --git a/code/__defines/armor.dm b/code/__defines/armor.dm index 491b929afc4..155ccb22f4a 100644 --- a/code/__defines/armor.dm +++ b/code/__defines/armor.dm @@ -45,3 +45,6 @@ #define ARMOR_ENERGY_RESISTANT 40 #define ARMOR_ENERGY_STRONG 75 #define ARMOR_ENERGY_SHIELDED 100 + +/**Armor piercing value that will bypass any armors completely */ +#define ARMOR_PIERCING_BYPASSED INFINITY \ No newline at end of file diff --git a/code/__defines/aspects.dm b/code/__defines/aspects.dm index c58f7ef8595..a0791e172e7 100644 --- a/code/__defines/aspects.dm +++ b/code/__defines/aspects.dm @@ -11,52 +11,61 @@ #define ASPECTS_PHYSICAL BITFLAG(0) #define ASPECTS_MENTAL BITFLAG(1) -#define DEFINE_ROBOLIMB_MODEL_ASPECTS(MODEL_PATH, MODEL_ID, COST) \ -/decl/aspect/prosthetic_limb/left_hand/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/left_hand; \ - aspect_cost = COST; \ - base_type = /decl/aspect/prosthetic_limb/left_hand; \ -} \ -/decl/aspect/prosthetic_limb/left_arm/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/left_arm; \ - aspect_cost = COST; \ - base_type = /decl/aspect/prosthetic_limb/left_arm; \ -} \ -/decl/aspect/prosthetic_limb/right_hand/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/right_hand; \ - aspect_cost = COST; \ - base_type = /decl/aspect/prosthetic_limb/right_hand; \ -} \ -/decl/aspect/prosthetic_limb/right_arm/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/right_arm; \ - aspect_cost = COST; \ - base_type = /decl/aspect/prosthetic_limb/right_arm; \ -} \ -/decl/aspect/prosthetic_limb/left_foot/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/left_foot; \ - aspect_cost = COST; \ - base_type = /decl/aspect/prosthetic_limb/left_foot; \ -} \ -/decl/aspect/prosthetic_limb/left_leg/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/left_leg; \ - base_type = /decl/aspect/prosthetic_limb/left_leg; \ - aspect_cost = COST; \ -} \ -/decl/aspect/prosthetic_limb/right_foot/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/right_foot; \ - base_type = /decl/aspect/prosthetic_limb/right_foot; \ - aspect_cost = COST; \ -} \ -/decl/aspect/prosthetic_limb/right_leg/##MODEL_ID { \ - model = MODEL_PATH; \ - parent = /decl/aspect/prosthetic_limb/right_leg; \ - base_type = /decl/aspect/prosthetic_limb/right_leg; \ - aspect_cost = COST; \ -} \ No newline at end of file +#define DEFINE_ROBOLIMB_MODEL_ASPECTS_WITH_SPECIES_BODYTYPE(MODEL_PATH, MODEL_ID, COST, SPECIES, BODYTYPE) \ +/decl/aspect/prosthetic_limb/left_hand/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/left_hand; \ + aspect_cost = COST * 0.5; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/left_arm/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/left_arm; \ + aspect_cost = COST; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/right_hand/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/right_hand; \ + aspect_cost = COST * 0.5; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/right_arm/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/right_arm; \ + aspect_cost = COST; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/left_foot/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/left_foot; \ + aspect_cost = COST * 0.5; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/left_leg/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/left_leg; \ + aspect_cost = COST; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/right_foot/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/right_foot; \ + aspect_cost = COST * 0.5; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} \ +/decl/aspect/prosthetic_limb/right_leg/##MODEL_ID { \ + model = MODEL_PATH; \ + parent = /decl/aspect/prosthetic_limb/right_leg; \ + aspect_cost = COST; \ + check_bodytype = BODYTYPE; \ + check_species = SPECIES; \ +} +#define DEFINE_ROBOLIMB_MODEL_ASPECTS(MODEL_PATH, MODEL_ID, COST) DEFINE_ROBOLIMB_MODEL_ASPECTS_WITH_SPECIES_BODYTYPE(MODEL_PATH, MODEL_ID, COST, null, null) diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm index 86b875b0fce..721851ffaf3 100644 --- a/code/__defines/chemistry.dm +++ b/code/__defines/chemistry.dm @@ -6,6 +6,7 @@ #define CHEM_TOUCH 1 #define CHEM_INGEST 2 #define CHEM_INJECT 3 +#define CHEM_INHALE 4 #define MINIMUM_CHEMICAL_VOLUME 0.01 diff --git a/code/__defines/colors.dm b/code/__defines/colors.dm index 7758ee595b9..a3523c8f7bb 100644 --- a/code/__defines/colors.dm +++ b/code/__defines/colors.dm @@ -93,15 +93,16 @@ #define COLOR_ASTEROID_ROCK "#735555" #define COLOR_DIAMOND "#d8d4ea" -#define PIPE_COLOR_GREY "#808080" -#define PIPE_COLOR_RED "#ff0000" -#define PIPE_COLOR_BLUE "#0000ff" -#define PIPE_COLOR_CYAN "#00ffff" -#define PIPE_COLOR_GREEN "#00ff00" -#define PIPE_COLOR_YELLOW "#ffcc00" -#define PIPE_COLOR_BLACK "#444444" -#define PIPE_COLOR_ORANGE "#b95a00" +#define PIPE_COLOR_GREY "#808080" +#define PIPE_COLOR_RED "#ff0000" +#define PIPE_COLOR_BLUE "#0000ff" +#define PIPE_COLOR_CYAN "#00ffff" +#define PIPE_COLOR_GREEN "#00ff00" +#define PIPE_COLOR_YELLOW "#ffcc00" +#define PIPE_COLOR_BLACK "#444444" +#define PIPE_COLOR_ORANGE "#b95a00" #define PIPE_COLOR_WHITE "#ffffff" +#define PIPE_COLOR_PURPLE "#880088" #define COMMS_COLOR_DEFAULT "#ff00ff" #define COMMS_COLOR_ENTERTAIN "#666666" @@ -198,14 +199,14 @@ #define RANDOM_RGB rgb(rand(0,255), rand(0,255), rand(0,255)) // Codex category colours. -#define CODEX_COLOR_LORE "#abdb9b" -#define CODEX_COLOR_MECHANICS "#9ebcd8" -#define CODEX_COLOR_ANTAG "#e5a2a2" - #define COLOR_WEBHOOK_DEFAULT 0x8bbbd5 // Colors for input/hotkey panel. #define COLOR_INPUT_DISABLED "#f0f0f0" #define COLOR_INPUT_ENABLED "#d3b5b5" +#define COLOR_DARKMODE_BACKGROUND "#202020" +#define COLOR_DARKMODE_DARKBACKGROUND "#171717" +#define COLOR_DARKMODE_TEXT "#a4bad6" + #define COLORED_SQUARE(COLOR) "___" diff --git a/code/__defines/computers.dm b/code/__defines/computers.dm index 8b14c6b42e4..710816cec40 100644 --- a/code/__defines/computers.dm +++ b/code/__defines/computers.dm @@ -33,6 +33,7 @@ #define PROGRAM_STATE_KILLED 0 #define PROGRAM_STATE_BACKGROUND 1 #define PROGRAM_STATE_ACTIVE 2 +#define PROGRAM_STATE_BROWSER 3 #define PROG_MISC "Miscellaneous" #define PROG_ENG "Engineering" @@ -54,4 +55,23 @@ // Caps for network logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it. #define MAX_NETWORK_LOGS 100 -#define MIN_NETWORK_LOGS 10 \ No newline at end of file +#define MIN_NETWORK_LOGS 10 + +// Default directories referenced by the OS or programs. +#define OS_PROGRAMS_DIR "programs" +#define OS_RECORDS_DIR "records" +#define OS_ACCOUNTS_DIR "accounts" +#define OS_DOCUMENTS_DIR "documents" +#define OS_LOGS_DIR "logs" + +// Return codes for file storage. +#define OS_FILE_SUCCESS 1 +#define OS_HARDDRIVE_ERROR 0 +#define OS_FILE_NOT_FOUND -1 +#define OS_DIR_NOT_FOUND -2 +#define OS_FILE_EXISTS -3 +#define OS_FILE_NO_READ -4 +#define OS_FILE_NO_WRITE -5 +#define OS_HARDDRIVE_SPACE -6 +#define OS_NETWORK_ERROR -7 +#define OS_BAD_NAME -8 \ No newline at end of file diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm index 3ae667b04da..feb53ecc9d3 100644 --- a/code/__defines/damage_organs.dm +++ b/code/__defines/damage_organs.dm @@ -33,6 +33,15 @@ #define FIRE_DAMAGE_MODIFIER 0.0215 // Higher values result in more external fire damage to the skin. (default 0.0215) #define AIR_DAMAGE_MODIFIER 2.025 // More means less damage from hot air scalding lungs, less = more damage. (default 2.025) +//Armor Resistance Types +#define ARMOR_MELEE "melee" //Blunt and cutting weapons +#define ARMOR_BULLET "bullet" //Kinectic projectiles +#define ARMOR_BOMB "bomb" //Explosions +#define ARMOR_LASER "laser" //Laser weapons +#define ARMOR_ENERGY "energy" //Intense heat, electricity +#define ARMOR_RAD "rad" //Ionizing radiation +#define ARMOR_BIO "bio" //Biohazards toxin damage + // Organ defines. #define ORGAN_CUT_AWAY BITFLAG(0) // The organ is in the process of being surgically removed. #define ORGAN_BLEEDING BITFLAG(1) // The organ is currently bleeding. diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm index e5f89e3caaa..2e2a738150d 100644 --- a/code/__defines/flags.dm +++ b/code/__defines/flags.dm @@ -63,6 +63,7 @@ The latter will result in a linter warning and will not work correctly. #define OBJ_FLAG_ROTATABLE BITFLAG(2) // Can be rotated with alt-click #define OBJ_FLAG_NOFALL BITFLAG(3) // Will prevent mobs from falling #define OBJ_FLAG_MOVES_UNSUPPORTED BITFLAG(4) // Object moves with shuttle transition even if turf below is a background turf. +#define OBJ_FLAG_HOLLOW BITFLAG(5) // Modifies initial matter values to be lower than w_class normally sets. // Item-level flags (/obj/item/item_flags) #define ITEM_FLAG_NO_BLUDGEON BITFLAG(0) // When an item has this it produces no "X has been hit by Y with Z" message with the default handler. @@ -79,7 +80,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_HOLLOW BITFLAG(14) // Modifies initial matter values to be lower than w_class normally sets. +#define ITEM_FLAG_CAN_TAPE BITFLAG(14) //Whether the item can be be taped onto something using tape // Flags for pass_flags (/atom/var/pass_flags) #define PASS_FLAG_TABLE BITFLAG(0) @@ -91,4 +92,12 @@ The latter will result in a linter warning and will not work correctly. #define OVERMAP_SECTOR_BASE BITFLAG(0) // Whether or not this sector is a starting sector. Z levels contained in this sector are added to station_levels #define OVERMAP_SECTOR_KNOWN BITFLAG(1) // Makes the sector show up on nav computers #define OVERMAP_SECTOR_IN_SPACE BITFLAG(2) // If the sector can be accessed by drifting off the map edge -#define OVERMAP_SECTOR_UNTARGETABLE BITFLAG(3) // If the sector is untargetable by missiles. \ No newline at end of file +#define OVERMAP_SECTOR_UNTARGETABLE BITFLAG(3) // If the sector is untargetable by missiles. + +// Flags for reagent presentation (/obj/item/chems/var/presentation_flags) +#define PRESENTATION_FLAG_NAME BITFLAG(0) // This chems subtype presents the name of its main reagent/cocktail. +#define PRESENTATION_FLAG_DESC BITFLAG(1) // This chems subtype presents the description of its main reagent/cocktail. + +// Decl-level flags (/decl/var/decl_flags) +#define DECL_FLAG_ALLOW_ABSTRACT_INIT BITFLAG(0) // Abstract subtypes without this set will CRASH() if fetched with GET_DECL(). +#define DECL_FLAG_MANDATORY_UID BITFLAG(1) // Requires uid to be non-null. \ No newline at end of file diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm index 0678ded72b8..56cade96b67 100644 --- a/code/__defines/items_clothing.dm +++ b/code/__defines/items_clothing.dm @@ -20,19 +20,20 @@ // Bitmasks for the flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses. // WARNING: The following flags apply only to the external suit! -#define HIDEGLOVES BITFLAG(0) -#define HIDESUITSTORAGE BITFLAG(1) -#define HIDEJUMPSUIT BITFLAG(2) -#define HIDESHOES BITFLAG(3) -#define HIDETAIL BITFLAG(4) +#define HIDEGLOVES BITFLAG(0) +#define HIDESUITSTORAGE BITFLAG(1) +#define HIDEJUMPSUIT BITFLAG(2) +#define HIDESHOES BITFLAG(3) +#define HIDETAIL BITFLAG(4) // WARNING: The following flags apply only to the helmets and masks! -#define HIDEMASK BITFLAG(0) -#define HIDEEARS BITFLAG(1) // Headsets and such. -#define HIDEEYES BITFLAG(2) // Glasses. -#define HIDEFACE BITFLAG(3) // Dictates whether we appear as "Unknown". -#define BLOCKHEADHAIR BITFLAG(4) // Hides the user's hair overlay. Leaves facial hair. -#define BLOCKHAIR BITFLAG(5) // Hides the user's hair, facial and otherwise. +#define HIDEMASK BITFLAG(0) +#define HIDEEARS BITFLAG(1) // Headsets and such. +#define HIDEEYES BITFLAG(2) // Glasses. +#define HIDEFACE BITFLAG(3) // Dictates whether we appear as "Unknown". +#define BLOCK_HEAD_HAIR BITFLAG(4) // Hides the user's hair overlay, and replace it with short hairs. Leaves facial hair. +#define BLOCK_FACIAL_HAIR BITFLAG(5) // Hides the user's hair, facial and otherwise. +#define BLOCK_ALL_HAIR (BLOCK_HEAD_HAIR | BLOCK_FACIAL_HAIR) // Inventory slot strings. // since numbers cannot be used as associative list keys. diff --git a/code/__defines/languages.dm b/code/__defines/languages.dm index eaa45859d34..c6ae4185206 100644 --- a/code/__defines/languages.dm +++ b/code/__defines/languages.dm @@ -1,11 +1,13 @@ // Language flags. -#define WHITELISTED 1 // Language is available if the speaker is whitelisted. -#define RESTRICTED 2 // Language can only be acquired by spawning or an admin. -#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight. -#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. -#define HIVEMIND 16 // Broadcast to all mobs with this language. -#define NONGLOBAL 32 // Do not add to general languages list. -#define INNATE 64 // All mobs can be assumed to speak and understand this language. (audible emotes) -#define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message -#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems -#define ALT_TRANSMIT 512 // Language is not based on vision or sound (Todo: add this into the say code and use it for the rootspeak languages) +#define LANG_FLAG_WHITELISTED BITFLAG(0) // Language is available if the speaker is whitelisted. +#define LANG_FLAG_RESTRICTED BITFLAG(1) // Language can only be acquired by spawning or an admin. +#define LANG_FLAG_NONVERBAL BITFLAG(2) // Language has a significant non-verbal component. Speech is garbled without line-of-sight. +#define LANG_FLAG_SIGNLANG BITFLAG(3) // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. +#define LANG_FLAG_HIVEMIND BITFLAG(4) // Broadcast to all mobs with this language. +#define LANG_FLAG_NONGLOBAL BITFLAG(5) // Do not add to general languages list. +#define LANG_FLAG_INNATE BITFLAG(6) // All mobs can be assumed to speak and understand this language. (audible emotes) +#define LANG_FLAG_NO_TALK_MSG BITFLAG(7) // Do not show the "\The [speaker] talks into \the [radio]" message +#define LANG_FLAG_NO_STUTTER BITFLAG(8) // No stuttering, slurring, or other speech problems +#define LANG_FLAG_ALT_TRANSMIT BITFLAG(9) // Language is not based on vision or sound (Todo: add this into the say code and use it for the rootspeak languages) +#define LANG_FLAG_FORBIDDEN BITFLAG(10) // Language is not to be granted to a mob under any circumstances. + diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm index 25508559ac1..b629f4a63de 100644 --- a/code/__defines/machinery.dm +++ b/code/__defines/machinery.dm @@ -27,7 +27,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called #define BROKEN BITFLAG(0) #define NOPOWER BITFLAG(1) #define MAINT BITFLAG(2) // Under maintenance. -#define EMPED BITFLAG(3) // Temporary broken by EMP pulse. +#define EMPED BITFLAG(3) // Temporary broken by EMP. #define NOSCREEN BITFLAG(4) // No UI shown via direct interaction #define NOINPUT BITFLAG(5) // No input taken from direct interaction @@ -51,7 +51,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called #define CAMERA_CHANNEL_ROBOTS "Robots" #define CAMERA_CHANNEL_MINE "Mining" -#define CAMERA_CHANNEL_SECRET "Secret" +#define CAMERA_CHANNEL_SECRET "Secret" // Non-station channels #define CAMERA_CHANNEL_CRESCENT "Crescent" @@ -150,7 +150,6 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called #define PART_FLAG_LAZY_INIT 1 // Will defer init on stock parts until machine is destroyed or parts are otherwise queried. #define PART_FLAG_QDEL 2 // Will delete on uninstall #define PART_FLAG_HAND_REMOVE 4 // Can be removed by hand -#define PART_FLAG_NODAMAGE 8 // Cannot be damaged // Machinery process flags, for use with START_PROCESSING_MACHINE #define MACHINERY_PROCESS_SELF 1 diff --git a/code/__defines/maths.dm b/code/__defines/maths.dm index c9267a72fcf..b2ea8d3eabf 100644 --- a/code/__defines/maths.dm +++ b/code/__defines/maths.dm @@ -1,7 +1,11 @@ // Macro functions. #define RAND_F(LOW, HIGH) (rand() * (HIGH - LOW) + LOW) #define CEILING(x) (-round(-(x))) + +// Float-aware floor and ceiling since round() will round upwards when given a second arg. +#define NONUNIT_FLOOR(x, y) (round( (x) / (y)) * (y)) #define NONUNIT_CEILING(x, y) (-round(-(x) / (y)) * (y)) + #define MULT_BY_RANDOM_COEF(VAR,LO,HI) VAR = round((VAR * rand(LO * 100, HI * 100))/100, 0.1) #define ROUND(x) (((x) >= 0) ? round((x)) : -round(-(x))) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 2c41ce636dc..bac4ed8b814 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -267,9 +267,10 @@ #define OUTSIDE_YES TRUE // Weather exposure values for being rained on or hailed on. -#define WEATHER_IGNORE -1 -#define WEATHER_PROTECTED 0 -#define WEATHER_EXPOSED 1 +#define WEATHER_IGNORE -1 +#define WEATHER_EXPOSED 0 +#define WEATHER_ROOFED 1 +#define WEATHER_PROTECTED 2 // Literacy check constants. #define WRITTEN_SKIP 0 @@ -278,3 +279,10 @@ // arbitrary low pressure bound for wind weather effects #define MIN_WIND_PRESSURE 10 + +#define TYPE_IS_ABSTRACT(D) (initial(D.abstract_type) == D) +#define TYPE_IS_SPAWNABLE(D) (!TYPE_IS_ABSTRACT(D) && initial(D.is_spawnable_type)) +#define INSTANCE_IS_ABSTRACT(D) (D.abstract_type == D.type) + +//Damage stuff +#define ITEM_HEALTH_NO_DAMAGE -1 diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index aa2611105ae..33289c36e45 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -151,11 +151,11 @@ #define INCAPACITATION_WEAKENED 64 #define INCAPACITATION_UNRESISTING (INCAPACITATION_KNOCKOUT|INCAPACITATION_STUNNED) -#define INCAPACITATION_DISRUPTED (INCAPACITATION_UNRESISTING|INCAPACITATION_WEAKENED) -#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING) -#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED) -#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_DISABLED) -#define INCAPACITATION_ALL (~INCAPACITATION_NONE) +#define INCAPACITATION_DISRUPTED (INCAPACITATION_UNRESISTING|INCAPACITATION_WEAKENED) +#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING) +#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED) +#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_DISABLED) +#define INCAPACITATION_ALL (~INCAPACITATION_NONE) // Organs. #define BP_MOUTH "mouth" diff --git a/code/__defines/observ.dm b/code/__defines/observ.dm new file mode 100644 index 00000000000..cada27347b2 --- /dev/null +++ b/code/__defines/observ.dm @@ -0,0 +1,4 @@ +// This also works, and removes the need for the _REPEAT variant, but the linter hates it: +// #define RAISE_EVENT(OBS, args...) (GET_DECL(OBS))?.raise_event(args); +#define RAISE_EVENT(OBS, args...) var/decl/observ/__event = GET_DECL(OBS); __event?.raise_event(args); +#define RAISE_EVENT_REPEAT(OBS, args...) __event = GET_DECL(OBS); __event?.raise_event(args); diff --git a/code/__defines/overmap.dm b/code/__defines/overmap.dm index 914c0bb6dbc..019c716fe12 100644 --- a/code/__defines/overmap.dm +++ b/code/__defines/overmap.dm @@ -17,8 +17,8 @@ #define KM_OVERMAP_RATE 100 #define SHIP_MOVE_RESOLUTION 0.001 -#define MOVING(speed, min_speed) abs(speed) >= min_speed -#define SANITIZE_SPEED(speed) SIGN(speed) * Clamp(abs(speed), 0, max_speed) +#define MOVING(speed, min_speed) (abs(speed) >= min_speed) +#define SANITIZE_SPEED(speed) (SIGN(speed) * clamp(abs(speed), 0, max_speed)) #define CHANGE_SPEED_BY(speed_var, v_diff, min_speed) \ v_diff = SANITIZE_SPEED(v_diff);\ if(!MOVING(speed_var + v_diff, min_speed)) \ diff --git a/code/__defines/paperwork.dm b/code/__defines/paperwork.dm new file mode 100644 index 00000000000..5994abe2a45 --- /dev/null +++ b/code/__defines/paperwork.dm @@ -0,0 +1,8 @@ +#define PEN_FLAG_ACTIVE BITFLAG(0) //If the pen is expanded and ready to write +#define PEN_FLAG_TOGGLEABLE BITFLAG(1) //If the pen can have its head retracted and extended +#define PEN_FLAG_FANCY BITFLAG(2) //If the pen is a fancy pen, mainly decides the font used +#define PEN_FLAG_CRAYON BITFLAG(3) //If the pen is a crayon, mainly decides the font used +#define PEN_FLAG_DEL_EMPTY BITFLAG(4) //If the pen is deleted when its use count reaches 0 + +#define TONER_USAGE_PAPER 1 //Amount of toner a paper uses +#define TONER_USAGE_PHOTO 5 //Amount of toner a photo uses \ No newline at end of file diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm index 25683bb5c8b..aaecaaaf4bf 100644 --- a/code/__defines/qdel.dm +++ b/code/__defines/qdel.dm @@ -10,24 +10,23 @@ #define QDEL_HINT_IFFAIL_FINDREFERENCE 6 //Above but only if gc fails. //defines for the gc_destroyed var -#define GC_QUEUE_PREQUEUE 1 +#define GC_QUEUE_FILTER 1 #define GC_QUEUE_CHECK 2 #define GC_QUEUE_HARDDELETE 3 #define GC_QUEUE_COUNT 3 //increase this when adding more steps. -#define GC_QUEUED_FOR_QUEUING -1 -#define GC_QUEUED_FOR_HARD_DEL -2 -#define GC_CURRENTLY_BEING_QDELETED -3 +#define GC_QUEUED_FOR_HARD_DEL -1 +#define GC_CURRENTLY_BEING_QDELETED -2 #define QDELING(X) (X.gc_destroyed) -#define QDELETED(X) (!X || QDELING(X)) -#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) +#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) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE) -#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME) +#define QDEL_IN(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, /datum/proc/qdel_self), time, TIMER_STOPPABLE)} +#define QDEL_IN_CLIENT_TIME(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, /datum/proc/qdel_self), time, TIMER_STOPPABLE | 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_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, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE) diff --git a/code/__defines/spaceman_dmm.dm b/code/__defines/spaceman_dmm.dm index 94f17433774..fd14916edc8 100644 --- a/code/__defines/spaceman_dmm.dm +++ b/code/__defines/spaceman_dmm.dm @@ -28,4 +28,4 @@ #define VAR_FINAL var #define VAR_PRIVATE var #define VAR_PROTECTED var -#endif +#endif \ No newline at end of file diff --git a/code/__defines/subsystem-priority.dm b/code/__defines/subsystem-priority.dm index 7890d77fdd2..54c87443595 100644 --- a/code/__defines/subsystem-priority.dm +++ b/code/__defines/subsystem-priority.dm @@ -20,6 +20,7 @@ #define SS_PRIORITY_SPACEDRIFT 40 // Drifting things. #define SS_PRIORITY_INPUT 20 // Input things. #define SS_PRIORITY_ICON_UPDATE 20 // Queued icon updates. Mostly used by APCs and tables. +#define SS_PRIORITY_AMBIENCE 20 // Queued ambient lighting updates. #define SS_PRIORITY_ALARM 20 // Alarm processing. #define SS_PRIORITY_EVENT 20 // Event processing and queue handling. #define SS_PRIORITY_SHUTTLE 20 // Shuttle movement. @@ -38,6 +39,7 @@ // SS_BACKGROUND #define SS_PRIORITY_OBJECTS 100 // processing_objects processing. +#define SS_PRIORITY_OVERMAP 95 // Moving objects on the overmap. #define SS_PRIORITY_PROCESSING 95 // Generic datum processor. Replaces objects processor. #define SS_PRIORITY_PLANTS 90 // Plant processing, slow ticks. #define SS_PRIORITY_VINES 50 // Spreading vine effects. @@ -52,7 +54,7 @@ #define SS_PRIORITY_COMPUTER_NETS 25 // Handles computer network devices hookups #define SS_PRIORITY_GARBAGE 20 // Garbage collection. #define SS_PRIORITY_WEATHER 10 // Weather processing. - +#define SS_PRIORITY_BLOB 0 // Blob processing. // Subsystem fire priority, from lowest to highest priority // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index c280b378933..66233d9a88d 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -20,22 +20,24 @@ // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. -#define SS_INIT_INPUT 20 -#define SS_INIT_WEBHOOKS 19 -#define SS_INIT_MODPACKS 18 -#define SS_INIT_SECRETS 17 -#define SS_INIT_GARBAGE 16 -#define SS_INIT_MATERIALS 15 -#define SS_INIT_PLANTS 14 -#define SS_INIT_LORE 13 -#define SS_INIT_MISC 12 -#define SS_INIT_SKYBOX 11 -#define SS_INIT_MAPPING 10 -#define SS_INIT_JOBS 9 -#define SS_INIT_CIRCUIT 8 -#define SS_INIT_GRAPH 7 -#define SS_INIT_OPEN_SPACE 6 -#define SS_INIT_ATOMS 5 +#define SS_INIT_INPUT 22 +#define SS_INIT_EARLY 21 +#define SS_INIT_WEBHOOKS 20 +#define SS_INIT_MODPACKS 19 +#define SS_INIT_SECRETS 18 +#define SS_INIT_GARBAGE 17 +#define SS_INIT_MATERIALS 16 +#define SS_INIT_PLANTS 15 +#define SS_INIT_LORE 14 +#define SS_INIT_MISC 13 +#define SS_INIT_SKYBOX 12 +#define SS_INIT_MAPPING 11 +#define SS_INIT_JOBS 10 +#define SS_INIT_CIRCUIT 9 +#define SS_INIT_GRAPH 8 +#define SS_INIT_OPEN_SPACE 7 +#define SS_INIT_ATOMS 6 +#define SS_INIT_PRE_CHAR_SETUP 5 #define SS_INIT_CHAR_SETUP 4 #define SS_INIT_MACHINES 3 #define SS_INIT_ICON_UPDATE 2 diff --git a/code/__defines/temperature.dm b/code/__defines/temperature.dm index 33003c92d12..822c9c20172 100644 --- a/code/__defines/temperature.dm +++ b/code/__defines/temperature.dm @@ -6,17 +6,7 @@ #define ADJUST_ATOM_TEMPERATURE(_atom, _temp) \ _atom.temperature = _temp; \ HANDLE_REACTIONS(_atom.reagents); \ - QUEUE_TEMPERATURE_ATOMS(_atom); - -#define QUEUE_TEMPERATURE_ATOMS(_atoms) \ - if(islist(_atoms)) { \ - for(var/thing in _atoms) { \ - var/atom/A = thing; \ - QUEUE_TEMPERATURE_ATOM(A); \ - } \ - } else { \ - QUEUE_TEMPERATURE_ATOM(_atoms); \ - } + queue_temperature_atoms(_atom); #define QUEUE_TEMPERATURE_ATOM(_atom) \ if(ATOM_SHOULD_TEMPERATURE_ENQUEUE(_atom)) { \ @@ -36,4 +26,14 @@ #define UNQUEUE_TEMPERATURE_ATOM(_atom) \ if(ATOM_IS_TEMPERATURE_SENSITIVE(_atom)) { \ SStemperature.processing -= _atom; \ - } \ No newline at end of file + } + + +// This is a proc primarily for profiling purposes. +/proc/queue_temperature_atoms(var/atom/atom) + if(islist(atom)) + for(var/thing in atom) + var/atom/A = thing + QUEUE_TEMPERATURE_ATOM(A) + else + QUEUE_TEMPERATURE_ATOM(atom) diff --git a/code/__defines/tools.dm b/code/__defines/tools.dm index ee7d5c59976..d0afd961cbc 100644 --- a/code/__defines/tools.dm +++ b/code/__defines/tools.dm @@ -8,6 +8,7 @@ #define TOOL_HATCHET /decl/tool_archetype/hatchet #define TOOL_WRENCH /decl/tool_archetype/wrench #define TOOL_SHOVEL /decl/tool_archetype/shovel +#define TOOL_PEN /decl/tool_archetype/pen // Surgical tools. #define TOOL_SCALPEL /decl/tool_archetype/scalpel @@ -46,6 +47,7 @@ #define IS_CROWBAR(A) IS_TOOL(A, TOOL_CROWBAR) #define IS_HATCHET(A) IS_TOOL(A, TOOL_HATCHET) #define IS_SHOVEL(A) IS_TOOL(A, TOOL_SHOVEL) +#define IS_PEN(A) IS_TOOL(A, TOOL_PEN) // Structure interaction flags #define TOOL_INTERACTION_ANCHOR BITFLAG(0) @@ -59,4 +61,14 @@ #define TOOL_CODEX_WIRECUTTERS "wirecutters (tool)" #define TOOL_CODEX_WELDER "welder (tool)" #define TOOL_CODEX_CROWBAR "crowbar (tool)" -#define TOOL_CODEX_MULTITOOL "multitool (tool)" \ No newline at end of file +#define TOOL_CODEX_MULTITOOL "multitool (tool)" + +// Tool properties for tool specific stuff +#define TOOL_PROP_COLOR_NAME "color_name" //Property containing a color name for some tools. Namely the pen tool. +#define TOOL_PROP_COLOR "color" //Property for specifying a color, for something like a pen. +#define TOOL_PROP_USES "uses_left" //Property for things that have a fixed amount of uses. -1 is unlimited. + +//Pen specific stuff +#define TOOL_PROP_PEN_FLAG "pen_flag" //Property for pens to specify additional properties about themselves +#define TOOL_PROP_PEN_SIG "signature" //Property for pens specifically. Returns a stored forged signature if there's one. +#define TOOL_PROP_PEN_SHADE_COLOR "shade_color" //Property for pens returns the shade color if applicable diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm index 94e4fd49a5a..a710b7d0e2b 100644 --- a/code/__defines/turfs.dm +++ b/code/__defines/turfs.dm @@ -19,3 +19,18 @@ #define SMOOTH_BLACKLIST 3 //Smooth with all but a blacklist of subtypes #define RANGE_TURFS(CENTER, RADIUS) block(locate(max(CENTER.x-(RADIUS), 1), max(CENTER.y-(RADIUS),1), CENTER.z), locate(min(CENTER.x+(RADIUS), world.maxx), min(CENTER.y+(RADIUS), world.maxy), CENTER.z)) + +#define EXT_LAYER_CONSTANT 0.001 +#define EXT_EDGE_OCEAN (10 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_SEAFLOOR (11 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_VOLCANIC (12 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_DIRT (20 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_BARREN (21 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_MUD (21 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_MUD_DARK (22 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_SAND (30 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_CHLORINE_SAND (31 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_WATER (40 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_GRASS (51 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_GRASS_WILD (52 * EXT_LAYER_CONSTANT) +#define EXT_EDGE_SNOW (60 * EXT_LAYER_CONSTANT) diff --git a/code/__defines/zmimic.dm b/code/__defines/zmimic.dm index fafd24afcbe..5f679f43597 100644 --- a/code/__defines/zmimic.dm +++ b/code/__defines/zmimic.dm @@ -9,6 +9,7 @@ #define ZM_ALLOW_ATMOS 8 //! If this turf permits passage of air. #define ZM_MIMIC_NO_AO 16 //! If the turf shouldn't apply regular turf AO and only do Z-mimic AO. #define ZM_NO_OCCLUDE 32 //! Don't occlude below atoms if we're a non-mimic z-turf. +#define ZM_MIMIC_BASETURF 64 //! Mimic baseturf instead of the below atom. Sometimes useful for elevators. // Convenience flag. #define ZM_MIMIC_DEFAULTS (ZM_MIMIC_BELOW|ZM_ALLOW_LIGHTING) @@ -20,7 +21,8 @@ var/global/list/mimic_defines = list( "ZM_ALLOW_LIGHTING", "ZM_ALLOW_ATMOS", "ZM_MIMIC_NO_AO", - "ZM_NO_OCCLUDE" + "ZM_NO_OCCLUDE", + "ZM_MIMIC_BASETURF" ) // Movable flags. diff --git a/code/__defines/~unit_testing.dm b/code/__defines/~unit_testing.dm deleted file mode 100644 index 7c360f55ddb..00000000000 --- a/code/__defines/~unit_testing.dm +++ /dev/null @@ -1,11 +0,0 @@ -/* - * - * This file is used by the unit testing scripts to indicate that Unit Tests are to be ran. - * Do not add anything but the UNIT_TEST definition here as it will be overwritten by the - * unit test environment when running tests. - * - * - * Should you wish to edit set UNIT_TEST to 1 like so: - * #define UNIT_TEST 1 - */ -#define UNIT_TEST 0 diff --git a/code/_helpers/animations.dm b/code/_helpers/animations.dm index ed2b0e80709..c3ba7d48996 100644 --- a/code/_helpers/animations.dm +++ b/code/_helpers/animations.dm @@ -8,6 +8,8 @@ addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_images_from_clients, I, show_to), 0.5 SECONDS) /proc/animate_speech_bubble(image/I, list/show_to, duration) + if(!I) + return var/matrix/M = matrix() M.Scale(0,0) I.transform = M diff --git a/code/_helpers/cmp.dm b/code/_helpers/cmp.dm index e2dd426cd96..dcb02bd07f7 100644 --- a/code/_helpers/cmp.dm +++ b/code/_helpers/cmp.dm @@ -64,6 +64,11 @@ if (!.) . = B.qdels - A.qdels +/proc/cmp_unit_test_priority(datum/unit_test/A, datum/unit_test/B) + . = A.priority - B.priority + if (!.) + . = sorttext(B, A) + /proc/cmp_timer(datum/timedevent/a, datum/timedevent/b) return a.timeToRun - b.timeToRun @@ -111,3 +116,11 @@ /proc/cmp_job_desc(var/datum/job/A, var/datum/job/B) return B.get_occupations_tab_sort_score() - A.get_occupations_tab_sort_score() + +/proc/cmp_lobby_option_asc(var/datum/lobby_option/A, var/datum/lobby_option/B) + return A.sort_priority - B.sort_priority + +/proc/cmp_files_sort(datum/computer_file/a, datum/computer_file/b) + . = istype(b, /datum/computer_file/directory) - istype(a, /datum/computer_file/directory) // Prioritize directories over other files. + if(!.) + return sorttext(b.filename, a.filename) diff --git a/code/_helpers/emissive.dm b/code/_helpers/emissive.dm index bc7534cad05..18ef96c37f8 100644 --- a/code/_helpers/emissive.dm +++ b/code/_helpers/emissive.dm @@ -1,9 +1,11 @@ -/proc/emissive_overlay(var/icon, var/icon_state, var/loc, var/dir) +/proc/emissive_overlay(var/icon, var/icon_state, var/loc, var/dir, var/color) var/image/emissive/I = new(icon, icon_state) if(!isnull(loc)) I.loc = loc if(!isnull(dir)) I.dir = dir + if(!isnull(color)) + I.color = color return I /image/emissive/New() diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm index 00a270fac83..b665a162e7b 100644 --- a/code/_helpers/files.dm +++ b/code/_helpers/files.dm @@ -25,7 +25,7 @@ var/extension = copytext(path,-4,0) if( !fexists(path) || !(extension in valid_extensions) ) - to_chat(src, "Error: browse_files(): File not found/Invalid file([path]).") + to_chat(src, SPAN_WARNING("Error: browse_files(): File not found/Invalid file([path]).")) return return path @@ -39,7 +39,7 @@ /client/proc/file_spam_check() var/time_to_wait = fileaccess_timer - world.time if(time_to_wait > 0) - to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.") + to_chat(src, SPAN_WARNING("Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.")) return 1 fileaccess_timer = world.time + FTPDELAY return 0 diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index 2108b333cd2..c704ab64ca6 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -16,11 +16,6 @@ return TRUE return FALSE -/proc/get_area(O) - RETURN_TYPE(/area) - var/turf/loc = get_turf(O) - return loc?.loc - /proc/get_area_name(O) //get area's proper name var/area/A = get_area(O) return A?.proper_name diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 20d9f28cb7a..372c9fca931 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -19,7 +19,6 @@ var/global/datum/visualnet/camera/cameranet = new() // Runes var/global/list/rune_list = new() -var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) // Strings which corraspond to bodypart covering flags, useful for outputting what something covers. var/global/list/string_part_flags = list( diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index 8f2ee604df1..0826de1981c 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -611,7 +611,7 @@ world return hsv(HSV[1], HSV[2], HSV[3], (HSV.len > 3 ? HSV[4] : null)) // Convert an rgb color to grayscale -/proc/GrayScale(rgb) +/proc/GrayScale(rgb) //#FIXME: This isn't true grayscale. Its from an example on the Byond ref on how to manipulate colors... var/list/RGB = ReadRGB(rgb) var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11 return (RGB.len > 3) ? rgb(gray, gray, gray, RGB[4]) : rgb(gray, gray, gray) @@ -706,7 +706,7 @@ The _flatIcons list is a cache for generated icon files. var/flatX2= flat.Width() var/flatY1= 1 var/flatY2= flat.Height() - + // Dimensions of overlay being added var/addX1 var/addX2 @@ -785,7 +785,7 @@ The _flatIcons list is a cache for generated icon files. flat.MapColors(arglist(A.color)) // Probably a valid color, could check length_char(A.color) == 7 if color normalization becomes etc etc etc. - else if(istext(A.color)) + else if(istext(A.color)) flat.Blend(A.color, ICON_MULTIPLY) // Colour matrices track/apply alpha changes in MapColors() above, so only apply if color isn't a matrix. @@ -849,9 +849,9 @@ The _flatIcons list is a cache for generated icon files. if (!value) return color var/list/RGB = ReadRGB(color) - RGB[1] = Clamp(RGB[1]+value,0,255) - RGB[2] = Clamp(RGB[2]+value,0,255) - RGB[3] = Clamp(RGB[3]+value,0,255) + RGB[1] = clamp(RGB[1]+value,0,255) + RGB[2] = clamp(RGB[2]+value,0,255) + RGB[3] = clamp(RGB[3]+value,0,255) return rgb(RGB[1],RGB[2],RGB[3]) /proc/sort_atoms_by_layer(var/list/atoms) @@ -908,7 +908,7 @@ The _flatIcons list is a cache for generated icon files. if(istype(A, /atom/movable/lighting_overlay) && show_lighting) render_atoms.Add(A) continue - + if(!A.alpha || A.invisibility) continue @@ -922,7 +922,7 @@ The _flatIcons list is a cache for generated icon files. capture.Blend(COLOR_BLACK, ICON_OVERLAY) for(var/atom/A as anything in render_atoms) var/icon/atom_icon = getFlatIcon(A) - + if(ismob(A)) var/mob/M = A if(M.lying) diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index a8bea9fa45d..62a80a4ea44 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -750,6 +750,26 @@ proc/dd_sortedObjectList(list/incoming) if(islist(.[i])) .[i] = .(.[i]) +/** + * Deep copy/clone everything in the list, or reference things that cannot be cloned. Use with caution. + * atom_refs_only: If true, the proc will only reference /atom subtypes, and will not clone them. + */ +/proc/listDeepClone(var/list/L, var/atom_refs_only = FALSE) + if(atom_refs_only && isatom(L)) + return L + if(istype(L, /datum)) + var/datum/D = L + return D.CanClone()? D.Clone() : D //If the datum can be cloned, clone it, or just reference it otherwise + //Anything else that's not a list just return the ref + if(!islist(L)) + return L + + . = L.Copy() + for(var/i = 1 to length(L)) + var/I = .[i] + if(islist(I) || istype(I, /datum)) + .[i] = listDeepClone(I) + #define IS_VALID_INDEX(list, index) (list.len && index > 0 && index <= list.len) // Returns the first key where T fulfills ispath @@ -775,7 +795,11 @@ var/global/list/json_cache = list() if(islist(decoded)) // To prevent cache mutation. return deepCopyList(decoded) else if(decoded) - return decoded + return decoded catch(var/exception/e) log_error("Exception during JSON decoding ([json_to_decode]): [e]") return list() + +/// Is this a dense (all keys have non-null values) associative list with at least one entry? +/proc/is_dense_assoc(var/list/L) + return length(L) > 0 && !isnull(L[L[1]]) \ No newline at end of file diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index 58784c3d05f..94a4bc41388 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -180,7 +180,7 @@ var/global/log_end= world.system_type == UNIX ? ascii2text(13) : "" if(include_link && is_special_character(M) && highlight_special_characters) - . += "/([name])" //Orange + . += "/([SPAN_ORANGE(name)])" else . += "/([name])" diff --git a/code/_helpers/matrices.dm b/code/_helpers/matrices.dm index 0d2071e858d..c211ec41a1c 100644 --- a/code/_helpers/matrices.dm +++ b/code/_helpers/matrices.dm @@ -47,7 +47,7 @@ /proc/color_rotation(angle) if(angle == 0) return color_identity() - angle = Clamp(angle, -180, 180) + angle = clamp(angle, -180, 180) var/cos = cos(angle) var/sin = sin(angle) @@ -62,7 +62,7 @@ //Makes everything brighter or darker without regard to existing color or brightness /proc/color_brightness(power) - power = Clamp(power, -255, 255) + power = clamp(power, -255, 255) power = power/255 return list(1,0,0, 0,1,0, 0,0,1, power,power,power) @@ -82,7 +82,7 @@ var/global/list/delta_index = list( //Exxagerates or removes brightness /proc/color_contrast(value) - value = Clamp(value, -100, 100) + value = clamp(value, -100, 100) if(value == 0) return color_identity() @@ -105,7 +105,7 @@ var/global/list/delta_index = list( /proc/color_saturation(value as num) if(value == 0) return color_identity() - value = Clamp(value, -100, 100) + value = clamp(value, -100, 100) if(value > 0) value *= 3 var/x = 1 + value / 100 diff --git a/code/_helpers/medical_scans.dm b/code/_helpers/medical_scans.dm index 1f6d1c4ac30..c2ee562d36b 100644 --- a/code/_helpers/medical_scans.dm +++ b/code/_helpers/medical_scans.dm @@ -78,7 +78,7 @@ O["name"] = I.name O["is_broken"] = I.is_broken() O["is_bruised"] = I.is_bruised() - O["is_damaged"] = I.is_damaged() + O["is_damaged"] = I.damage > 0 O["scan_results"] = I.get_scan_results(tag) O["ailments"] = I.has_diagnosable_ailments(scanner = TRUE) scan["internal_organs"] += list(O) @@ -195,7 +195,7 @@ if(skill_level >= SKILL_ADEPT) if(ratio <= 0.70) dat += "Patient is in Hypovolemic Shock. Transfusion highly recommended." - else + else dat += "Blood pressure:ERROR - Patient has lacks a circulatory system." dat += "Blood volume:ERROR - Patient has lacks a circulatory system." @@ -266,7 +266,6 @@ break var/row = list() row += "[E["name"]]" - row += "" var/rowdata = list() if(E["brute_dam"] + E["burn_dam"] == 0) rowdata += "None" @@ -280,7 +279,7 @@ rowdata += "[capitalize(get_wound_severity(E["brute_ratio"], (E["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] physical trauma" if(E["burn_dam"]) rowdata += "[capitalize(get_wound_severity(E["burn_ratio"], (E["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] burns" - row += "[jointext(rowdata, "
")]" + row += "[jointext(rowdata, "
")]" if(skill_level >= SKILL_ADEPT) var/list/status = list() diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm index 237860c07a8..ddf6c2243ad 100644 --- a/code/_helpers/mobs.dm +++ b/code/_helpers/mobs.dm @@ -123,7 +123,7 @@ if (progbar) qdel(progbar) -/proc/do_after(mob/user, delay, atom/target = null, check_holding = 1, progress = 1, incapacitation_flags = INCAPACITATION_DEFAULT, same_direction = 0, can_move = 0) +/proc/do_after(mob/user, delay, atom/target = null, check_holding = 1, progress = 1, incapacitation_flags = INCAPACITATION_DEFAULT, same_direction = 0, can_move = 0, max_distance, check_in_view = 0) if(!user) return 0 var/atom/target_loc = null @@ -159,7 +159,11 @@ drifting = 0 original_loc = user.loc - if(QDELETED(user) || user.incapacitated(incapacitation_flags) || (!drifting && user.loc != original_loc && !can_move) || (same_direction && user.dir != original_dir)) + if(QDELETED(user) || user.incapacitated(incapacitation_flags) || (!drifting && user.loc != original_loc && !can_move) || (same_direction && user.dir != original_dir) || (!isnull(max_distance) && get_dist(user, target) > max_distance)) + . = 0 + break + + if(check_in_view && !(target in view(max_distance, user))) . = 0 break diff --git a/code/_helpers/overmap.dm b/code/_helpers/overmap.dm index 049a44e209e..67258663860 100644 --- a/code/_helpers/overmap.dm +++ b/code/_helpers/overmap.dm @@ -3,7 +3,8 @@ var/global/list/overmaps_by_name = list() var/global/list/overmaps_by_z = list() /proc/get_empty_zlevel(var/base_turf_type) - . = INCREMENT_WORLD_Z_SIZE + INCREMENT_WORLD_Z_SIZE if(base_turf_type && base_turf_type != world.turf) for(var/turf/T as anything in block(locate(1, 1, .),locate(world.maxx, world.maxy, .))) T.ChangeTurf(base_turf_type) + return world.maxz diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 5df9464f702..43aec53f30c 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -33,7 +33,7 @@ if(input_length > max_length) to_chat(usr, SPAN_WARNING("Your message is too long by [input_length - max_length] character\s.")) return - input = copytext_char(input, 1, max_length) + input = copytext_char(input, 1, max_length + 1) if(extra) input = replace_characters(input, list("\n"=" ","\t"=" ")) @@ -198,6 +198,49 @@ if(32) //space dat += "_" return jointext(dat, null) + +//Used to strip text of everything but letters and numbers, and select special symbols. +//Requires that the filename has an alphanumeric character. +/proc/sanitize_for_file(text) + if(!text) return "" + var/list/dat = list() + var/has_alphanumeric = FALSE + var/last_was_fullstop = FALSE + for(var/i=1, i<=length(text), i++) + var/ascii_char = text2ascii(text,i) + switch(ascii_char) + if(65 to 90) //A-Z + dat += ascii2text(ascii_char) + has_alphanumeric = TRUE + last_was_fullstop = FALSE + if(97 to 122) //a-z + dat += ascii2text(ascii_char) + has_alphanumeric = TRUE + last_was_fullstop = FALSE + if(48 to 57) //0-9 + dat += ascii2text(ascii_char) + has_alphanumeric = TRUE + last_was_fullstop = FALSE + if(32) //space + dat += ascii2text(ascii_char) + last_was_fullstop = FALSE + if(33, 36, 40, 41, 42, 45, 95) //!, $, (, ), *, -, _ + dat += ascii2text(ascii_char) + last_was_fullstop = FALSE + if(46) //. + if(last_was_fullstop) // No repeats of . to avoid confusion with .. + continue + dat += ascii2text(ascii_char) + last_was_fullstop = TRUE + + if(!has_alphanumeric) + return "" + + if(dat[length(dat)] == ".") //kill trailing . + dat.Cut(length(dat)) + return jointext(dat, null) + + // UNICODE: Convert to regex? //Returns null if there is any bad text in the string @@ -640,8 +683,17 @@ var/global/list/fullstop_alternatives = list(".", "!", "?") #define APPEND_FULLSTOP_IF_NEEDED(TXT) ((copytext_char(TXT, -1, 0) in global.fullstop_alternatives) ? TXT : "[TXT].") /proc/make_rainbow(var/msg) + var/static/list/rainbow_classes = list( + "font_red", + "font_orange", + "font_yellow", + "font_green", + "font_blue", + "font_violet", + "font_purple" + ) for(var/i = 1 to length(msg)) - . += "[copytext(msg, i, i+1)]" + . += "[copytext(msg, i, i+1)]" // Returns direction-string, rounded to multiples of 22.5, from the first parameter to the second // N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW @@ -680,3 +732,109 @@ var/global/list/fullstop_alternatives = list(".", "!", "?") return "Northwest" if(337) return "North-Northwest" + +///Returns true if the text starts with the given sequence of characters. +/proc/text_starts_with(var/text, var/start) + return copytext(text, 1, length(start) + 1) == start + +///Returns true if the text ends with the given sequence of characters. +/proc/text_ends_with(var/text, var/end) + var/tlen = length(text) + return copytext(text, ((tlen - length(end)) + 1), tlen + 1) == end + +///Returns true if the text ends with ANY of the given sequences of characters. +/proc/text_ends_with_any_of(var/text, var/list/endings) + for(var/ending in endings) + if(text_ends_with(text, ending)) + return ending + return + +///Siblants that should end with es +var/global/list/plural_siblants = list("ss", "x", "sh", "ch") +///Vocalized y sounds that needs to end in -ies when made plural +var/global/list/plural_vocalized_y = list("quy", "by", "dy", "fy", "gy", "hy", "jy", "ky", "ly", "my", "ny", "py", "ry", "sy", "ty", "vy", "xy", "zy") +///Plurals endings in -ves +var/global/list/plural_endings_in_ves = list("fe", "af") +///Plurals endings in -sses or -zzes +var/global/list/plural_endings_with_doubled_letter = list("as", "ez") +///Words that have a different plural form, and their plural form +var/global/list/apophonic_plurals = list( + "foot" = "feet", + "goose" = "geese", + "louse" = "lice", + "man" = "men", + "woman" = "women", + "mouse" = "mice", + "tooth" = "teeth", + "ox" = "oxen", + //#TODO: Add more of those +) +///Used to tell how to make it a plural word and etc. +var/global/list/english_loanwords = list( + "fungus", + "cactus", + //#TODO: Add more of those +) +///Words that stay the same in plural +var/global/list/plural_words_unchanged = list( + "series", + "means", + "species" + //#TODO: Add more of those +) + +///Properly changes the given word (or the last word of the string) into a plural word. Applies a bunch of exceptions from the english language. +/proc/text_make_plural(var/word) + if(!length(word)) + return + var/initial_word = word + //If someone passed us several words, just keep the last one. + var/list/splited = splittext_char(word, " ", 1, length(word)+1, FALSE) + log_debug("splitted '[initial_word]' to [log_info_line(splited)].") + if(length(splited) > 1) + word = splited[splited.len] + else + splited = null + + //Words that don't change when pluralized + if(global.plural_words_unchanged[word]) + return initial_word + + //Apophonic plurals + if(global.apophonic_plurals[word]) + word = global.apophonic_plurals[word] + + //Siblants + plurals of nouns in -o preceded by a consonant. Loanwords ending in o just ends with an s + else if(text_ends_with_any_of(word, global.plural_siblants) || (text_ends_with(word, "o") && !(word in global.english_loanwords))) + word = "[word]es" + + //Plurals of nouns in -y + else if(text_ends_with_any_of(word, global.plural_vocalized_y)) + word = "[copytext(word, 1, length(word))]ies" + + // -f and -fe endings + else if(text_ends_with_any_of(word, global.plural_endings_in_ves)) + word = "[copytext(word, 1, length(word) - 1)]ves" //EX: calf -> calves, leaf -> leaves, knife -> knives + + //some ā€˜-s’ and ā€˜-z’ endings + else if(text_ends_with_any_of(word, global.plural_endings_with_doubled_letter)) + word = "[word][copytext(word, length(word), length(word) + 1)]es" //Ex: gas -> gas'ses', fez -> fez'zes' + + //Plurals of nouns in -us + else if(text_ends_with(word, "us")) + if(!(word in global.english_loanwords)) + word = "[word]es" + else + word = "[copytext(word, 1, length(word) - 1)]i" //EX: Cactus -> Cacti, Fungus -> Fungi + + //Finally just go with the basic rules + else + if(text_ends_with(word, "s")) + word = "[word]es" + else + word = "[word]s" + + //Put the sentence back together, if applicable + if(splited) + word = "[jointext(splited, " ", 1, length(splited))] [word]" + return word diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index 2d69d3f43b6..ba248a2a0da 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -8,7 +8,7 @@ else if (isnull(minutes)) PRINT_STACK_TRACE("Null minutes value supplied to minutes_to_readable().") return "BAD INPUT" - + var/hours = 0 var/days = 0 var/weeks = 0 @@ -104,6 +104,21 @@ var/global/round_start_time = 0 round_start_time = world.time return 1 +/proc/ticks2readable(tick_time) + var/hours = round(tick_time / (1 HOUR)) + var/minutes = round((tick_time % (1 HOUR)) / (1 MINUTE)) + var/seconds = round((tick_time % (1 MINUTE)) / (1 SECOND)) + var/out = list() + if(hours > 0) + out += "[hours] hour\s" + if(minutes > 0) + out += "[minutes] minute\s" + if(seconds > 0) + out += "[seconds] second\s" + if(length(out)) + return english_list(out) + return null + /proc/roundduration2text() if(!round_start_time) return "00:00" @@ -134,7 +149,7 @@ var/global/rollovercheck_last_timeofday = 0 global.rollovercheck_last_timeofday = world.timeofday return global.midnight_rollovers -/// Increases delay as the server gets more overloaded +/// Increases delay as the server gets more overloaded /// as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful #define DELTA_CALC max(((max(TICK_USAGE, world.cpu) / 100) * max(Master.sleep_delta-1,1)), 1) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 8f38ebb0a3e..d0b3fb80089 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -7,10 +7,6 @@ //Checks if all high bits in req_mask are set in bitfield #define BIT_TEST_ALL(bitfield, req_mask) ((~(bitfield) & (req_mask)) == 0) -//Returns the middle-most value -/proc/dd_range(var/low, var/high, var/num) - return max(low,min(high,num)) - /proc/get_projectile_angle(atom/source, atom/target) var/sx = source.x * world.icon_size var/sy = source.y * world.icon_size @@ -207,7 +203,7 @@ Turf and target are seperate in case you want to teleport some distance from a t line+=locate(px,py,M.z) return line -#define LOCATE_COORDS(X, Y, Z) locate(between(1, X, world.maxx), between(1, Y, world.maxy), Z) +#define LOCATE_COORDS(X, Y, Z) locate(clamp(1, X, world.maxx), clamp(1, Y, world.maxy), Z) /proc/getcircle(turf/center, var/radius) //Uses a fast Bresenham rasterization algorithm to return the turfs in a thin circle. if(!radius) return list(center) @@ -234,7 +230,7 @@ Turf and target are seperate in case you want to teleport some distance from a t #undef LOCATE_COORDS -#define LOCATE_COORDS_SAFE(X, Y, Z) locate(between(TRANSITIONEDGE + 1, X, world.maxx - TRANSITIONEDGE), between(TRANSITIONEDGE + 1, Y, world.maxy - TRANSITIONEDGE), Z) +#define LOCATE_COORDS_SAFE(X, Y, Z) locate(clamp(TRANSITIONEDGE + 1, X, world.maxx - TRANSITIONEDGE), clamp(TRANSITIONEDGE + 1, Y, world.maxy - TRANSITIONEDGE), Z) /proc/getcirclesafe(turf/center, var/radius) //Uses a fast Bresenham rasterization algorithm to return the turfs in a thin circle. if(!radius) return list(center) @@ -449,10 +445,6 @@ Turf and target are seperate in case you want to teleport some distance from a t var/y = min(world.maxy, max(1, A.y + dy)) return locate(x,y,A.z) -//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. Lower bound takes priority. -/proc/between(var/low, var/middle, var/high) - return max(min(middle, high), low) - //Will return the contents of an atom recursivly to a depth of 'searchDepth' /atom/proc/GetAllContents(searchDepth = 5) var/list/toReturn = list() @@ -544,7 +536,6 @@ Turf and target are seperate in case you want to teleport some distance from a t /datum/coords //Simple datum for storing coordinates. var/x_pos = null var/y_pos = null - var/z_pos = null /area/proc/copy_contents_to(var/area/A , var/platingRequired = 0 ) //Takes: Area. Optional: If it should copy to areas that don't have plating @@ -744,7 +735,7 @@ var/global/list/WALLITEMS = list( /obj/machinery/status_display, /obj/machinery/network/requests_console, /obj/machinery/light_switch, /obj/structure/sign, /obj/machinery/newscaster, /obj/machinery/firealarm, /obj/structure/noticeboard, /obj/item/storage/secure/safe, /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth, - /obj/item/storage/mirror, /obj/structure/fireaxecabinet, /obj/structure/filingcabinet/wallcabinet + /obj/structure/mirror, /obj/structure/fireaxecabinet, /obj/structure/filing_cabinet/wall ) /proc/gotwallitem(loc, dir) for(var/obj/O in loc) @@ -793,3 +784,15 @@ var/global/list/WALLITEMS = list( // call to generate a stack trace and print to runtime logs /proc/get_stack_trace(msg, file, line) CRASH("%% [file],[line] %% [msg]") + +/**Returns a number string with its ordinal suffix th, st, nd, rd */ +/proc/get_ordinal_string(var/num) + if(num < 10 && num > 20) //11, 12, 13 are exceptions in english, and just get 'th' like everything else + switch(num % 10) + if(1) + return "[num]st" + if(2) + return "[num]nd" + if(3) + return "[num]rd" + return "[num]th" diff --git a/code/_helpers/view.dm b/code/_helpers/view.dm index 13ee837caa7..1855aa758c2 100644 --- a/code/_helpers/view.dm +++ b/code/_helpers/view.dm @@ -1,12 +1,7 @@ /proc/getviewsize(view) - var/viewX - var/viewY if(isnum(view)) - var/totalviewrange = 1 + 2 * view - viewX = totalviewrange - viewY = totalviewrange + var/totalviewrange = (view < 0 ? -1 : 1) + 2 * view + return list(totalviewrange, totalviewrange) else var/list/viewrangelist = splittext(view,"x") - viewX = text2num(viewrangelist[1]) - viewY = text2num(viewrangelist[2]) - return list(viewX, viewY) + return list(text2num(viewrangelist[1]), text2num(viewrangelist[2])) diff --git a/code/_helpers/vis_contents.dm b/code/_helpers/vis_contents.dm index cb3431e2917..5d4656426f7 100644 --- a/code/_helpers/vis_contents.dm +++ b/code/_helpers/vis_contents.dm @@ -11,6 +11,3 @@ set_vis_contents(src, new_vis_contents) else if(length(vis_contents)) clear_vis_contents(src) - -/turf/proc/get_vis_contents_to_add() - return diff --git a/code/_helpers/visual_filters.dm b/code/_helpers/visual_filters.dm index e76a194fd0a..cbe1eac711c 100644 --- a/code/_helpers/visual_filters.dm +++ b/code/_helpers/visual_filters.dm @@ -8,11 +8,14 @@ /proc/cmp_filter_data_priority(list/A, list/B) return A["priority"] - B["priority"] +// Defining this for future proofing and ease of searching for erroneous usage. +/image/proc/add_filter(filter_name, priority, list/params) + filters += filter(arglist(params)) + /atom/movable/proc/add_filter(filter_name, priority, list/params) - LAZYINITLIST(filter_data) var/list/p = params.Copy() p["priority"] = priority - filter_data[filter_name] = p + LAZYSET(filter_data, filter_name, p) update_filters() /atom/movable/proc/update_filters() @@ -26,8 +29,9 @@ UPDATE_OO_IF_PRESENT /atom/movable/proc/get_filter(filter_name) - if(filter_data && filter_data[filter_name]) - return filters[filter_data.Find(filter_name)] + var/filter_index = filter_data?.Find(filter_name) + if(filter_index > 0 && filter_index <= length(filters)) + return filters[filter_index] // Polaris Extensions /atom/movable/proc/remove_filter(filter_name) diff --git a/code/_macros.dm b/code/_macros.dm index 4520907f8a7..fcd6e78a2b7 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -2,11 +2,12 @@ #define PUBLIC_GAME_MODE SSticker.master_mode -#define Clamp(value, low, high) (value <= low ? low : (value >= high ? high : value)) -#define CLAMP01(x) (Clamp(x, 0, 1)) +#define CLAMP01(x) (clamp(x, 0, 1)) #define get_turf(A) get_step(A,0) +#define get_area(A) (get_step(A, 0)?.loc) + #define get_x(A) (get_step(A, 0)?.x || 0) #define get_y(A) (get_step(A, 0)?.y || 0) @@ -143,25 +144,35 @@ #define JOINTEXT(X) jointext(X, null) -#define SPAN_ITALIC(X) "[X]" - -#define SPAN_BOLD(X) "[X]" - -#define SPAN_NOTICE(X) "[X]" - -#define SPAN_WARNING(X) "[X]" - -#define SPAN_STYLE(style, X) "[X]" - -#define SPAN_DANGER(X) "[X]" - -#define SPAN_OCCULT(X) "[X]" - -#define SPAN_MFAUNA(X) "[X]" - -#define SPAN_SUBTLE(X) "[X]" - -#define SPAN_INFO(X) "[X]" +#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_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) + +// 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 STYLE_SMALLFONTS(X, S, C1) "[X]" diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 932fb5c1abe..e7dfe6206f5 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -177,5 +177,4 @@ return TRUE /atom/proc/attack_robot(mob/user) - attack_ai(user) - return + return attack_ai(user) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 39be692eb6c..d01a671bebd 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -12,12 +12,19 @@ /atom/proc/handle_mouse_drop(var/atom/over, var/mob/user) . = over.receive_mouse_drop(src, user) +// Can the user drop something onto this atom? +/atom/proc/user_can_mousedrop_onto(var/mob/user, var/atom/being_dropped, var/incapacitation_flags) + return !user.incapacitated(incapacitation_flags) && check_mousedrop_interactivity(user) && user.check_dexterity(DEXTERITY_GRIP) + +/atom/proc/check_mousedrop_interactivity(var/mob/user) + return CanPhysicallyInteract(user) + // This proc checks if an atom can be mousedropped onto the target by the user. /atom/proc/can_mouse_drop(var/atom/over, var/mob/user = usr, var/incapacitation_flags = INCAPACITATION_DEFAULT) SHOULD_CALL_PARENT(TRUE) if(!istype(user) || !istype(over) ||QDELETED(user) || QDELETED(over) || QDELETED(src)) return FALSE - if(user.incapacitated(incapacitation_flags) || !CanPhysicallyInteract(user) || !user.check_dexterity(DEXTERITY_GRIP)) + if(!over.user_can_mousedrop_onto(user, src, incapacitation_flags)) return FALSE if(!check_mousedrop_adjacency(over, user)) return FALSE diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index f28a472232d..2a7ced79c8b 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -14,6 +14,7 @@ */ #define ui_entire_screen "WEST,SOUTH to EAST,NORTH" +#define ui_center_fullscreen "CENTER-7,CENTER-7" //Lower left, persistant menu #define ui_inventory "LEFT:6,BOTTOM:5" @@ -54,7 +55,7 @@ #define ui_pull_resist "RIGHT-2:26,BOTTOM+1:7" #define ui_acti "RIGHT-2:26,BOTTOM:5" #define ui_movi "RIGHT-3:24,BOTTOM:5" -#define ui_attack_selector "RIGHT-3:24,BOTTOM+1:-2" +#define ui_attack_selector "RIGHT-3:24,BOTTOM+1:6" #define ui_zonesel "RIGHT-1:28,BOTTOM:5" #define ui_acti_alt "RIGHT-1:28,BOTTOM:5" //alternative intent switcher for when the interface is hidden #define ui_stamina "RIGHT-3:24,BOTTOM+1:5" diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm index 6d30353ae04..895f2fae9ac 100644 --- a/code/_onclick/hud/action.dm +++ b/code/_onclick/hud/action.dm @@ -18,7 +18,6 @@ var/procname = null var/atom/movable/target = null var/check_flags = 0 - var/processing = 0 var/active = 0 var/obj/screen/action_button/button = null var/button_icon = 'icons/obj/action_buttons/actions.dmi' diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index 232eb4728e4..4da06f9b575 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -23,14 +23,8 @@ screens[category] = screen screen.transform = null - if(screen && client) - if(screen.screen_loc != ui_entire_screen) - if(max(client.last_view_x_dim, client.last_view_y_dim) > 7) - var/matrix/M = matrix() - M.Scale(CEILING(client.last_view_x_dim/7),CEILING(client.last_view_y_dim/7)) - screen.transform = M - if(stat != DEAD || screen.allstate) - client.screen += screen + if(screen && client && (stat != DEAD || screen.allstate)) + client.screen += screen return screen /mob/proc/show_screen(var/screen, var/animated) @@ -79,7 +73,7 @@ /obj/screen/fullscreen icon = 'icons/mob/screen_full.dmi' icon_state = "default" - screen_loc = "CENTER-7,CENTER-7" + screen_loc = ui_center_fullscreen plane = FULLSCREEN_PLANE mouse_opacity = 0 var/severity = 0 diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index bf00ec77cd3..bce2e800065 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -19,6 +19,9 @@ /obj/screen/receive_mouse_drop(atom/dropping, mob/user) return TRUE +/obj/screen/check_mousedrop_interactivity(var/mob/user) + return user.client && (src in user.client.screen) + /obj/screen/Destroy() master = null return ..() @@ -50,7 +53,6 @@ name = "default attack selector" icon_state = "attack_selector" screen_loc = ui_attack_selector - maptext_y = 12 var/mob/living/carbon/human/owner /obj/screen/default_attack_selector/Click(location, control, params) @@ -68,7 +70,7 @@ return - owner.set_default_unarmed_attack() + owner.set_default_unarmed_attack(src) return TRUE /obj/screen/default_attack_selector/Destroy() @@ -346,8 +348,9 @@ usr.swap_hand() if("hand") usr.swap_hand() - else if(usr.attack_ui(slot_id)) - usr.update_inv_hands(0) + else + if(usr.attack_ui(slot_id)) + usr.update_inv_hands(0) return 1 // Character setup stuff diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 80240d7a94b..ddd9ee5d309 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -91,9 +91,21 @@ avoid code duplication. This includes items that may sometimes act as a standard //I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files. /obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone, animate = TRUE) if(item_flags & ITEM_FLAG_NO_BLUDGEON) - return 0 - if(M == user && user.a_intent != I_HURT) - return 0 + return FALSE + + // If on help, possibly don't attack. + if(user.a_intent == I_HELP) + switch(user.get_preference_value(/datum/client_preference/help_intent_attack_blocking)) + if(PREF_ALWAYS) + if(user == M) + to_chat(user, SPAN_WARNING("You refrain from hitting yourself with \the [src] as you are on help intent.")) + else + to_chat(user, SPAN_WARNING("You refrain from hitting \the [M] with \the [src] as you are on help intent.")) + return FALSE + if(PREF_MYSELF) + if(user == M) + to_chat(user, SPAN_WARNING("You refrain from hitting yourself with \the [src] as you are on help intent.")) + return FALSE ///////////////////////// diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 913f54f0a45..51a5217e7b6 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -36,7 +36,6 @@ var/global/list/gamemode_cache = list() var/vote_no_dead = 0 // dead people can't vote (tbi) var/vote_no_dead_crew_transfer = 0 // dead people can't vote on crew transfer votes // var/enable_authentication = 0 // goon authentication - var/del_new_on_log = 1 // del's new players if they log before they spawn in var/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard var/traitor_scaling = 0 //if amount of traitors scales based on amount of players var/objectives_disabled = 0 //if objectives are disabled or not @@ -154,8 +153,6 @@ var/global/list/gamemode_cache = list() var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database - var/simultaneous_pm_warning_timeout = 100 - var/use_iterative_explosions //Defines whether the server uses iterative or circular explosions. var/iterative_explosives_z_threshold = 10 var/iterative_explosives_z_multiplier = 0.75 @@ -265,6 +262,8 @@ var/global/list/gamemode_cache = list() var/expanded_alt_interactions = FALSE // Set to true to enable look, grab, drop, etc. in the alt interaction menu. + var/show_typing_indicator_for_whispers = FALSE // Do whispers show typing indicators overhead? + /datum/configuration/VV_hidden() . = ..() | protected_vars @@ -820,6 +819,9 @@ var/global/list/gamemode_cache = list() if("no_throttle_localhost") config.no_throttle_localhost = TRUE + if("show_typing_indicator_for_whispers") + config.show_typing_indicator_for_whispers = TRUE + else log_misc("Unknown setting in configuration: '[name]'") diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm index 6f987688d18..c1f62978980 100644 --- a/code/controllers/subsystems/air.dm +++ b/code/controllers/subsystems/air.dm @@ -198,8 +198,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun T.post_update_air_properties() T.needs_air_update = 0 #ifdef ZASDBG - T.cut_overlay(mark, TRUE) - updated++ + remove_vis_contents(T, zasdbgovl_mark) #endif if (no_mc_tick) @@ -215,8 +214,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun T.post_update_air_properties() T.needs_air_update = 0 #ifdef ZASDBG - T.cut_overlay(mark, TRUE) - updated++ + remove_vis_contents(T, zasdbgovl_mark) #endif if (no_mc_tick) @@ -364,7 +362,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun return tiles_to_update += T #ifdef ZASDBG - T.add_overlay(mark, TRUE) + add_vis_contents(T, zasdbgovl_mark) #endif T.needs_air_update = 1 diff --git a/code/controllers/subsystems/ambience.dm b/code/controllers/subsystems/ambience.dm new file mode 100644 index 00000000000..1f615731f18 --- /dev/null +++ b/code/controllers/subsystems/ambience.dm @@ -0,0 +1,56 @@ +SUBSYSTEM_DEF(ambience) + name = "Ambient Lighting" + wait = 1 + priority = SS_PRIORITY_LIGHTING + init_order = SS_INIT_LIGHTING + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT // Copied from icon update subsystem. + flags = SS_NO_INIT + var/list/queued = list() + +/datum/controller/subsystem/ambience/stat_entry() + ..("P:[length(queued)]") + +/datum/controller/subsystem/ambience/fire(resumed = FALSE, no_mc_tick = FALSE) + var/list/curr = queued + while (curr.len) + var/turf/target = curr[curr.len] + curr.len-- + if(!QDELETED(target)) + target.update_ambient_light_from_z() + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + +/turf/proc/update_ambient_light_from_z() + + // If we're not outside, we don't show ambient light. + if(!is_outside()) + clear_ambient_light() + return FALSE + + // If we're dynamically lit, we want ambient light regardless of neighbors. + . = TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) + // If we're not, we want ambient light if one of our neighbors needs to show spillover from corners. + if(!.) + for(var/turf/T in RANGE_TURFS(src, 1)) + // Fuck if I know how these turfs are located in an area that is not an area. + if(isloc(T.loc) && TURF_IS_DYNAMICALLY_LIT_UNSAFE(T)) + . = TRUE + break + + if(.) + // Grab what we need to set ambient light. + // TODO: z-level data handlers should store this information in a cheaply accessible way. + var/obj/effect/overmap/visitable/sector/exoplanet/planet = global.overmap_sectors["[z]"] + if(istype(planet)) + if(planet.lightlevel) + set_ambient_light(COLOR_WHITE, planet.lightlevel) + return TRUE + else + if(config.starlight) + set_ambient_light(SSskybox.background_color, config.starlight) + return TRUE + + clear_ambient_light() + return FALSE diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm index e7740189d57..67b1de5e258 100644 --- a/code/controllers/subsystems/atoms.dm +++ b/code/controllers/subsystems/atoms.dm @@ -38,9 +38,14 @@ SUBSYSTEM_DEF(atoms) 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)) - InitAtom(A, mapload_arg) + if(atom_args) + atom_args.Insert(1, TRUE) + InitAtom(A, atom_args) + else + 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. @@ -87,6 +92,7 @@ SUBSYSTEM_DEF(atoms) else A.LateInitialize(arglist(arguments)) if(INITIALIZE_HINT_QDEL) + A.atom_flags |= ATOM_FLAG_INITIALIZED // never call EarlyDestroy if we return this hint qdel(A) qdeleted = TRUE else @@ -134,8 +140,3 @@ SUBSYSTEM_DEF(atoms) var/initlog = InitLog() if(initlog) text2file(initlog, "[global.log_directory]/initialize.log") - -#undef BAD_INIT_QDEL_BEFORE -#undef BAD_INIT_DIDNT_INIT -#undef BAD_INIT_SLEPT -#undef BAD_INIT_NO_HINT diff --git a/code/controllers/subsystems/fluids.dm b/code/controllers/subsystems/fluids.dm index b921af44e65..308b3546e30 100644 --- a/code/controllers/subsystems/fluids.dm +++ b/code/controllers/subsystems/fluids.dm @@ -73,10 +73,10 @@ SUBSYSTEM_DEF(fluids) flooded_a_neighbor = FALSE UPDATE_FLUID_BLOCKED_DIRS(current_turf) for(spread_dir in global.cardinal) - if(current_turf.fluid_blocked_dirs & spread_dir) + if(current_turf.fluid_blocked_dirs & spread_dir) continue neighbor = get_step(current_turf, spread_dir) - if(!istype(neighbor) || neighbor.flooded) + if(!istype(neighbor) || neighbor.flooded) continue UPDATE_FLUID_BLOCKED_DIRS(neighbor) if((neighbor.fluid_blocked_dirs & global.reverse_dir[spread_dir]) || !neighbor.CanFluidPass(spread_dir) || checked_targets[neighbor]) @@ -192,7 +192,7 @@ SUBSYSTEM_DEF(fluids) current_fluid.last_flow_dir = 0 if (MC_TICK_CHECK) - break + break if(!holders_copied_yet) holders_copied_yet = TRUE @@ -203,6 +203,8 @@ SUBSYSTEM_DEF(fluids) processing_holders.len-- if(!QDELETED(reagent_holder)) reagent_holder.handle_update() + else + holders_to_update -= reagent_holder if(MC_TICK_CHECK) return diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index 095cf0a91a5..8f71c4f3a8d 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, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level + var/list/collection_timeout = list(0, 3 MINUTES, 10 SECONDS) // 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 @@ -97,13 +97,13 @@ SUBSYSTEM_DEF(garbage) /datum/controller/subsystem/garbage/fire() //the fact that this resets its processing each fire (rather then resume where it left off) is intentional. - var/queue = GC_QUEUE_PREQUEUE + var/queue = GC_QUEUE_FILTER while (state == SS_RUNNING) switch (queue) - if (GC_QUEUE_PREQUEUE) - HandlePreQueue() - queue = GC_QUEUE_PREQUEUE+1 + if (GC_QUEUE_FILTER) + HandleQueue(GC_QUEUE_FILTER) + queue = GC_QUEUE_FILTER+1 if (GC_QUEUE_CHECK) HandleQueue(GC_QUEUE_CHECK) queue = GC_QUEUE_CHECK+1 @@ -114,27 +114,8 @@ SUBSYSTEM_DEF(garbage) if (state == SS_PAUSED) //make us wait again before the next run. state = SS_RUNNING -//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond. -//Don't attempt to optimize, not worth the effort. -/datum/controller/subsystem/garbage/proc/HandlePreQueue() - var/list/tobequeued = queues[GC_QUEUE_PREQUEUE] - var/static/count = 0 - if (count) - var/c = count - count = 0 //so if we runtime on the Cut, we don't try again. - tobequeued.Cut(1,c+1) - - for (var/ref in tobequeued) - count++ - Queue(ref, GC_QUEUE_PREQUEUE+1) - if (MC_TICK_CHECK) - break - if (count) - tobequeued.Cut(1,count+1) - count = 0 - -/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK) - if (level == GC_QUEUE_CHECK) +/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_FILTER) + if (level == GC_QUEUE_FILTER) delslasttick = 0 gcedlasttick = 0 var/cut_off_time = world.time - collection_timeout[level] //ignore entries newer then this @@ -149,11 +130,14 @@ SUBSYSTEM_DEF(garbage) lastlevel = level - for (var/refID in queue) - if (!refID) + //We do this rather then for(var/refID in queue) because that sort of for loop copies the whole list. + //Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun. + for (var/refidx in 1 to length(queue)) + var/refID = queue[refidx] + if (isnull(refID)) count++ if (MC_TICK_CHECK) - break + return continue var/GCd_at_time = queue[refID] @@ -164,7 +148,7 @@ SUBSYSTEM_DEF(garbage) var/datum/D D = locate(refID) - if (!D || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake + if (isnull(D) || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake ++gcedlasttick ++totalgcs pass_counts[level]++ @@ -172,10 +156,11 @@ SUBSYSTEM_DEF(garbage) reference_find_on_fail -= refID //It's deleted we don't care anymore. #endif if (MC_TICK_CHECK) - break + return continue // Something's still referring to the qdel'd object. + fail_counts[level]++ switch (level) if (GC_QUEUE_CHECK) #ifdef TESTING @@ -192,30 +177,23 @@ SUBSYSTEM_DEF(garbage) if(!I.failures) to_world_log("GC: -- \ref[D] | [type] was unable to be GC'd --") I.failures++ - fail_counts[level]++ if (GC_QUEUE_HARDDELETE) if(harddel_halt) continue - fail_counts[level]++ HardDelete(D) if (MC_TICK_CHECK) - break + return continue Queue(D, level+1) if (MC_TICK_CHECK) - break + return if (count) queue.Cut(1,count+1) count = 0 -/datum/controller/subsystem/garbage/proc/PreQueue(datum/D) - if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - queues[GC_QUEUE_PREQUEUE] += D - D.gc_destroyed = GC_QUEUED_FOR_QUEUING - -/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) +/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) @@ -228,9 +206,6 @@ SUBSYSTEM_DEF(garbage) D.gc_destroyed = gctime var/list/queue = queues[level] - if (queue[refid]) - queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list. - queue[refid] = gctime //this is mainly to separate things profile wise. @@ -267,7 +242,7 @@ SUBSYSTEM_DEF(garbage) /datum/controller/subsystem/garbage/proc/HardQueue(datum/D) if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - queues[GC_QUEUE_PREQUEUE] += D + queues[GC_QUEUE_FILTER] += D D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL /datum/controller/subsystem/garbage/Recover() @@ -304,14 +279,14 @@ SUBSYSTEM_DEF(garbage) // 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. /proc/qdel(datum/D, force=FALSE, ...) - if(!D) + 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] - if (!I) + if (isnull(I)) I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type) I.qdels++ @@ -334,13 +309,13 @@ SUBSYSTEM_DEF(garbage) else I.destroy_time += TICK_USAGE_TO_MS(start_tick) - if(!D) + if(isnull(D)) return switch(hint) if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. GC_CHECK_AM_NULLSPACE(D, "QDEL_HINT_QUEUE") - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) if (QDEL_HINT_IWILLGC) D.gc_destroyed = world.time return @@ -360,19 +335,19 @@ SUBSYSTEM_DEF(garbage) #endif I.no_respect_force++ - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate() GC_CHECK_AM_NULLSPACE(D, "QDEL_HINT_HARDDEL") SSgarbage.HardQueue(D) if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. SSgarbage.HardDelete(D) if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion. - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) #ifdef TESTING D.find_references() #endif if (QDEL_HINT_IFFAIL_FINDREFERENCE) - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) #ifdef TESTING SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE #endif @@ -382,7 +357,7 @@ SUBSYSTEM_DEF(garbage) PRINT_STACK_TRACE("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") #endif I.no_hint++ - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") @@ -393,9 +368,14 @@ SUBSYSTEM_DEF(garbage) set name = "Find References" set src in world - find_references(FALSE) + user_find_references() + +/datum/proc/user_find_references() + if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "No", "Yes") == "No") + return + find_references() -/datum/proc/find_references(skip_alert) +/datum/proc/find_references() running_find_references = type if(usr && usr.client) if(usr.client.running_find_references) @@ -407,11 +387,6 @@ SUBSYSTEM_DEF(garbage) SSgarbage.next_fire = world.time + world.tick_lag return - if(!skip_alert) - if(UNLINT(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No")) == "No") - running_find_references = null - return - //this keeps the garbage collector from failing to collect objects being searched for in here SSgarbage.can_fire = 0 @@ -461,7 +436,7 @@ SUBSYSTEM_DEF(garbage) qdel(src, TRUE) //Force. if(!running_find_references) - find_references(TRUE) + find_references() /datum/verb/qdel_then_if_fail_find_references() set category = "Debug" diff --git a/code/controllers/subsystems/initialization/aspects.dm b/code/controllers/subsystems/initialization/aspects.dm new file mode 100644 index 00000000000..2c6d6409d10 --- /dev/null +++ b/code/controllers/subsystems/initialization/aspects.dm @@ -0,0 +1,15 @@ +// This subsystem exists solely to crosslink aspects due to mutual dependency loops. +SUBSYSTEM_DEF(aspects) + name = "Aspects" + flags = SS_NO_FIRE + init_order = SS_INIT_PRE_CHAR_SETUP + var/list/all_aspects = list() + +/datum/controller/subsystem/aspects/Initialize() + var/list/all_aspect_decls = decls_repository.get_decls_of_subtype(/decl/aspect) + for(var/aspect_type in all_aspect_decls) + var/decl/aspect/aspect = all_aspect_decls[aspect_type] + if(aspect.name) // remove when dev abstract decl changes are merged in + aspect.build_references() + all_aspects |= aspect + . = ..() diff --git a/code/controllers/subsystems/initialization/codex.dm b/code/controllers/subsystems/initialization/codex.dm index 85d54f03660..6c409ca3e63 100644 --- a/code/controllers/subsystems/initialization/codex.dm +++ b/code/controllers/subsystems/initialization/codex.dm @@ -2,37 +2,49 @@ SUBSYSTEM_DEF(codex) name = "Codex" flags = SS_NO_FIRE init_order = SS_INIT_MISC_CODEX + var/regex/linkRegex + var/regex/trailingLinebreakRegexStart + var/regex/trailingLinebreakRegexEnd var/list/all_entries = list() var/list/entries_by_path = list() var/list/entries_by_string = list() var/list/index_file = list() var/list/search_cache = list() - var/list/categories = list() /datum/controller/subsystem/codex/Initialize() - // Codex link syntax is such: - // keyword when keyword is mentioned verbatim, + // Codex link syntax is such: + // keyword when keyword is mentioned verbatim, // whatever when shit gets tricky linkRegex = regex(@"<(span|l)(\s+codexlink='([^>]*)'|)>([^<]+)","g") + // used to remove trailing linebreaks when retrieving codex body. + // TODO: clean up codex page generation so this isn't necessary. + trailingLinebreakRegexStart = regex(@"^<\s*\/*\s*br\s*\/*\s*>", "igm") + trailingLinebreakRegexEnd = regex(@"<\s*\/*\s*br\s*\/*\s*>$", "igm") + // Create general hardcoded entries. - for(var/ctype in typesof(/datum/codex_entry)) + for(var/ctype in subtypesof(/datum/codex_entry)) var/datum/codex_entry/centry = ctype - if(initial(centry.name) || initial(centry.associated_paths) || initial(centry.associated_strings)) + if(initial(centry.name)) centry = new centry() // Create categorized entries. + var/list/deferred_population = list() var/list/categories = decls_repository.get_decls_of_subtype(/decl/codex_category) for(var/ctype in categories) var/decl/codex_category/cat = categories[ctype] - if(cat?.name) - cat.Populate() + if(cat.defer_population) + deferred_population += cat + continue + cat.Populate() + + for(var/decl/codex_category/cat as anything in deferred_population) + cat.Populate() // Create the index file for later use. - for(var/thing in SScodex.all_entries) - var/datum/codex_entry/entry = thing + for(var/datum/codex_entry/entry as anything in all_entries) index_file[entry.name] = entry index_file = sortTim(index_file, /proc/cmp_text_asc) . = ..() @@ -42,7 +54,7 @@ SUBSYSTEM_DEF(codex) var/key = linkRegex.group[4] if(linkRegex.group[2]) key = linkRegex.group[3] - key = lowertext(trim(key)) + key = codex_sanitize(key) var/datum/codex_entry/linked_entry = get_entry_by_string(key) var/replacement = linkRegex.group[4] if(linked_entry) @@ -56,18 +68,18 @@ SUBSYSTEM_DEF(codex) if(entity.get_specific_codex_entry()) return entity.get_specific_codex_entry() return get_entry_by_string(entity.name) || entries_by_path[entity.type] - else if(entries_by_path[entry]) + if(ispath(entry)) return entries_by_path[entry] - else if(entries_by_string[lowertext(entry)]) - return entries_by_string[lowertext(entry)] + if(istext(entry)) + return entries_by_string[codex_sanitize(entry)] /datum/controller/subsystem/codex/proc/get_entry_by_string(var/string) - return entries_by_string[lowertext(trim(string))] + return entries_by_string[codex_sanitize(string)] /datum/controller/subsystem/codex/proc/present_codex_entry(var/mob/presenting_to, var/datum/codex_entry/entry) if(entry && istype(presenting_to) && presenting_to.client) var/datum/browser/popup = new(presenting_to, "codex\ref[entry]", "Codex", nheight=425) - popup.set_content(parse_links(entry.get_text(presenting_to), presenting_to)) + popup.set_content(parse_links(jointext(entry.get_codex_body(presenting_to), null), presenting_to)) popup.open() /datum/controller/subsystem/codex/proc/get_guide(var/category) @@ -79,7 +91,7 @@ SUBSYSTEM_DEF(codex) if(!initialized) return list() - searching = sanitize(lowertext(trim(searching))) + searching = codex_sanitize(searching) if(!searching) return list() if(!search_cache[searching]) @@ -90,12 +102,9 @@ SUBSYSTEM_DEF(codex) results = list() for(var/entry_title in entries_by_string) var/datum/codex_entry/entry = entries_by_string[entry_title] - if(findtext(entry.name, searching) || \ - findtext(entry.lore_text, searching) || \ - findtext(entry.mechanics_text, searching) || \ - findtext(entry.antag_text, searching)) + if(findtext(entry.name, searching) || findtext(entry.lore_text, searching) || findtext(entry.mechanics_text, searching) || findtext(entry.antag_text, searching)) results |= entry - search_cache[searching] = dd_sortedObjectList(results) + search_cache[searching] = sortTim(results, /proc/cmp_name_asc) return search_cache[searching] /datum/controller/subsystem/codex/Topic(href, href_list) @@ -103,8 +112,7 @@ SUBSYSTEM_DEF(codex) if(!. && href_list["show_examined_info"] && href_list["show_to"]) var/mob/showing_mob = locate(href_list["show_to"]) if(!istype(showing_mob) || !showing_mob.can_use_codex()) - return - + return var/atom/showing_atom = locate(href_list["show_examined_info"]) var/entry if(istype(showing_atom, /datum/codex_entry)) diff --git a/code/controllers/subsystems/initialization/fabrication.dm b/code/controllers/subsystems/initialization/fabrication.dm index 4e926800079..2c288555d40 100644 --- a/code/controllers/subsystems/initialization/fabrication.dm +++ b/code/controllers/subsystems/initialization/fabrication.dm @@ -11,7 +11,7 @@ SUBSYSTEM_DEF(fabrication) var/list/recipes_by_product_type = list() var/list/fields_by_id = list() - // Fabricators who want their initial recipies + // Weakrefs to fabricators who want their initial recipies var/list/fabricators_to_init = list() // These should be removed after rewriting crafting to respect init order. var/list/crafting_recipes_to_init = list() @@ -41,6 +41,11 @@ SUBSYSTEM_DEF(fabrication) if(ispath(handler.begins_with_object_type)) LAZYDISTINCTADD(crafting_procedures_by_type[handler.begins_with_object_type], handler) + for(var/weakref/weak_fab in fabricators_to_init) + var/obj/machinery/fabricator/fab = weak_fab.resolve() + fab?.refresh_design_cache() + fabricators_to_init.Cut() + for(var/datum/stack_recipe/recipe in crafting_recipes_to_init) recipe.InitializeMaterials() crafting_recipes_to_init.Cut() @@ -94,6 +99,8 @@ SUBSYSTEM_DEF(fabrication) . = crafting_procedures_by_type[_type] /datum/controller/subsystem/fabrication/proc/try_craft_with(var/obj/item/target, var/obj/item/thing, var/mob/user) + if(QDELETED(target) || QDELETED(thing) || QDELETED(user)) + return for(var/decl/crafting_stage/initial_stage in SSfabrication.find_crafting_recipes(target.type)) if(initial_stage.can_begin_with(target) && initial_stage.is_appropriate_tool(thing)) var/obj/item/crafting_holder/H = new /obj/item/crafting_holder(get_turf(target), initial_stage, target, thing, user) @@ -101,3 +108,6 @@ SUBSYSTEM_DEF(fabrication) return H else qdel(H) + +/datum/controller/subsystem/fabrication/proc/queue_design_cache_refresh(var/obj/machinery/fabricator/fab) + fabricators_to_init |= weakref(fab) \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/materials.dm b/code/controllers/subsystems/initialization/materials.dm index dde82d0e56d..cfe07bcfe10 100644 --- a/code/controllers/subsystems/initialization/materials.dm +++ b/code/controllers/subsystems/initialization/materials.dm @@ -15,11 +15,9 @@ SUBSYSTEM_DEF(materials) // Chemistry vars. var/list/active_holders = list() - var/list/chemical_reactions_by_type = list() var/list/chemical_reactions_by_id = list() var/list/chemical_reactions_by_result = list() var/list/processing_holders = list() - var/list/pending_reagent_change = list() var/list/cocktails_by_primary_ingredient = list() // Overlay caches @@ -59,6 +57,8 @@ SUBSYSTEM_DEF(materials) // Various other material functions. build_material_lists() // Build core material lists. build_fusion_reaction_list() // Build fusion reaction tree. + materials = sortTim(SSmaterials.materials, /proc/cmp_name_asc) + materials_by_name = sortTim(SSmaterials.materials_by_name, /proc/cmp_name_or_type_asc, TRUE) var/alpha_inc = 256 / DAMAGE_OVERLAY_COUNT for(var/i = 1; i <= DAMAGE_OVERLAY_COUNT; i++) @@ -76,11 +76,9 @@ SUBSYSTEM_DEF(materials) return materials = list() materials_by_name = list() - for(var/mtype in subtypesof(/decl/material)) - var/decl/material/new_mineral = mtype - if(!initial(new_mineral.name)) - continue - new_mineral = GET_DECL(mtype) + var/list/material_decls = decls_repository.get_decls_of_subtype(/decl/material) + for(var/mtype in material_decls) + var/decl/material/new_mineral = material_decls[mtype] materials += new_mineral materials_by_name[lowertext(new_mineral.name)] = new_mineral if(new_mineral.sparse_material_weight) @@ -143,7 +141,7 @@ SUBSYSTEM_DEF(materials) return planet.get_strata(location) var/s_key = "[location.z]" if(!global.default_strata_type_by_z[s_key]) - global.default_strata_type_by_z[s_key] = pick(subtypesof(/decl/strata)) + global.default_strata_type_by_z[s_key] = pick(decls_repository.get_decl_paths_of_subtype(/decl/strata)) return global.default_strata_type_by_z[s_key] /datum/controller/subsystem/materials/proc/get_material_by_name(var/mat_name) diff --git a/code/controllers/subsystems/input.dm b/code/controllers/subsystems/input.dm index 4a7d56790d7..833eec99b36 100644 --- a/code/controllers/subsystems/input.dm +++ b/code/controllers/subsystems/input.dm @@ -18,8 +18,7 @@ SUBSYSTEM_DEF(input) macro_set = list( "Any" = "\"KeyDown \[\[*\]\]\"", "Any+UP" = "\"KeyUp \[\[*\]\]\"", - "Back" = "\".winset \\\"outputwindow.input.text=\\\"\\\"\\\"\"", - "Escape" = "Reset-Held-Keys" + "Back" = "\".winset \\\"outputwindow.input.text=\\\"\\\"\\\"\"" ) // Badmins just wanna have fun ♪ diff --git a/code/controllers/subsystems/jobs.dm b/code/controllers/subsystems/jobs.dm index 2d73a9154d9..82d9af389e1 100644 --- a/code/controllers/subsystems/jobs.dm +++ b/code/controllers/subsystems/jobs.dm @@ -285,16 +285,17 @@ SUBSYSTEM_DEF(jobs) var/age = V.client.prefs.get_character_age() if(age < job.minimum_character_age) // Nope. continue - switch(age) - if(job.minimum_character_age to (job.minimum_character_age+10)) - weightedCandidates[V] = 3 // Still a bit young. - if((job.minimum_character_age+10) to (job.ideal_character_age-10)) - weightedCandidates[V] = 6 // Better. - if((job.ideal_character_age-10) to (job.ideal_character_age+10)) + switch(age - job.ideal_character_age) + if(0 to -10) + if(age < (job.minimum_character_age+10)) + weightedCandidates[V] = 3 // Still a bit young. + else + weightedCandidates[V] = 6 // Better. + if(-10 to 10) weightedCandidates[V] = 10 // Great. - if((job.ideal_character_age+10) to (job.ideal_character_age+20)) + if(10 to 20) weightedCandidates[V] = 6 // Still good. - if((job.ideal_character_age+20) to INFINITY) + if(20 to INFINITY) weightedCandidates[V] = 3 // Geezer. else // If there's ABSOLUTELY NOBODY ELSE diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm index 1dad77c32a9..daf0a7a44df 100644 --- a/code/controllers/subsystems/lighting.dm +++ b/code/controllers/subsystems/lighting.dm @@ -7,6 +7,7 @@ SUBSYSTEM_DEF(lighting) var/total_lighting_overlays = 0 var/total_lighting_sources = 0 + var/total_ambient_turfs = 0 var/list/lighting_corners = list() // List of all lighting corners in the world. var/list/light_queue = list() // lighting sources queued for update. @@ -33,7 +34,7 @@ SUBSYSTEM_DEF(lighting) #ifdef USE_INTELLIGENT_LIGHTING_UPDATES "IUR: [total_ss_updates ? round(total_instant_updates/(total_instant_updates+total_ss_updates)*100, 0.1) : "NaN"]%\n", #endif - "\tT:{L:[total_lighting_sources] C:[lighting_corners.len] O:[total_lighting_overlays]}\n", + "\tT:{L:[total_lighting_sources] C:[lighting_corners.len] O:[total_lighting_overlays] A:[total_ambient_turfs]}\n", "\tP:{L:[light_queue.len - (lq_idex - 1)]|C:[corner_queue.len - (cq_idex - 1)]|O:[overlay_queue.len - (oq_idex - 1)]}\n", "\tL:{L:[processed_lights]|C:[processed_corners]|O:[processed_overlays]}\n" ) @@ -81,6 +82,8 @@ SUBSYSTEM_DEF(lighting) 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 diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm index b804766b704..e5173d352a8 100644 --- a/code/controllers/subsystems/mapping.dm +++ b/code/controllers/subsystems/mapping.dm @@ -25,6 +25,19 @@ SUBSYSTEM_DEF(mapping) for(var/datum/map_template/MT as anything in get_all_template_instances()) register_map_template(MT) + // Resize the world to the max template size to fix a BYOND bug with world resizing breaking events. + // REMOVE WHEN THIS IS FIXED: https://www.byond.com/forum/post/2833191 + var/new_maxx = world.maxx + var/new_maxy = world.maxy + for(var/map_template_name in map_templates) + var/datum/map_template/map_template = map_templates[map_template_name] + new_maxx = max(map_template.width, new_maxx) + new_maxy = max(map_template.height, new_maxy) + if (new_maxx > world.maxx) + world.maxx = new_maxx + if (new_maxy > world.maxy) + world.maxy = new_maxy + // Populate overmap. if(length(global.using_map.overmap_ids)) for(var/overmap_id in global.using_map.overmap_ids) @@ -65,7 +78,7 @@ SUBSYSTEM_DEF(mapping) PRINT_STACK_TRACE("Duplicate map name '[map_template.name]' on type [map_template.type]!") return FALSE return TRUE - + /datum/controller/subsystem/mapping/proc/get_all_template_instances() . = list() for(var/template_type in subtypesof(/datum/map_template)) diff --git a/code/controllers/subsystems/processing/blob.dm b/code/controllers/subsystems/processing/blob.dm new file mode 100644 index 00000000000..c90b507c0ba --- /dev/null +++ b/code/controllers/subsystems/processing/blob.dm @@ -0,0 +1,4 @@ +PROCESSING_SUBSYSTEM_DEF(blob) + name = "Blobs" + priority = SS_PRIORITY_BLOB + wait = 5 SECONDS diff --git a/code/controllers/subsystems/processing/circuit.dm b/code/controllers/subsystems/processing/circuit.dm index 85b70d4d540..4151434dfe6 100644 --- a/code/controllers/subsystems/processing/circuit.dm +++ b/code/controllers/subsystems/processing/circuit.dm @@ -12,7 +12,6 @@ PROCESSING_SUBSYSTEM_DEF(circuit) var/list/cached_components = list() // Associative list of [component_path]:[component] pairs var/list/all_assemblies = list() // Associative list of [assembly_name]:[assembly_path] pairs var/list/cached_assemblies = list() // Associative list of [assembly_path]:[assembly] pairs - var/list/all_circuits = list() // Associative list of [circuit_name]:[circuit_path] pairs var/list/circuit_fabricator_recipe_list = list() // Associative list of [category_name]:[list_of_circuit_paths] pairs var/cost_multiplier = SHEET_MATERIAL_AMOUNT / 10 // Each circuit cost unit is 200cm3 diff --git a/code/controllers/subsystems/processing/overmap.dm b/code/controllers/subsystems/processing/overmap.dm new file mode 100644 index 00000000000..7eb6bd1784b --- /dev/null +++ b/code/controllers/subsystems/processing/overmap.dm @@ -0,0 +1,25 @@ +// Some duplicated behavior from SSprocessing in here so atoms can +// still process normally as well as handling overmap movement. + +SUBSYSTEM_DEF(overmap) + name = "Overmap" + priority = SS_PRIORITY_OVERMAP + wait = 2 + flags = SS_BACKGROUND | SS_POST_FIRE_TIMING | SS_NO_INIT + var/list/moving_entities = list() + var/list/current_run = list() + +// Processing boilerplate. +/datum/controller/subsystem/overmap/fire(resumed = 0) + if(!resumed) + src.current_run = moving_entities.Copy() + var/list/current_run = src.current_run + var/wait = src.wait + var/times_fired = src.times_fired + while(current_run.len) + var/obj/effect/overmap/entity = current_run[current_run.len] + current_run.len-- + if(QDELETED(entity) || entity.ProcessOvermap(wait, times_fired) == PROCESS_KILL) + moving_entities -= entity + if (MC_TICK_CHECK) + return diff --git a/code/controllers/subsystems/radiation.dm b/code/controllers/subsystems/radiation.dm index a160166cd9d..c84d255da74 100644 --- a/code/controllers/subsystems/radiation.dm +++ b/code/controllers/subsystems/radiation.dm @@ -16,7 +16,7 @@ SUBSYSTEM_DEF(radiation) if (!resumed) current_sources = sources.Copy() current_res_cache = resistance_cache.Copy() - listeners = global.living_mob_list_.Copy() + listeners = global.living_mob_list_.Copy() while(current_sources.len) var/datum/radiation_source/S = current_sources[current_sources.len] @@ -28,7 +28,7 @@ SUBSYSTEM_DEF(radiation) S.update_rad_power(S.rad_power - config.radiation_decay_rate) if (MC_TICK_CHECK) return - + while(current_res_cache.len) var/turf/T = current_res_cache[current_res_cache.len] current_res_cache.len-- @@ -106,7 +106,7 @@ SUBSYSTEM_DEF(radiation) var/datum/radiation_source/existing = sources_assoc[S.source_turf] if(existing) qdel(existing) - sources += S + sources |= S sources_assoc[S.source_turf] = S // Creates a temporary radiation source that will decay diff --git a/code/controllers/subsystems/skybox.dm b/code/controllers/subsystems/skybox.dm index 739d27f8917..b07694ae7b1 100644 --- a/code/controllers/subsystems/skybox.dm +++ b/code/controllers/subsystems/skybox.dm @@ -9,7 +9,7 @@ SUBSYSTEM_DEF(skybox) var/background_icon = "dyable" var/use_stars = TRUE var/use_overmap_details = TRUE - var/star_path = 'icons/skybox/skybox.dmi' + var/stars_icon = 'icons/skybox/skybox.dmi' var/star_state = "stars" var/static/list/skybox_cache = list() @@ -50,7 +50,7 @@ SUBSYSTEM_DEF(skybox) im.plane = DUST_PLANE im.alpha = 128 im.blend_mode = BLEND_ADD - + MA.overlays = list(im) dust_cache["[i]"] = MA @@ -64,19 +64,19 @@ SUBSYSTEM_DEF(skybox) im.blend_mode = BLEND_ADD MA.overlays = list(im) - + speedspace_cache["NS_[i]"] = MA - + // EAST/WEST MA = new(normal_space) im = image('icons/turf/space_dust_transit.dmi', "speedspace_ew_[i]") im.plane = DUST_PLANE im.blend_mode = BLEND_ADD - + MA.overlays = list(im) - + speedspace_cache["EW_[i]"] = MA - + //Over-the-edge images for (var/dir in global.alldirs) var/mutable_appearance/MA = new(normal_space) @@ -117,7 +117,7 @@ SUBSYSTEM_DEF(skybox) var/image/base = overlay_image(skybox_icon, background_icon, background_color, PIXEL_SCALE) if(use_stars) - var/image/stars = overlay_image(skybox_icon, star_state, flags = PIXEL_SCALE | RESET_COLOR) + var/image/stars = overlay_image(stars_icon, star_state, flags = PIXEL_SCALE | RESET_COLOR) base.overlays += stars res.overlays += base diff --git a/code/controllers/subsystems/statistics.dm b/code/controllers/subsystems/statistics.dm index c6931d5ba1e..7c031e71a1c 100644 --- a/code/controllers/subsystems/statistics.dm +++ b/code/controllers/subsystems/statistics.dm @@ -149,7 +149,7 @@ SUBSYSTEM_DEF(statistics) death.place_of_death = sanitize_sql(death.place_of_death) death.name = sanitize_sql(dead.real_name) death.key = sanitize_sql(dead.key) - death.special_role = sanitize_sql(dead.mind.get_special_role_name()) + death.special_role = sanitize_sql(dead.mind.get_special_role_name("No special role")) death.job = sanitize_sql(dead.mind.assigned_role) if(dead.last_attacker_) death.last_attacker_name = sanitize_sql(dead.last_attacker_.name) diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm index c708696697b..af33521fc58 100644 --- a/code/controllers/subsystems/supply.dm +++ b/code/controllers/subsystems/supply.dm @@ -9,8 +9,6 @@ SUBSYSTEM_DEF(supply) var/points = 50 var/points_per_process = 1 var/point_sources = list() - var/pointstotalsum = 0 - var/pointstotal = 0 var/price_markup = 1.15 var/crate_return_rebate = 0.9 @@ -24,7 +22,7 @@ SUBSYSTEM_DEF(supply) var/list/requestlist = list() var/list/donelist = list() var/list/master_supply_list = list() - + //shuttle movement var/movetime = 1200 var/datum/shuttle/autodock/ferry/supply/shuttle @@ -34,7 +32,7 @@ SUBSYSTEM_DEF(supply) "manifest" = "From exported manifests", "crate" = "From exported crates", "data" = "From uploaded survey data", - "total" = "Total" + "total" = "Total" ) /datum/controller/subsystem/supply/Initialize() @@ -96,8 +94,8 @@ SUBSYSTEM_DEF(supply) var/atom/A = atom if(find_slip && istype(A,/obj/item/paper/manifest)) var/obj/item/paper/manifest/slip = A - if(!slip.is_copy && length(slip.stamped)) - add_points_from_source(slip.order_total * slip_return_rebate, "manifest") + if(!LAZYACCESS(slip.metadata, "is_copy") && LAZYLEN(slip.applied_stamps)) + add_points_from_source(LAZYACCESS(slip.metadata, "order_total") * slip_return_rebate, "manifest") find_slip = 0 continue @@ -161,8 +159,8 @@ SUBSYSTEM_DEF(supply) info +="CONTENTS: