diff --git a/beestation.dme b/beestation.dme index aec9c2351be21..37782b3b5dc61 100644 --- a/beestation.dme +++ b/beestation.dme @@ -1904,6 +1904,7 @@ #include "code\modules\admin\view_variables\topic_basic.dm" #include "code\modules\admin\view_variables\topic_list.dm" #include "code\modules\admin\view_variables\view_variables.dm" +#include "code\modules\admin\view_variables\vv_ghost.dm" #include "code\modules\antagonists\eldritch.dm" #include "code\modules\antagonists\toddsie.dm" #include "code\modules\antagonists\_common\antag_datum.dm" @@ -2440,6 +2441,7 @@ #include "code\modules\client\verbs\ooc.dm" #include "code\modules\client\verbs\ping.dm" #include "code\modules\client\verbs\suicide.dm" +#include "code\modules\client\verbs\typing.dm" #include "code\modules\client\verbs\who.dm" #include "code\modules\clothing\chameleon.dm" #include "code\modules\clothing\clothing.dm" @@ -2477,6 +2479,7 @@ #include "code\modules\clothing\head\tinfoilhat.dm" #include "code\modules\clothing\head\tophat.dm" #include "code\modules\clothing\masks\_masks.dm" +#include "code\modules\clothing\masks\bandana.dm" #include "code\modules\clothing\masks\boxing.dm" #include "code\modules\clothing\masks\breath.dm" #include "code\modules\clothing\masks\cluwne.dm" diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index a121e87c9a282..acdcd16740e5d 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -243,9 +243,10 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define BLOCKING_HUNTER (1<<3) //is the item more suited to fighting fauna? // Object/Item sharpness -#define IS_BLUNT 0 -#define IS_SHARP 1 -#define IS_SHARP_ACCURATE 2 +#define BLUNT 0 //Can only remove limbs if they're easy to remove +#define SHARP 1 //Can only remove limbs if target is dead +#define SHARP_DISMEMBER 2 //Can only remove limbs if the limb is already disabled +#define SHARP_DISMEMBER_EASY 3 //Has a chance equal to weapon force to remove limb on every attack, in some cases taking them off in one swing //! ### His Grace. #define HIS_GRACE_SATIATED 0 //! He hungers not. If bloodthirst is set to this, His Grace is asleep. diff --git a/code/__DEFINES/dye_keys.dm b/code/__DEFINES/dye_keys.dm index 9efe387bc636e..8d9496b5a10c8 100644 --- a/code/__DEFINES/dye_keys.dm +++ b/code/__DEFINES/dye_keys.dm @@ -2,6 +2,7 @@ #define DYE_REGISTRY_JUMPSKIRT "jumpskirt" #define DYE_REGISTRY_SUITS "suit" #define DYE_REGISTRY_GLOVES "gloves" +#define DYE_REGISTRY_BANDANA "bandana" #define DYE_REGISTRY_SNEAKERS "sneakers" #define DYE_REGISTRY_CAP "softcap" #define DYE_REGISTRY_BERET "beret" diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 04e7d943ddb6e..820be445b4754 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -56,14 +56,16 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define HTML_USE_INITAL_ICON_1 (1<<13) /// Prevents direct access for anything in the contents of this atom. #define NO_DIRECT_ACCESS_FROM_CONTENTS_1 (1<<14) +/// Prevents aggregation of the item in the stack panel +#define STAT_UNIQUE_1 (1<<15) //turf-only flags. These use flags_1 too. // These exist to cover /turf and /area at the same time -#define NOJAUNT_1 (1<<15) -#define UNUSED_RESERVATION_TURF_1 (1<<16) -#define CAN_BE_DIRTY_1 (1<<17) //! If a turf can be made dirty at roundstart. This is also used in areas. -#define NO_LAVA_GEN_1 (1<<18) //! Blocks lava rivers being generated on the turf -#define NO_RUINS_1 (1<<19) //! Blocks ruins spawning on the turf +#define NOJAUNT_1 (1<<16) +#define UNUSED_RESERVATION_TURF_1 (1<<17) +#define CAN_BE_DIRTY_1 (1<<18) //! If a turf can be made dirty at roundstart. This is also used in areas. +#define NO_LAVA_GEN_1 (1<<19) //! Blocks lava rivers being generated on the turf +#define NO_RUINS_1 (1<<20) //! Blocks ruins spawning on the turf // Update flags for [/atom/proc/update_appearance] /// Update the atom's name @@ -111,6 +113,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define HIDDEN_STASH_LOCATION (1<<10) /// Indicates that this area uses an APC from another location (Skips the unit tests for APCs) #define REMOTE_APC (1<<11) +/// This area is prevented from having gravity (ie. space, nearstation, or outside solars) +#define NO_GRAVITY (1<<12) /* These defines are used specifically with the atom/pass_flags bitmask diff --git a/code/__DEFINES/gravity.dm b/code/__DEFINES/gravity.dm index a638b22be3dd6..d5650651c5ea2 100644 --- a/code/__DEFINES/gravity.dm +++ b/code/__DEFINES/gravity.dm @@ -19,8 +19,10 @@ * This should only be possible on multi-z maps because it works like shit on maps that aren't. */ #define NEGATIVE_GRAVITY -1 - -#define STANDARD_GRAVITY 1 //Anything above this is high gravity, anything below no grav until negative gravity +/// Used to indicate no gravity +#define ZERO_GRAVITY 0 +//Anything above this is high gravity, anything below no grav until negative gravity +#define STANDARD_GRAVITY 1 /// The gravity strength threshold for high gravity damage. #define GRAVITY_DAMAGE_THRESHOLD 3 /// The scaling factor for high gravity damage. diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index f91c1f44bad1c..beb339be799f5 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -18,7 +18,7 @@ GLOBAL_VAR_INIT(magic_appearance_detecting_image, new /image) // appearances are // The filters list has the same ref type id as a filter, but isnt one and also isnt a list, so we have to check if the thing has Cut() instead GLOBAL_VAR_INIT(refid_filter, TYPEID(filter(type="angular_blur"))) -#define isfilter(thing) (!hascall(thing, "Cut") && TYPEID(thing) == GLOB.refid_filter) +#define isfilter(thing) (!islist(thing) && hascall(thing, "Cut") && TYPEID(thing) == GLOB.refid_filter) GLOBAL_DATUM_INIT(regex_rgb_text, /regex, regex(@"^#?(([0-9a-fA-F]{8})|([0-9a-fA-F]{6})|([0-9a-fA-F]{3}))$")) #define iscolortext(thing) (istext(thing) && GLOB.regex_rgb_text.Find(thing)) diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index 77e8060c06532..42002e5ab433c 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -22,9 +22,22 @@ // LANGUAGE SOURCE DEFINES -#define LANGUAGE_ALL "all" // For use in full removal only. +/// For use in full removal only. +#define LANGUAGE_ALL "all" + +// Generic language sources. +/// Language is linked to the movable directly. #define LANGUAGE_ATOM "atom" +/// Language is linked to the mob's mind. +/// If a mind transfer happens, language follows. #define LANGUAGE_MIND "mind" +/// Language is linked to the mob's species. +/// If a species change happens, language goes away. +/// If applied to a non-human (no species) atom, this is effectively the same as [LANGUAGE_ATOM]. +#define LANGUAGE_SPECIES "species" + +// More specific language sources. +// Only ever goes away when dismissed directly. #define LANGUAGE_FRIEND "friend" #define LANGUAGE_ABSORB "absorb" #define LANGUAGE_APHASIA "aphasia" @@ -46,6 +59,13 @@ #define LANGUAGE_MULTILINGUAL "multilingual" #define LANGUAGE_EMP "emp" #define LANGUAGE_HOLOPARA "holoparasite" +#define LANGUAGE_BABEL "babel" + +// Language flags. Used in granting and removing languages. +/// This language can be spoken. +#define SPOKEN_LANGUAGE (1<<0) +/// This language can be understood. +#define UNDERSTOOD_LANGUAGE (1<<1) // Languages available from Multilingual GLOBAL_LIST_INIT(multilingual_language_list, typecacheof(list( diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 4e8891ec83936..bf747004f89b3 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -1,27 +1,11 @@ //Defines for atom layers and planes //KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE -//NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE -#define LOWEST_EVER_PLANE -200 - -#define CLICKCATCHER_PLANE -99 - -#define PLANE_SPACE -95 -#define PLANE_SPACE_PARALLAX -90 - -#define GRAVITY_PULSE_PLANE -89 -#define GRAVITY_PULSE_RENDER_TARGET "*GRAVPULSE_RENDER_TARGET" -//#define ZMIMIC_MIN_PLANE -80 -// ZMIMIC: ----------- -80 to -70 -// Highest plane used by zmimic, occupies up to -ZMIMIC_MAX_DEPTH -#define ZMIMIC_MAX_PLANE -70 -/// The maxiumum number of planes deep we'll go before we just dump everything on the same plane. -#define ZMIMIC_MAX_DEPTH 10 +//KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE -#define FLOOR_PLANE -7 -#define GAME_PLANE -4 -#define GAME_PLANE_RENDER_TARGET "GAME_PLANE_RENDER_TARGET" +///cinematics are "below" the splash screen +#define CINEMATIC_LAYER -1 #define SPACE_LAYER 1.8 //#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define @@ -100,6 +84,54 @@ #define TEXT_EFFECT_UI_LAYER 5.90 // text effects shouldn't be displayed behind. // maybe it should be custom layer category like 'UI_LAYER 6' +///1000 is an unimportant number, it's just to normalize copied layers +#define RADIAL_LAYER 1000 + +#define RADIAL_BACKGROUND_LAYER 0 +#define RADIAL_CONTENT_LAYER 1000 + +/** + * Planes + */ + +//NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE +#define LOWEST_EVER_PLANE -200 + +#define CLICKCATCHER_PLANE -99 + +#define PLANE_SPACE -95 +#define PLANE_SPACE_PARALLAX -90 + +#define GRAVITY_PULSE_PLANE -89 +#define GRAVITY_PULSE_RENDER_TARGET "*GRAVPULSE_RENDER_TARGET" + +//---------- Z-MIMIC ------------- +//#define ZMIMIC_MIN_PLANE -80 +// ZMIMIC: ----------- -80 to -70 +// Highest plane used by zmimic, occupies up to -ZMIMIC_MAX_DEPTH +#define ZMIMIC_MAX_PLANE -70 +/// The maxiumum number of planes deep we'll go before we just dump everything on the same plane. +#define ZMIMIC_MAX_DEPTH 10 + +//---------- ABSTRACT LIGHTING ------------- +// Layering order of these is not particularly meaningful. +// Important part is the seperation of the planes for control via plane_master +// We put these below the standard planes because if they are rendered without a plane-master (RenderIcon) +// then we want them to be as hidden as possible. + +///This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas +#define EMISSIVE_PLANE -50 +#define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE" + +/// The plane for managing the global starlight effect +#define STARLIGHT_PLANE -45 + +//---------- STANDARD ------------- + +#define FLOOR_PLANE -7 +#define GAME_PLANE -4 +#define GAME_PLANE_RENDER_TARGET "GAME_PLANE_RENDER_TARGET" + #define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals #define AREA_PLANE 60 @@ -115,9 +147,6 @@ #define LIGHTING_PLANE 100 #define LIGHTING_PLANE_ADDITIVE 101 -/// The plane for managing the global starlight effect -#define STARLIGHT_PLANE 105 - ///Lighting objects that are "free floating" #define O_LIGHTING_VISUAL_PLANE 110 #define O_LIGHTING_VISUAL_LAYER 110 @@ -128,13 +157,6 @@ ///visibility + hiding of things outside of light source range #define BYOND_LIGHTING_PLANE 130 -//---------- EMISSIVES ------------- -//Layering order of these is not particularly meaningful. -//Important part is the seperation of the planes for control via plane_master - -///This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas -#define EMISSIVE_PLANE 150 -#define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE" ///---------------- MISC ----------------------- @@ -183,17 +205,8 @@ #define ABOVE_HUD_PLANE 1100 #define ABOVE_HUD_RENDER_TARGET "ABOVE_HUD_PLANE" -///1000 is an unimportant number, it's just to normalize copied layers -#define RADIAL_LAYER 1000 - -#define RADIAL_BACKGROUND_LAYER 0 -#define RADIAL_CONTENT_LAYER 1000 - ///Plane of the "splash" icon used that shows on the lobby screen. Nothing should ever be above this. #define SPLASHSCREEN_PLANE 9999 -///cinematics are "below" the splash screen -#define CINEMATIC_LAYER -1 - ///Plane master controller keys #define PLANE_MASTERS_GAME "plane_masters_game" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index dd6121db10c3d..725630f412cfb 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -279,6 +279,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// this object has been frozen #define TRAIT_FROZEN "frozen" + +/// Trait given to a mob that is currently thinking (giving off the "thinking" icon), used in an IC context +#define TRAIT_THINKING_IN_CHARACTER "currently_thinking_IC" + ///Turf trait for when a turf is transparent #define TURF_Z_TRANSPARENT_TRAIT "turf_z_transparent" diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index d52b459750be9..9cd1e59e7144d 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -128,6 +128,9 @@ /// Trait given to an atom/movable when they orbit something. #define ORBITING_TRAIT "orbiting" +/// This trait comes from when a mob is currently typing. +#define CURRENTLY_TYPING_TRAIT "currently_typing" + #define VENTCRAWLING_TRAIT "ventcrawling" #define SPECIES_FLIGHT_TRAIT "species-flight" #define NO_GRAVITY_TRAIT "no-gravity" diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 37b857bba8133..7602316bbbeac 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -32,8 +32,7 @@ #define VV_MSG_EDITED "
Var Edited" #define VV_MSG_DELETED "
Deleted" -#define VV_NORMAL_LIST_NO_EXPAND_THRESHOLD 50 -#define VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD 150 +#define VV_BIG_SIZED_LIST_THRESHOLD 50 //#define IS_VALID_ASSOC_KEY(V) (istext(V) || ispath(V) || isdatum(V) || islist(V)) #define IS_VALID_ASSOC_KEY(V) (!isnum_safe(V)) //hhmmm.. @@ -45,6 +44,9 @@ #define VV_HREF_TARGETREF(targetref, href_key, text) "[text]" #define VV_HREF_TARGET_1V(target, href_key, text, varname) "[text]" //for stuff like basic varedits, one variable #define VV_HREF_TARGETREF_1V(targetref, href_key, text, varname) "[text]" +//! Non-standard helper for special list vv. this doesn't use VV_HK_TARGET and REF because special list doesn't work in a sane sense. +#define VV_HREF_SPECIAL(dmlist_origin_ref, href_action, text, list_index, dmlist_varname) "[text]" +#define VV_HREF_SPECIAL_MENU(dmlist_origin_ref, href_action, dmlist_varname) "?_src_=vars;[HrefToken()];[href_action]=TRUE;[VV_HK_DO_LIST_EDIT]=TRUE;dmlist_origin_ref=[dmlist_origin_ref];dmlist_varname=[dmlist_varname]" #define GET_VV_TARGET locate(href_list[VV_HK_TARGET]) #define GET_VV_VAR_TARGET href_list[VV_HK_VARNAME] @@ -71,6 +73,9 @@ #define VV_HK_LIST_SHUFFLE "listshuffle" #define VV_HK_LIST_SET_LENGTH "listlen" +// I exist alone here just for special list edit. God, why. +#define VV_HK_DO_LIST_EDIT "do_vv_list_edit" + // vv_do_basic() keys #define VV_HK_BASIC_EDIT "datumedit" #define VV_HK_BASIC_CHANGE "datumchange" @@ -182,3 +187,42 @@ /// ALWAYS render a reduced list, useful for fuckoff big datums that need to be condensed for the sake of client load #define VV_ALWAYS_CONTRACT_LIST (1<<0) +#define VV_READ_ONLY (1<<1) + + +#define VV_LIST_PROTECTED (1) /// Can not vv the list. Doing vv this list is not safe. +#define VV_LIST_READ_ONLY (2) /// Can vv the list, but can not edit. +#define VV_LIST_EDITABLE (3) /// Can vv the list, and edit. + +// Becomes read only at live, editable at debug, dynamically +#ifdef DEBUG +#define VV_LIST_READ_ONLY___DEBUG_EDITABLE (3) +#else +#define VV_LIST_READ_ONLY___DEBUG_EDITABLE (2) +#endif + +/// A list of all the special byond lists that need to be handled different by vv. +/// manually adding var name is recommanded. +GLOBAL_LIST_INIT(vv_special_lists, list( + // /datum + "vars" = VV_LIST_READ_ONLY, + // /atom + "overlays" = VV_LIST_EDITABLE, + "underlays" = VV_LIST_EDITABLE, + "vis_contents" = VV_LIST_EDITABLE, + "vis_locs" = VV_LIST_READ_ONLY___DEBUG_EDITABLE, + "contents" = VV_LIST_EDITABLE, + "locs" = VV_LIST_READ_ONLY___DEBUG_EDITABLE, + "verbs" = VV_LIST_READ_ONLY___DEBUG_EDITABLE, // verb is not safe to edit in live server + "filters" = VV_LIST_PROTECTED, // This is not good to change in vv, yet. + // /client + "bounds" = VV_LIST_PROTECTED, // DM document says it's read-only. Better not to edit this. + "images" = VV_LIST_EDITABLE, + "screen" = VV_LIST_EDITABLE, +)) +// NOTE: this is highly attached to how /datum/vv_ghost works. + + +#ifndef DEBUG +GLOBAL_PROTECT(vv_special_lists) // changing this in live server is a bad idea +#endif diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm index 9e81c7044de12..0ae35ef62507e 100644 --- a/code/__HELPERS/areas.dm +++ b/code/__HELPERS/areas.dm @@ -91,7 +91,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng newA = new area_choice newA.setup(str) newA.set_dynamic_lighting() - newA.has_gravity = oldA.has_gravity + newA.default_gravity = oldA.default_gravity else newA = area_choice diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 8d75b40d3dd9d..43a1497a6ec07 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -183,16 +183,17 @@ DEFINE_BITFIELD(flags_1, list( "HOLOGRAM_1" = HOLOGRAM_1, "INITIALIZED_1" = INITIALIZED_1, "IS_ONTOP_1" = IS_ONTOP_1, + //"IS_PLAYER_COLORABLE_1" = IS_PLAYER_COLORABLE_1, "NODECONSTRUCT_1" = NODECONSTRUCT_1, "NOJAUNT_1" = NOJAUNT_1, "NO_RUINS_1" = NO_RUINS_1, "NO_LAVA_GEN_1" = NO_LAVA_GEN_1, - "UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1, "OVERLAY_QUEUED_1" = OVERLAY_QUEUED_1, "ON_BORDER_1" = ON_BORDER_1, "PREVENT_CLICK_UNDER_1" = PREVENT_CLICK_UNDER_1, - "TESLA_IGNORE_1" = TESLA_IGNORE_1, "PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1, + "TESLA_IGNORE_1" = TESLA_IGNORE_1, + "UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1, "UNPAINTABLE_1" = UNPAINTABLE_1, )) diff --git a/code/_globalvars/lists/admin.dm b/code/_globalvars/lists/admin.dm index aa7075fd54dda..4d46c5358641d 100644 --- a/code/_globalvars/lists/admin.dm +++ b/code/_globalvars/lists/admin.dm @@ -8,19 +8,3 @@ GLOBAL_LIST_INIT_TYPED(smite_list, /datum/smite, init_smites()) GLOBAL_VAR_INIT(admin_notice, "") // Admin notice that all clients see when joining the server - -// A list of all the special byond lists that need to be handled different by vv -GLOBAL_LIST_INIT(vv_special_lists, init_special_list_names()) - -/proc/init_special_list_names() - var/list/output = list() - var/obj/sacrifice = new - for(var/varname in sacrifice.vars) - var/value = sacrifice.vars[varname] - if(!islist(value)) - if(!isdatum(value) && hascall(value, "Cut")) - output += varname - continue - if(isnull(locate(REF(value)))) - output += varname - return output diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index aab4c39b3d4b4..08080ba01b0f3 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -93,6 +93,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NOMOBSWAP" = TRAIT_NOMOBSWAP, "TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION, "TRAIT_THERMAL_VISION" = TRAIT_THERMAL_VISION, + "TRAIT_THINKING_IN_CHARACTER" = TRAIT_THINKING_IN_CHARACTER, "TRAIT_ABDUCTOR_TRAINING" = TRAIT_ABDUCTOR_TRAINING, "TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING, "TRAIT_SURGEON" = TRAIT_SURGEON, diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 05a5407037edc..ce03494737e75 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -96,9 +96,7 @@ screen_loc = ui_language_menu /atom/movable/screen/language_menu/Click() - var/mob/M = usr - var/datum/language_holder/H = M.get_language_holder() - H.open_language_menu(usr) + usr.get_language_holder().open_language_menu(usr) /atom/movable/screen/inventory var/slot_id diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 0e1208e019332..4e2df5017792f 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -20,6 +20,9 @@ var/motd + /// If the configuration is loaded + var/loaded = FALSE + var/static/regex/ic_filter_regex var/static/regex/ooc_filter_regex @@ -60,6 +63,8 @@ LoadProtectedIDs() LoadChatFilter() + loaded = TRUE + if (Master) Master.OnConfigLoad() diff --git a/code/datums/action.dm b/code/datums/action.dm index 53d4359d77f1e..589658362f8d5 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -718,20 +718,6 @@ icon_icon = 'icons/hud/actions/actions_items.dmi' button_icon_state = "jetboot" -/datum/action/language_menu - name = "Language Menu" - desc = "Open the language menu to review your languages, their keys, and select your default language." - button_icon_state = "language_menu" - check_flags = NONE - -/datum/action/language_menu/Trigger() - if(!..()) - return FALSE - if(ismob(owner)) - var/mob/M = owner - var/datum/language_holder/H = M.get_language_holder() - H.open_language_menu(usr) - /datum/action/item_action/wheelys name = "Toggle Wheely-Heel's Wheels" desc = "Pops out or in your wheely-heel's wheels." diff --git a/code/datums/brain_damage/mrat.dm b/code/datums/brain_damage/mrat.dm index d93a5a35372fe..5fb29ddf11797 100644 --- a/code/datums/brain_damage/mrat.dm +++ b/code/datums/brain_damage/mrat.dm @@ -123,7 +123,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/camera/imaginary_friend/mrat) leave = new leave.Grant(src) - grant_all_languages(spoken=FALSE) // they understand all language, but doesn't have to speak that + grant_all_languages(UNDERSTOOD_LANGUAGE) // they understand all language, but doesn't have to speak that // mentor rats default language is set to metalanguage from imaginary friend init // everything mrat says will be understandable to all people diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index e91a588b846ff..c670462932fc8 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -28,13 +28,15 @@ lose_text = "You suddenly remember how languages work." /datum/brain_trauma/severe/aphasia/on_gain() - owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA) - owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA) + owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/aphasia, LANGUAGE_APHASIA) + owner.grant_language(/datum/language/aphasia, source = LANGUAGE_APHASIA) ..() /datum/brain_trauma/severe/aphasia/on_lose() - owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA) - owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA) + if(!QDELING(owner)) + owner.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_APHASIA) + owner.remove_language(/datum/language/aphasia, LANGUAGE_APHASIA) + ..() /datum/brain_trauma/severe/blindness diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 3ba80201c2fa6..d88793bc03b9a 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -51,6 +51,12 @@ switch_personalities() ..() +/datum/brain_trauma/severe/split_personality/on_death() + if(current_controller != OWNER) + switch_personalities(TRUE) + ..() + + /datum/brain_trauma/severe/split_personality/on_lose() if(current_controller != OWNER) //it would be funny to cure a guy only to be left with the other personality, but it seems too cruel switch_personalities(TRUE) @@ -60,7 +66,7 @@ /datum/brain_trauma/severe/split_personality/proc/switch_personalities(reset_to_owner = FALSE) - if(QDELETED(owner) || owner.stat == DEAD || QDELETED(stranger_backseat) || QDELETED(owner_backseat)) + if(QDELETED(owner) || QDELETED(stranger_backseat) || QDELETED(owner_backseat)) return var/mob/living/split_personality/current_backseat diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm index 313b34f13d3b6..f6d5a27821b7b 100644 --- a/code/datums/diseases/advance/symptoms/voice_change.dm +++ b/code/datums/diseases/advance/symptoms/voice_change.dm @@ -70,7 +70,7 @@ Bonus if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure. current_language = pick(subtypesof(/datum/language) - /datum/language/common) H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE) - H.grant_language(current_language, TRUE, TRUE, LANGUAGE_VOICECHANGE) + H.grant_language(current_language, source = LANGUAGE_VOICECHANGE) /datum/symptom/voice_change/End(datum/disease/advance/A) ..() diff --git a/code/datums/dna.dm b/code/datums/dna.dm index cb5f1b1cd4bd9..4313073edb97a 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -344,11 +344,6 @@ dna.species = new_race dna.species.on_species_gain(src, old_species, pref_load) SEND_SIGNAL(src, COMSIG_CARBON_SPECIESCHANGE, new_race) - if(ishuman(src)) - qdel(language_holder) - var/species_holder = initial(mrace.species_language_holder) - language_holder = new species_holder(src) - update_atom_languages() if(icon_update) update_mutations_overlay()// no lizard with human hulk overlay please. diff --git a/code/datums/elements/forced_gravity.dm b/code/datums/elements/forced_gravity.dm index 51a0c270e77fa..2f79d6b41ff4a 100644 --- a/code/datums/elements/forced_gravity.dm +++ b/code/datums/elements/forced_gravity.dm @@ -1,14 +1,20 @@ /datum/element/forced_gravity element_flags = ELEMENT_BESPOKE id_arg_index = 2 + ///the level of gravity we force unto our target var/gravity + ///whether we will override the turf if it forces no gravity var/ignore_space -/datum/element/forced_gravity/Attach(datum/target, gravity=1, ignore_space=FALSE, can_override = FALSE) +/datum/element/forced_gravity/Attach(datum/target, gravity = 1, ignore_space = FALSE, can_override = FALSE) . = ..() if(!isatom(target)) return ELEMENT_INCOMPATIBLE + var/our_ref = REF(src) + if(HAS_TRAIT_FROM(target, TRAIT_FORCED_GRAVITY, our_ref)) + return + src.gravity = gravity src.ignore_space = ignore_space @@ -16,9 +22,9 @@ if(isturf(target)) RegisterSignal(target, COMSIG_TURF_HAS_GRAVITY, PROC_REF(turf_gravity_check), override = can_override) - ADD_TRAIT(target, TRAIT_FORCED_GRAVITY, REF(src)) + ADD_TRAIT(target, TRAIT_FORCED_GRAVITY, our_ref) -/datum/element/forced_gravity/Detach(datum/source, force) +/datum/element/forced_gravity/Detach(datum/source) . = ..() var/static/list/signals_b_gone = list(COMSIG_ATOM_HAS_GRAVITY, COMSIG_TURF_HAS_GRAVITY) UnregisterSignal(source, signals_b_gone) @@ -26,6 +32,7 @@ /datum/element/forced_gravity/proc/gravity_check(datum/source, turf/location, list/gravs) SIGNAL_HANDLER + if(!ignore_space && location.force_no_gravity) return FALSE gravs += gravity diff --git a/code/datums/greyscale/greyscale_configs.dm b/code/datums/greyscale/greyscale_configs.dm index dd93c881bc20a..16ba9efad921d 100644 --- a/code/datums/greyscale/greyscale_configs.dm +++ b/code/datums/greyscale/greyscale_configs.dm @@ -201,6 +201,65 @@ icon_file = 'icons/obj/plushes.dmi' json_config = 'code/datums/greyscale/json_configs/plushie_spacelizard.json' +/datum/greyscale_config/bandana + name = "Bandana" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/bandana.json' + +/datum/greyscale_config/bandana_up + name = "Bandana Up" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/bandana_up.json' + +/datum/greyscale_config/bandana_worn + name = "Worn Bandana" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/bandana_worn.json' + +/datum/greyscale_config/bandana_worn_up + name = "Worn Bandana Up" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/bandana_worn_up.json' + +/datum/greyscale_config/bandstriped + name = "Striped Bandana" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/bandstriped.json' + +/datum/greyscale_config/bandstriped_up + name = "Striped Bandana Up" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/bandstriped_up.json' + +/datum/greyscale_config/bandstriped_worn + name = "Worn Striped Bandana" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/bandstriped_worn.json' + +/datum/greyscale_config/bandstriped_worn_up + name = "Worn Striped Bandana Up" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/bandstriped_worn_up.json' + +/datum/greyscale_config/bandskull + name = "Skull Bandana" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/bandskull.json' + +/datum/greyscale_config/bandskull_up + name = "Skull Bandana Up" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/bandskull_up.json' + +/datum/greyscale_config/bandskull_worn + name = "Worn Skull Bandana" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/bandskull_worn.json' + +/datum/greyscale_config/bandskull_worn_up + name = "Worn Skull Bandana Up" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/bandskull_worn_up.json' /datum/greyscale_config/ctf_standard name = "CTF Standard Vest" icon_file = 'icons/obj/clothing/suits/ctf.dmi' diff --git a/code/datums/greyscale/json_configs/bandana.json b/code/datums/greyscale/json_configs/bandana.json new file mode 100644 index 0000000000000..a56d9b182658a --- /dev/null +++ b/code/datums/greyscale/json_configs/bandana.json @@ -0,0 +1,10 @@ +{ + "bandana": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandana_up.json b/code/datums/greyscale/json_configs/bandana_up.json new file mode 100644 index 0000000000000..393d7b0710f66 --- /dev/null +++ b/code/datums/greyscale/json_configs/bandana_up.json @@ -0,0 +1,10 @@ +{ + "bandana_up": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_up", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandana_worn.json b/code/datums/greyscale/json_configs/bandana_worn.json new file mode 100644 index 0000000000000..bc0e6c002d515 --- /dev/null +++ b/code/datums/greyscale/json_configs/bandana_worn.json @@ -0,0 +1,10 @@ +{ + "bandana_worn": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_worn", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandana_worn_up.json b/code/datums/greyscale/json_configs/bandana_worn_up.json new file mode 100644 index 0000000000000..b5375d5dfa07c --- /dev/null +++ b/code/datums/greyscale/json_configs/bandana_worn_up.json @@ -0,0 +1,10 @@ +{ + "bandana_worn_up": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_worn_up", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandskull.json b/code/datums/greyscale/json_configs/bandskull.json new file mode 100644 index 0000000000000..18344d5d13a19 --- /dev/null +++ b/code/datums/greyscale/json_configs/bandskull.json @@ -0,0 +1,16 @@ +{ + "bandskull": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_skull", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandskull_up.json b/code/datums/greyscale/json_configs/bandskull_up.json new file mode 100644 index 0000000000000..c01dc7bcf4351 --- /dev/null +++ b/code/datums/greyscale/json_configs/bandskull_up.json @@ -0,0 +1,16 @@ +{ + "bandskull_up": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_up", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_skull_up", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandskull_worn.json b/code/datums/greyscale/json_configs/bandskull_worn.json new file mode 100644 index 0000000000000..3d2e34688c94b --- /dev/null +++ b/code/datums/greyscale/json_configs/bandskull_worn.json @@ -0,0 +1,16 @@ +{ + "bandskull_worn": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_worn", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_skull_worn", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandskull_worn_up.json b/code/datums/greyscale/json_configs/bandskull_worn_up.json new file mode 100644 index 0000000000000..be37d2ee2b857 --- /dev/null +++ b/code/datums/greyscale/json_configs/bandskull_worn_up.json @@ -0,0 +1,16 @@ +{ + "bandskull_worn_up": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_worn_up", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_skull_worn_up", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandstriped.json b/code/datums/greyscale/json_configs/bandstriped.json new file mode 100644 index 0000000000000..e31fb50309f0a --- /dev/null +++ b/code/datums/greyscale/json_configs/bandstriped.json @@ -0,0 +1,16 @@ +{ + "bandstriped": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_stripe", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandstriped_up.json b/code/datums/greyscale/json_configs/bandstriped_up.json new file mode 100644 index 0000000000000..da464432cd4a1 --- /dev/null +++ b/code/datums/greyscale/json_configs/bandstriped_up.json @@ -0,0 +1,16 @@ +{ + "bandstriped_up": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_up", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_stripe_up", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandstriped_worn.json b/code/datums/greyscale/json_configs/bandstriped_worn.json new file mode 100644 index 0000000000000..89d729aa4c97b --- /dev/null +++ b/code/datums/greyscale/json_configs/bandstriped_worn.json @@ -0,0 +1,16 @@ +{ + "bandstriped_worn": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_worn", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_stripe_worn", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/bandstriped_worn_up.json b/code/datums/greyscale/json_configs/bandstriped_worn_up.json new file mode 100644 index 0000000000000..7d08ea651ac8b --- /dev/null +++ b/code/datums/greyscale/json_configs/bandstriped_worn_up.json @@ -0,0 +1,16 @@ +{ + "bandstriped_worn_up": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth_worn_up", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "bandana_stripe_worn_up", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/mind.dm b/code/datums/mind.dm index baac761495270..d05a0a0b82427 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1,24 +1,24 @@ -/* Note from Carnie: +/* Note from Carnie: The way datum/mind stuff works has been changed a lot. Minds now represent IC characters rather than following a client around constantly. Guidelines for using minds properly: - - Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living! + - Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living! ghost.mind is however used as a reference to the ghost's corpse - - When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human) - the existing mind of the old mob should be transfered to the new mob like so: + - When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human) + the existing mind of the old mob should be transferred to the new mob like so: mind.transfer_to(new_mob) - - You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you. + - You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you. By setting key or ckey explicitly after transferring the mind with transfer_to you will cause bugs like DCing the player. - - IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you. + - IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you. - - When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting + - When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting a ghost to become a xeno during an event). Simply assign the key or ckey like you've always done. new_mob.key = key @@ -30,22 +30,28 @@ */ /datum/mind + /// Key of the mob var/key - var/name //replaces mob/var/original_name - var/ghostname //replaces name for observers name if set - /// The last living mob this mind occupied - if the player is dead, this is their body. + /// The name linked to this mind + var/name + /// replaces name for observers name if set + var/ghostname + /// Current mob this mind datum is attached to var/mob/living/current - var/active = 0 + /// Is this mind active? + var/active = FALSE var/memory var/list/quirks = list() - var/assigned_role + /// Job datum indicating the mind's role. This should always exist after initialization, as a reference to a singleton. + var/datum/job/assigned_role var/special_role var/list/restricted_roles = list() var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button. var/linglink + /// Martial art on this mind var/datum/martial_art/martial_art var/static/default_martial_art = new/datum/martial_art var/miming = 0 // Mime's vow of silence @@ -61,7 +67,6 @@ var/no_cloning_at_all = FALSE var/datum/mind/enslaved_to //If this mind's master is another mob (i.e. adamantine golems) - var/datum/language_holder/language_holder var/unconvertable = FALSE var/late_joiner = FALSE @@ -97,7 +102,6 @@ /datum/mind/Destroy() SSticker.minds -= src QDEL_LIST(antag_datums) - QDEL_NULL(language_holder) soulOwner = null set_current(null) return ..() @@ -115,11 +119,6 @@ SIGNAL_HANDLER set_current(null) -/datum/mind/proc/get_language_holder() - if(!language_holder) - language_holder = new (src) - return language_holder - /datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0) if(current) // remove ourself from our old body's mind variable current.mind = null @@ -137,9 +136,22 @@ var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list var/mob/living/old_current = current - if(current) - current.transfer_observers_to(new_character, TRUE) //transfer anyone observing the old character to the new one - set_current(new_character) //associate ourself with our new body + if(old_current) + //transfer anyone observing the old character to the new one + old_current.transfer_observers_to(new_character) + + // Offload all mind languages from the old holder to a temp one + var/datum/language_holder/empty/temp_holder = new() + var/datum/language_holder/old_holder = old_current.get_language_holder() + var/datum/language_holder/new_holder = new_character.get_language_holder() + // Off load mind languages to the temp holder momentarily + new_holder.transfer_mind_languages(temp_holder) + // Transfer the old holder's mind languages to the new holder + old_holder.transfer_mind_languages(new_holder) + // And finally transfer the temp holder's mind languages back to the old holder + temp_holder.transfer_mind_languages(old_holder) + + set_current(new_character) //associate ourself with our new body new_character.mind = src //and associate our new body with ourself for(var/datum/quirk/T as() in quirks) //Retarget all traits this mind has @@ -151,13 +163,13 @@ if(iscarbon(new_character)) var/mob/living/carbon/C = new_character C.last_mind = src - transfer_antag_huds(hud_to_transfer) //inherit the antag HUD + transfer_antag_huds(hud_to_transfer) //inherit the antag HUD transfer_actions(new_character) transfer_martial_arts(new_character) RegisterSignal(new_character, COMSIG_MOB_DEATH, PROC_REF(set_death_time)) if(active || force_key_move) new_character.key = key //now transfer the key to link the client to our new body - current.update_atom_languages() + SEND_SIGNAL(src, COMSIG_MIND_TRANSFER_TO, old_current, new_character) // Update SSD indicators if(isliving(old_current)) diff --git a/code/datums/mocking/client.dm b/code/datums/mocking/client.dm index 05bfd5eab0cc6..8aa24279176a3 100644 --- a/code/datums/mocking/client.dm +++ b/code/datums/mocking/client.dm @@ -6,5 +6,7 @@ /// The view of the client, similar to /client/var/view var/view = "17x15" + var/typing_indicators + /datum/client_interface/proc/should_include_for_role(banning_key = BAN_ROLE_ALL_ANTAGONISTS, role_preference_key = null, poll_ignore_key = null, req_hours = 0, feedback = FALSE) return TRUE diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 4bd9acdc358d9..7ebdb959fcf4c 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -237,12 +237,12 @@ /datum/mutation/stoner/on_acquiring(mob/living/carbon/owner) ..() - owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER) + owner.grant_language(/datum/language/beachbum, source = LANGUAGE_STONER) owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER) /datum/mutation/stoner/on_losing(mob/living/carbon/owner) ..() - owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER) + owner.remove_language(/datum/language/beachbum, source = LANGUAGE_STONER) owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER) /datum/mutation/medieval diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 75f70585a4c3d..fc585e65218a9 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -1048,11 +1048,11 @@ . = ..() to_chat(owner, "Alert: Vocal cords are malfunctioning.") owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/uncommon, LANGUAGE_EMP) - owner.grant_language(/datum/language/uncommon, FALSE, TRUE, LANGUAGE_EMP) + owner.grant_language(/datum/language/uncommon, SPOKEN_LANGUAGE, source = LANGUAGE_EMP) /datum/status_effect/spanish/on_remove() owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_EMP) - owner.remove_language(/datum/language/uncommon, TRUE, TRUE, LANGUAGE_EMP) + owner.remove_language(/datum/language/uncommon, source = LANGUAGE_EMP) to_chat(owner, "Alert: Vocal cords restored to normal function.") return ..() diff --git a/code/datums/traits/positive_quirk.dm b/code/datums/traits/positive_quirk.dm index d1bc2dd5d16e7..efc0249eba8c2 100644 --- a/code/datums/traits/positive_quirk.dm +++ b/code/datums/traits/positive_quirk.dm @@ -125,11 +125,11 @@ var/datum/language/known_language /datum/quirk/multilingual/proc/set_up_language() - var/datum/language_holder/LH = quirk_holder.get_language_holder() + var/datum/language_holder/LH = quirk_target.get_language_holder() if(quirk_holder.assigned_role == JOB_NAME_CURATOR) return var/obj/item/organ/tongue/T = quirk_target.getorganslot(ORGAN_SLOT_TONGUE) - var/list/languages_possible = T.languages_possible + var/list/languages_possible = T.get_possible_languages() languages_possible = languages_possible - typecacheof(/datum/language/codespeak) - typecacheof(/datum/language/narsie) - typecacheof(/datum/language/ratvar) languages_possible = languages_possible - LH.understood_languages languages_possible = languages_possible - LH.spoken_languages @@ -142,14 +142,14 @@ known_language = read_choice_preference(/datum/preference/choiced/quirk/multilingual_language) if(!known_language) // default to random set_up_language() - var/datum/language_holder/LH = quirk_holder.get_language_holder() - LH.grant_language(known_language, TRUE, TRUE, LANGUAGE_MULTILINGUAL) + var/datum/language_holder/LH = quirk_target.get_language_holder() + LH.grant_language(known_language, source = LANGUAGE_MULTILINGUAL) /datum/quirk/multilingual/remove() if(!known_language) return - var/datum/language_holder/LH = quirk_holder.get_language_holder() - LH.remove_language(known_language, TRUE, TRUE, LANGUAGE_MULTILINGUAL) + var/datum/language_holder/LH = quirk_target.get_language_holder() + LH.remove_language(known_language, source = LANGUAGE_MULTILINGUAL) /datum/quirk/night_vision name = "Night Vision" diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm index 702eb9b2769eb..6abf5df6716cc 100644 --- a/code/datums/wires/explosive.dm +++ b/code/datums/wires/explosive.dm @@ -56,6 +56,7 @@ /datum/wires/explosive/c4 holder_type = /obj/item/grenade/plastic/c4 + duds_number = 1 randomize = TRUE //Same behaviour since no wire actually disarms it /datum/wires/explosive/c4/interactable(mob/user) diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm index 865e96087e51d..29d5a11124257 100644 --- a/code/game/area/Space_Station_13_areas.dm +++ b/code/game/area/Space_Station_13_areas.dm @@ -29,30 +29,32 @@ NOTE: there are two lists of areas in the end of this file: centcom and station power_light = FALSE power_equip = FALSE power_environ = FALSE - area_flags = UNIQUE_AREA + area_flags = UNIQUE_AREA | NO_GRAVITY outdoors = TRUE ambience_index = null ambient_music_index = AMBIENCE_SPACE ambient_buzz = null //Space is deafeningly quiet sound_environment = SOUND_AREA_SPACE fullbright_type = FULLBRIGHT_STARLIGHT + default_gravity = ZERO_GRAVITY /area/space/nearstation icon_state = "space_near" dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT + default_gravity = ZERO_GRAVITY /area/start name = "start area" icon_state = "start" requires_power = FALSE dynamic_lighting = DYNAMIC_LIGHTING_DISABLED - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambience_index = null ambient_buzz = null /area/testroom requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY name = "Test Room" icon_state = "storage" @@ -62,7 +64,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Asteroid" icon_state = "asteroid" always_unpowered = TRUE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambience_index = AMBIENCE_MINING sound_environment = SOUND_AREA_ASTEROID area_flags = UNIQUE_AREA @@ -965,10 +967,11 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/solar //requires_power = FALSE /* YOU WISH FOR INFINITE POWER YOU STINGY CHEAPO, TOO BAD */ dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT - area_flags = UNIQUE_AREA + area_flags = UNIQUE_AREA | NO_GRAVITY flags_1 = NONE ambience_index = AMBIENCE_ENGI sound_environment = SOUND_AREA_SPACE + default_gravity = ZERO_GRAVITY /area/solar/fore name = "Fore Solar Array" @@ -1533,11 +1536,15 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/science/test_area name = "Toxins Test Area" - area_flags = BLOBS_ALLOWED | UNIQUE_AREA + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | NO_GRAVITY icon_state = "tox_test" lights_always_start_on = TRUE always_unpowered = TRUE +/area/science/test_area/planet + name = "Planetary Toxins Test Area" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA + /area/science/mixing name = "Toxins Mixing Lab" icon_state = "tox_mix" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 299f19b3cf78f..1a2c83bf6703d 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -60,7 +60,8 @@ var/power_light = TRUE var/power_environ = TRUE - var/has_gravity = FALSE + /// The default gravity for the area + var/default_gravity = ZERO_GRAVITY ///Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter) var/teleport_restriction = TELEPORT_ALLOW_ALL diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm index bb8c5bfd524f2..d98a686e18c25 100644 --- a/code/game/area/areas/away_content.dm +++ b/code/game/area/areas/away_content.dm @@ -7,7 +7,7 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30" /area/awaymission name = "Strange Location" icon_state = "away" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambience_index = AMBIENCE_AWAY sound_environment = SOUND_ENVIRONMENT_ROOM airlock_hack_difficulty = AIRLOCK_WIRE_SECURITY_ELITE @@ -17,13 +17,13 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30" icon_state = "away" dynamic_lighting = DYNAMIC_LIGHTING_DISABLED requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg','sound/ambience/ambiodd.ogg','sound/ambience/ambinice.ogg') /area/awaymission/errorroom name = "Super Secret Room" dynamic_lighting = DYNAMIC_LIGHTING_DISABLED - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY /area/awaymission/vr name = "Virtual Reality" diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm index 6ad046ad0b340..6c23f443545aa 100644 --- a/code/game/area/areas/centcom.dm +++ b/code/game/area/areas/centcom.dm @@ -10,7 +10,7 @@ icon_state = "centcom" dynamic_lighting = DYNAMIC_LIGHTING_ENABLED requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_NONE area_flags = VALID_TERRITORY | UNIQUE_AREA flags_1 = NONE @@ -86,7 +86,7 @@ icon_state = "yellow" dynamic_lighting = DYNAMIC_LIGHTING_ENABLED requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY flags_1 = NONE camera_networks = list(CAMERA_NETWORK_THUNDERDOME) @@ -125,7 +125,7 @@ icon_state = "yellow" dynamic_lighting = DYNAMIC_LIGHTING_ENABLED requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_WIZARD area_flags = VALID_TERRITORY | UNIQUE_AREA flags_1 = NONE @@ -139,7 +139,7 @@ requires_power = FALSE teleport_restriction = TELEPORT_ALLOW_ABDUCTORS area_flags = VALID_TERRITORY | UNIQUE_AREA - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY flags_1 = NONE network_root_id = "ALIENS" airlock_hack_difficulty = AIRLOCK_WIRE_SECURITY_MAXIMUM @@ -149,7 +149,7 @@ name = "Syndicate Mothership" icon_state = "syndie-ship" requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_NONE area_flags = VALID_TERRITORY | UNIQUE_AREA flags_1 = NONE @@ -175,7 +175,7 @@ icon_state = "yellow" requires_power = FALSE dynamic_lighting = DYNAMIC_LIGHTING_DISABLED - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY airlock_hack_difficulty = AIRLOCK_WIRE_SECURITY_ELITE /area/ctf/control_room @@ -212,7 +212,7 @@ icon_state = "yellow" requires_power = FALSE dynamic_lighting = DYNAMIC_LIGHTING_DISABLED - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_CLOCKWORK area_flags = VALID_TERRITORY | UNIQUE_AREA | HIDDEN_AREA ambience_index = AMBIENCE_REEBE diff --git a/code/game/area/areas/iceland.dm b/code/game/area/areas/iceland.dm index cf492f3dd5590..86bf32be0f1bd 100644 --- a/code/game/area/areas/iceland.dm +++ b/code/game/area/areas/iceland.dm @@ -11,7 +11,7 @@ flags_1 = NONE min_ambience_cooldown = 70 SECONDS max_ambience_cooldown = 220 SECONDS - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambience_index = AMBIENCE_SPOOKY sound_environment = SOUND_AREA_LARGE_SOFTFLOOR area_flags = UNIQUE_AREA | FLORA_ALLOWED diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm index 92abb4db4cbf7..f0b8dc5932ca5 100644 --- a/code/game/area/areas/mining.dm +++ b/code/game/area/areas/mining.dm @@ -2,7 +2,7 @@ /area/mine icon_state = "mining" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY lighting_colour_tube = "#ffe8d2" lighting_colour_bulb = "#ffdcb7" area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED @@ -88,7 +88,7 @@ /area/lavaland icon_state = "mining" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY flags_1 = NONE sound_environment = SOUND_AREA_LAVALAND ambient_buzz = 'sound/ambience/magma.ogg' diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index 2d41e3ae6d34f..7b1ac81547593 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -3,7 +3,7 @@ /area/ruin name = "\improper Unexplored Location" icon_state = "away" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY area_flags = HIDDEN_AREA | BLOBS_ALLOWED dynamic_lighting = DYNAMIC_LIGHTING_ENABLED ambience_index = AMBIENCE_RUINS @@ -14,7 +14,7 @@ always_unpowered = FALSE /area/ruin/unpowered/no_grav - has_gravity = FALSE + default_gravity = ZERO_GRAVITY /area/ruin/powered requires_power = FALSE diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm index 03734228494fa..a2dfbf0de14ef 100644 --- a/code/game/area/areas/ruins/space.dm +++ b/code/game/area/areas/ruins/space.dm @@ -1,11 +1,11 @@ //Space Ruin Parents /area/ruin/space - has_gravity = FALSE + default_gravity = ZERO_GRAVITY area_flags = UNIQUE_AREA /area/ruin/space/has_grav - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY /area/ruin/space/has_grav/powered requires_power = FALSE @@ -228,12 +228,12 @@ /area/ruin/space/has_grav/ancientstation/space name = "Exposed To Space" icon_state = "teleporter" - has_gravity = FALSE + default_gravity = ZERO_GRAVITY /area/ruin/space/has_grav/ancientstation/atmo name = "Beta Station Atmospherics" icon_state = "red" - has_gravity = FALSE + default_gravity = ZERO_GRAVITY ambience_index = AMBIENCE_ENGI /area/ruin/space/has_grav/ancientstation/betanorth @@ -359,12 +359,12 @@ /area/ruin/space/djstation name = "Ruskie DJ Station" icon_state = "DJ" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY /area/ruin/space/djstation/solars name = "DJ Station Solars" icon_state = "DJ" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY //ABANDONED TELEPORTER diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 1c758ec62d719..f98360e871bc0 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -6,7 +6,7 @@ name = "Shuttle" requires_power = FALSE dynamic_lighting = DYNAMIC_LIGHTING_ENABLED - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY always_unpowered = FALSE // Loading the same shuttle map at a different time will produce distinct area instances. area_flags = NONE diff --git a/code/game/atoms.dm b/code/game/atoms.dm index e77aa3d204422..a4c74ad6e577f 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1925,6 +1925,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom) * Gravity situations: * * No gravity if you're not in a turf * * No gravity if this atom is in is a space turf + * * No gravity if the area has NO_GRAVITY flag (space, ordnance bomb site, nearstation, solars) * * Gravity if the area it's in always has gravity * * Gravity if there's a gravity generator on the z level * * Gravity if the Z level has an SSMappingTrait for ZTRAIT_GRAVITY @@ -1952,7 +1953,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom) var/area/turf_area = gravity_turf.loc - return !gravity_turf.force_no_gravity && (SSmapping.gravity_by_z_level[gravity_turf.z] || turf_area.has_gravity) + return (!gravity_turf.force_no_gravity && !(turf_area.area_flags & NO_GRAVITY)) && (SSmapping.gravity_by_z_level[gravity_turf.z] || turf_area.default_gravity) /* * Called when something made out of plasma is exposed to high temperatures. diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 084427779275b..ad49981527d67 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -14,8 +14,10 @@ var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported var/throw_range = 7 var/mob/pulledby = null + /// What language holder type to init as var/initial_language_holder = /datum/language_holder - var/datum/language_holder/language_holder // Mindless mobs and objects need language too, some times. Mind holder takes prescedence. + /// Holds all languages this mob can speak and understand + VAR_PRIVATE/datum/language_holder/language_holder var/verb_say = "says" var/verb_ask = "asks" @@ -684,23 +686,23 @@ //Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting //Mobs should return 1 if they should be able to move of their own volition, see client/Move() in mob_movement.dm //movement_dir == 0 when stopping or any dir when trying to move -/atom/movable/proc/Process_Spacemove(movement_dir = 0) +/atom/movable/proc/Process_Spacemove(movement_dir = FALSE) if(has_gravity(src)) - return 1 + return TRUE - if(pulledby) - return 1 + if(pulledby && (pulledby.pulledby != src || moving_from_pull)) + return TRUE if(throwing) - return 1 + return TRUE if(!isturf(loc)) - return 1 + return TRUE if(locate(/obj/structure/lattice) in range(1, get_turf(src))) //Not realistic but makes pushing things in space easier - return 1 + return TRUE - return 0 + return FALSE /// Only moves the object if it's under no gravity @@ -1025,84 +1027,80 @@ */ /// Gets or creates the relevant language holder. For mindless atoms, gets the local one. For atom with mind, gets the mind one. -/atom/movable/proc/get_language_holder(get_minds = TRUE) +/atom/movable/proc/get_language_holder() + RETURN_TYPE(/datum/language_holder) + if(QDELING(src)) + CRASH("get_language_holder() called on a QDELing atom, \ + this will try to re-instantiate the language holder that's about to be deleted, which is bad.") + if(!language_holder) language_holder = new initial_language_holder(src) return language_holder /// Grants the supplied language and sets omnitongue true. -/atom/movable/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ATOM) - var/datum/language_holder/LH = get_language_holder() - return LH.grant_language(language, understood, spoken, source) +/atom/movable/proc/grant_language(language, language_flags = ALL, source = LANGUAGE_ATOM) + return get_language_holder().grant_language(language, language_flags, source) /// Grants every language. -/atom/movable/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND) - var/datum/language_holder/LH = get_language_holder() - return LH.grant_all_languages(understood, spoken, grant_omnitongue, source) +/atom/movable/proc/grant_all_languages(language_flags = ALL, grant_omnitongue = TRUE, source = LANGUAGE_MIND) + return get_language_holder().grant_all_languages(language_flags, grant_omnitongue, source) /// Removes a single language. -/atom/movable/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL) - var/datum/language_holder/LH = get_language_holder() - return LH.remove_language(language, understood, spoken, source) +/atom/movable/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL) + return get_language_holder().remove_language(language, language_flags, source) /// Removes every language and sets omnitongue false. /atom/movable/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE) - var/datum/language_holder/LH = get_language_holder() - return LH.remove_all_languages(source, remove_omnitongue) + return get_language_holder().remove_all_languages(source, remove_omnitongue) /// Adds a language to the blocked language list. Use this over remove_language in cases where you will give languages back later. /atom/movable/proc/add_blocked_language(language, source = LANGUAGE_ATOM) - var/datum/language_holder/LH = get_language_holder() - return LH.add_blocked_language(language, source) + return get_language_holder().add_blocked_language(language, source) /// Removes a language from the blocked language list. /atom/movable/proc/remove_blocked_language(language, source = LANGUAGE_ATOM) - var/datum/language_holder/LH = get_language_holder() - return LH.remove_blocked_language(language, source) + return get_language_holder().remove_blocked_language(language, source) /// Checks if atom has the language. If spoken is true, only checks if atom can speak the language. -/atom/movable/proc/has_language(language, spoken = FALSE) - var/datum/language_holder/LH = get_language_holder() - return LH.has_language(language, spoken) +/atom/movable/proc/has_language(language, flags_to_check) + return get_language_holder().has_language(language, flags_to_check) /// Checks if atom can speak the language. /atom/movable/proc/can_speak_language(language) - var/datum/language_holder/LH = get_language_holder() - return LH.can_speak_language(language) + return get_language_holder().can_speak_language(language) /// Returns the result of tongue specific limitations on spoken languages. -/atom/movable/proc/could_speak_language(language) +/atom/movable/proc/could_speak_language(datum/language/language_path) return TRUE /// Returns selected language, if it can be spoken, or finds, sets and returns a new selected language if possible. /atom/movable/proc/get_selected_language() - var/datum/language_holder/LH = get_language_holder() - return LH.get_selected_language() + return get_language_holder().get_selected_language() /// Gets a random understood language, useful for hallucinations and such. /atom/movable/proc/get_random_understood_language() - var/datum/language_holder/LH = get_language_holder() - return LH.get_random_understood_language() + return get_language_holder().get_random_understood_language() /// Gets a random spoken language, useful for forced speech and such. /atom/movable/proc/get_random_spoken_language() - var/datum/language_holder/LH = get_language_holder() - return LH.get_random_spoken_language() + return get_language_holder().get_random_spoken_language() /// Copies all languages into the supplied atom/language holder. Source should be overridden when you /// do not want the language overwritten by later atom updates or want to avoid blocked languages. -/atom/movable/proc/copy_languages(from_holder, source_override=FALSE, spoken=TRUE, understood=TRUE, blocked=TRUE) - if(isatom(from_holder)) +/atom/movable/proc/copy_languages(datum/language_holder/from_holder, source_override=FALSE, spoken=TRUE, understood=TRUE, blocked=TRUE) + if(ismovable(from_holder)) var/atom/movable/thing = from_holder from_holder = thing.get_language_holder() - var/datum/language_holder/LH = get_language_holder() - return LH.copy_languages(from_holder, source_override, spoken, understood, blocked) - -/// Empties out the atom specific languages and updates them according to the current atoms language holder. -/// As a side effect, it also creates missing language holders in the process. -/atom/movable/proc/update_atom_languages() - var/datum/language_holder/LH = get_language_holder() - return LH.update_atom_languages(src) + + return get_language_holder().copy_languages(from_holder, source_override, spoken, understood, blocked) + +/// Sets the passed path as the active language +/// Returns the currently selected language if successful, if the language was not valid, returns null +/atom/movable/proc/set_active_language(language_path) + var/datum/language_holder/our_holder = get_language_holder() + our_holder.selected_language = language_path + + return our_holder.get_selected_language() // verifies its validity, returns it if successful. /* End language procs */ diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm index 0c7162fe13824..03847bff295ef 100644 --- a/code/game/gamemodes/clown_ops/clown_weapons.dm +++ b/code/game/gamemodes/clown_ops/clown_weapons.dm @@ -97,7 +97,7 @@ hitsound = null attack_verb_on = list("slips") clumsy_check = FALSE - sharpness = IS_BLUNT + sharpness = BLUNT sword_color = "yellow" heat = 0 light_color = "#ffff00" diff --git a/code/game/machinery/telecomms/machines/message_server.dm b/code/game/machinery/telecomms/machines/message_server.dm index 0bad60e62f52a..dc614e8553cbf 100644 --- a/code/game/machinery/telecomms/machines/message_server.dm +++ b/code/game/machinery/telecomms/machines/message_server.dm @@ -71,7 +71,7 @@ icon_state = "blackcube" lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' righthand_file = 'icons/mob/inhands/items_righthand.dmi' - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_LARGE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF #define MESSAGE_SERVER_FUNCTIONING_MESSAGE "This is an automated message. The messaging system is functioning correctly." diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 2aa9564b3f17f..eb582cc0defdd 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -81,6 +81,16 @@ GLOBAL_LIST_INIT(dye_registry, list( DYE_SYNDICATE = /obj/item/clothing/under/syndicate, DYE_CENTCOM = /obj/item/clothing/under/rank/centcom/commander ), + DYE_REGISTRY_BANDANA = list( + DYE_RED = /obj/item/clothing/mask/bandana/red, + DYE_ORANGE = /obj/item/clothing/mask/bandana/orange, + DYE_YELLOW = /obj/item/clothing/mask/bandana/gold, + DYE_GREEN = /obj/item/clothing/mask/bandana/green, + DYE_BLUE = /obj/item/clothing/mask/bandana/blue, + DYE_PURPLE = /obj/item/clothing/mask/bandana/purple, + DYE_BLACK = /obj/item/clothing/mask/bandana/black, + DYE_WHITE = /obj/item/clothing/mask/bandana/white + ), DYE_REGISTRY_SNEAKERS = list( DYE_RED = /obj/item/clothing/shoes/sneakers/red, DYE_ORANGE = /obj/item/clothing/shoes/sneakers/orange, diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index efe12677ab434..86b723c7d20e0 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -36,6 +36,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/inhand_x_dimension = 32 /// y dimension of the inhand sprite var/inhand_y_dimension = 32 + /// Worn overlay will be shifted by this along y axis + var/worn_y_offset = 0 //Not on /clothing because for some reason any /obj/item can technically be "worn" with enough fuckery. /// If this is set, update_icons() will find on mob (WORN, NOT INHANDS) states in this file instead, primary use: badminnery/events @@ -156,8 +158,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/flags_cover = 0 /// Used to define how hot it's flame will be when lit. Used it igniters, lighters, flares, candles, etc. var/heat = 0 - /// IS_BLUNT | IS_SHARP | IS_SHARP_ACCURATE Used to define whether the item is sharp or blunt. IS_SHARP is used if the item is supposed to be able to cut open things. See _DEFINES/combat.dm - var/sharpness = IS_BLUNT + /// BLUNT | SHARP | SHARP_DISMEMBER | SHARP_DISMEMBER_EASY Used to define whether the item is sharp or blunt. SHARP is used if the item is supposed to be able to cut open things. See _DEFINES/combat.dm + var/sharpness = BLUNT //this multiplies an attacks force for secondary effects like attacking blocking implements, dismemberment, and knocking a target silly var/attack_weight = 1 diff --git a/code/game/objects/items/chainsaw.dm b/code/game/objects/items/chainsaw.dm index cc09f01d685c7..435f1c3d5367f 100644 --- a/code/game/objects/items/chainsaw.dm +++ b/code/game/objects/items/chainsaw.dm @@ -20,7 +20,7 @@ attack_verb_continuous = list("saws", "tears", "lacerates", "cuts", "chops", "dices") attack_verb_simple = list("saw", "tear", "lacerate", "cut", "chop", "dice") hitsound = "swing_hit" - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_DEEP_WOUND actions_types = list(/datum/action/item_action/startchainsaw) var/on = FALSE diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index e91135a8c7db1..224a384e86fb4 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -277,7 +277,7 @@ attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE tool_behaviour = TOOL_SCALPEL else @@ -288,7 +288,7 @@ attack_verb_continuous = list("stubs", "pokes") attack_verb_simple = list("stub", "poke") hitsound = 'sound/weapons/genhit.ogg' - sharpness = IS_BLUNT + sharpness = BLUNT bleed_force = 0 tool_behaviour = null diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index 2100e9a95c919..78325763604a4 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -359,8 +359,8 @@ . = ..() for(var/each in traits_to_give) ADD_TRAIT(user, each, "debug") - user.grant_all_languages(TRUE, TRUE, TRUE, "debug") - user.grant_language(/datum/language/metalanguage, TRUE, TRUE, "debug") + grant_all_languages(source = "debug") + user.grant_language(/datum/language/metalanguage, source = "debug") var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] hud.add_hud_to(user) diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 0fcd562b8a1cb..cb56d0baa3997 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -76,7 +76,7 @@ if(user.dna.check_mutation(HULK)) to_chat(user, "You lack the grace to wield this!") return COMPONENT_TWOHANDED_BLOCK_WIELD - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force = BLEED_DEEP_WOUND w_class = w_class_on hitsound = 'sound/weapons/blade1.ogg' diff --git a/code/game/objects/items/fireaxe.dm b/code/game/objects/items/fireaxe.dm index 081497c40a02c..6065ccb0e7db7 100644 --- a/code/game/objects/items/fireaxe.dm +++ b/code/game/objects/items/fireaxe.dm @@ -15,7 +15,7 @@ attack_verb_continuous = list("attacks", "chops", "cleaves", "tears", "lacerates", "cuts") attack_verb_simple = list("attack", "chop", "cleave", "tear", "lacerate", "cut") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT max_integrity = 200 armor_type = /datum/armor/item_fireaxe diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 718e93d430268..3575bc0699e0f 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -333,7 +333,7 @@ block_flags = BLOCKING_NASTY | BLOCKING_ACTIVE block_level = 1 block_power = 30 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") @@ -456,7 +456,7 @@ block_power = 15 block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY slot_flags = ITEM_SLOT_BACK - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT attack_verb_continuous = list("chops", "slices", "cuts", "reaps") attack_verb_simple = list("chop", "slice", "cut", "reap") @@ -524,8 +524,7 @@ S.fully_replace_character_name(null, "The spirit of [name]") S.status_flags |= GODMODE S.copy_languages(user, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the user. - S.update_atom_languages() - grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue + S.get_language_holder().omnitongue = TRUE //Grants omnitongue var/input = sanitize_name(stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN)) if(src && input) @@ -579,7 +578,7 @@ righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' w_class = WEIGHT_CLASS_HUGE item_flags = ABSTRACT | ISWEAPON - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT attack_verb_continuous = list("saws", "tears", "lacerates", "cuts", "chops", "dices") attack_verb_simple = list("saw", "tear", "lacerate", "cut", "chop", "dice") @@ -605,7 +604,7 @@ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' worn_icon_state = "render" hitsound = 'sound/items/bikehorn.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") @@ -659,7 +658,7 @@ throw_speed = 4 throw_range = 7 throwforce = 30 - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT attack_verb_continuous = list("enlightens", "redpills") attack_verb_simple = list("enlighten", "redpill") @@ -675,7 +674,7 @@ slot_flags = null item_flags = ABSTRACT | ISWEAPON w_class = WEIGHT_CLASS_HUGE - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT /obj/item/nullrod/armblade/Initialize(mapload) @@ -718,7 +717,7 @@ force = 14 block_power = 40 slot_flags = ITEM_SLOT_BACK - sharpness = IS_BLUNT + sharpness = BLUNT hitsound = "swing_hit" attack_verb_continuous = list("smashes", "slams", "whacks", "thwacks") attack_verb_simple = list("smash", "slam", "whack", "thwack") @@ -737,7 +736,7 @@ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_HUGE - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT slot_flags = null hitsound = 'sound/weapons/bladeslice.ogg' @@ -773,7 +772,7 @@ attack_verb_continuous = list("pokes", "impales", "pierces", "jabs") attack_verb_simple = list("poke", "impale", "pierce", "jab") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT /obj/item/nullrod/egyptian @@ -816,7 +815,7 @@ icon = 'icons/obj/clockwork_objects.dmi' slot_flags = ITEM_SLOT_BELT armour_penetration = 10 - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP bleed_force = BLEED_CUT w_class = WEIGHT_CLASS_BULKY attack_verb_continuous = list("stabs", "pokes", "slashes", "clocks") @@ -836,7 +835,7 @@ throw_speed = 3 throw_range = 6 tool_behaviour = TOOL_KNIFE - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP w_class = WEIGHT_CLASS_SMALL /obj/item/nullrod/rainbow_knife/afterattack(atom/O, mob/user, proximity) diff --git a/code/game/objects/items/knives.dm b/code/game/objects/items/knives.dm index e32c8392d430b..876717738cd7c 100644 --- a/code/game/objects/items/knives.dm +++ b/code/game/objects/items/knives.dm @@ -18,7 +18,7 @@ custom_materials = list(/datum/material/iron=12000) attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP bleed_force = BLEED_CUT armor_type = /datum/armor/item_knife var/bayonet = FALSE //Can this be attached to a gun? @@ -76,6 +76,7 @@ attack_verb_simple = list("cleave", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") w_class = WEIGHT_CLASS_NORMAL custom_price = 60 + sharpness = SHARP_DISMEMBER //This is a big boy knife /obj/item/knife/hunting name = "hunting knife" diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index fba93468ceda5..0ac6ea85e83c9 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -106,7 +106,7 @@ attack_verb_off = list("taps", "pokes") throw_speed = 3 throw_range = 5 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force_on = BLEED_DEEP_WOUND embedding = list("embed_chance" = 200, "armour_block" = 60, "max_pain_mult" = 15) armour_penetration = 35 @@ -139,7 +139,7 @@ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' sword_color = null //stops icon from breaking when turned on. w_class = WEIGHT_CLASS_NORMAL - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force_on = BLEED_DEEP_WOUND light_color = "#40ceff" tool_behaviour = TOOL_SAW @@ -170,7 +170,7 @@ sword_color = null //stops icon from breaking when turned on. hitcost = 75 //Costs more than a standard cyborg esword w_class = WEIGHT_CLASS_NORMAL - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force_on = BLEED_DEEP_WOUND light_color = "#40ceff" tool_behaviour = TOOL_SAW @@ -268,7 +268,7 @@ throw_range = 1 w_class = WEIGHT_CLASS_BULKY//So you can't hide it in your pocket or some such. var/datum/effect_system/spark_spread/spark_system - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force_on = BLEED_DEEP_WOUND //Most of the other special functions are handled in their own files. aka special snowflake code so kewl diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index b401ff08a3600..cc021a15a5600 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -46,7 +46,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT /obj/item/melee/synthetic_arm_blade/Initialize(mapload) @@ -70,7 +70,7 @@ throwforce = 10 w_class = WEIGHT_CLASS_BULKY armour_penetration = 75 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT attack_verb_continuous = list("slashes", "cuts") attack_verb_simple = list("slash", "cut") diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm index a556f326681e2..0177c4b2187ae 100644 --- a/code/game/objects/items/melee/transforming.dm +++ b/code/game/objects/items/melee/transforming.dm @@ -1,5 +1,5 @@ /obj/item/melee/transforming - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = 0 var/active = FALSE var/force_on = 30 //force when active diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index 25dc5d1e95467..20e9a34d9feab 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -125,6 +125,6 @@ throw_speed = 4 attack_verb_continuous = list("mops", "stabs", "shanks", "jousts") attack_verb_simple = list("mop", "stab", "shank", "joust") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE embedding = list("armour_block" = 40) diff --git a/code/game/objects/items/pitchfork.dm b/code/game/objects/items/pitchfork.dm index a01c3933fd895..16c22402f9fc0 100644 --- a/code/game/objects/items/pitchfork.dm +++ b/code/game/objects/items/pitchfork.dm @@ -13,7 +13,7 @@ attack_verb_continuous = list("attacks", "impales", "pierces") attack_verb_simple = list("attack", "impale", "pierce") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT max_integrity = 200 armor_type = /datum/armor/item_pitchfork diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm index 3f7c68e07e163..6437ba060288c 100644 --- a/code/game/objects/items/sharpener.dm +++ b/code/game/objects/items/sharpener.dm @@ -8,7 +8,6 @@ var/increment = 4 var/max = 30 var/prefix = "sharpened" - var/requires_sharpness = 1 /obj/item/sharpener/attackby(obj/item/I, mob/user, params) @@ -18,7 +17,7 @@ if(I.force >= max || I.throwforce >= max)//no esword sharpening to_chat(user, "[I] is much too powerful to sharpen further!") return - if(requires_sharpness && !I.is_sharp()) + if(!I.is_sharp()) to_chat(user, "You can only sharpen items that are already sharp, such as knives!") return if(istype(I, /obj/item/melee/transforming/energy)) @@ -39,7 +38,6 @@ I.force = clamp(I.force + increment, 0, max) user.visible_message("[user] sharpens [I] with [src]!", "You sharpen [I], making it much more deadly than before.") playsound(src, 'sound/items/unsheath.ogg', 25, 1) - I.sharpness = IS_SHARP_ACCURATE I.bleed_force *= 1.1 I.throwforce = clamp(I.throwforce + increment, 0, max) I.name = "[prefix] [I.name]" @@ -54,4 +52,3 @@ increment = 200 max = 200 prefix = "super-sharpened" - requires_sharpness = 0 diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 0b2fb887db7aa..61117ee21f763 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -104,7 +104,7 @@ transparent = TRUE /obj/item/shield/riot/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/melee) && W.sharpness == IS_BLUNT) + if(istype(W, /obj/item/melee) && W.sharpness == BLUNT) if(cooldown < world.time - 25) user.visible_message("[user] bashes [src] with [W]!") playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index a75d2f6045b13..671d6bda2d008 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -18,7 +18,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "lacerates", "gores") attack_verb_simple = list("attack", "poke", "jab", "tear", "lacerate", "gore") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT max_integrity = 200 armor_type = /datum/armor/item_spear @@ -201,7 +201,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/spear/explosive) hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "lacerates", "gores") attack_verb_simple = list("attack", "poke", "jab", "tear", "lacerate", "gore") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT /obj/item/spear/bamboospear/ComponentInitialize() diff --git a/code/game/objects/items/stacks/sheets/mineral/glass.dm b/code/game/objects/items/stacks/sheets/mineral/glass.dm index 31f1fcac6b563..5ddfcea1fb57c 100644 --- a/code/game/objects/items/stacks/sheets/mineral/glass.dm +++ b/code/game/objects/items/stacks/sheets/mineral/glass.dm @@ -248,7 +248,7 @@ resistance_flags = ACID_PROOF armor_type = /datum/armor/item_shard max_integrity = 40 - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE var/icon_prefix embedding = list("embed_chance" = 65) diff --git a/code/game/objects/items/stacks/sheets/organic/cloths_recipes.dm b/code/game/objects/items/stacks/sheets/organic/cloths_recipes.dm index 1987c3979daae..2f08e99675fc6 100644 --- a/code/game/objects/items/stacks/sheets/organic/cloths_recipes.dm +++ b/code/game/objects/items/stacks/sheets/organic/cloths_recipes.dm @@ -4,7 +4,8 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, time = 4 SECONDS), \ new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, time = 4 SECONDS), \ new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, time = 4 SECONDS), \ - new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, time = 4 SECONDS), \ + new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1), \ + new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2), \ new/datum/stack_recipe("white hoodie", /obj/item/clothing/suit/hooded/hoodie, 5, time = 4 SECONDS), \ null, \ new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, time = 6 SECONDS), \ @@ -50,7 +51,7 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \ new/datum/stack_recipe("durathread jumpskirt", /obj/item/clothing/under/color/jumpskirt/durathread, 4, time = 4 SECONDS), \ new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS), \ new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS), \ - new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS), \ + new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \ new/datum/stack_recipe("durathread hoodie", /obj/item/clothing/suit/hooded/hoodie/durathread, 5, time = 5 SECONDS), \ )) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 0056cc7f57dd4..06f70b1690b1f 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -427,7 +427,7 @@ /obj/item/dualsaber/toy/on_wield(obj/item/source, mob/living/carbon/user) . = ..() - sharpness = IS_BLUNT + sharpness = BLUNT bleed_force = 0 /obj/item/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) @@ -459,7 +459,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' block_flags = BLOCKING_ACTIVE | BLOCKING_PROJECTILE //if it some how gets block level, katanas block projectiles for the meme item_flags = ISWEAPON - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE /* @@ -1173,7 +1173,7 @@ card_throwforce = 12 card_throw_speed = 6 embedding = list("pain_mult" = 1, "embed_chance" = 80, "max_damage_mult" = 8, "fall_chance" = 0, "embed_chance_turf_mod" = 15, "armour_block" = 60) //less painful than throwing stars - card_sharpness = IS_SHARP + card_sharpness = SHARP bleed_force = BLEED_SURFACE card_throw_range = 7 card_attack_verb_continuous = list("attacks", "slices", "dices", "slashes", "cuts") diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 51e6a94249423..e8c4a4d60cf00 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -89,7 +89,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 block_upgrade_walk = 1 block_level = 1 block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_DEEP_WOUND max_integrity = 200 armor_type = /datum/armor/item_claymore @@ -280,7 +280,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 block_level = 1 block_upgrade_walk = 1 block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY | BLOCKING_PROJECTILE - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_DEEP_WOUND max_integrity = 200 armor_type = /datum/armor/item_katana @@ -357,7 +357,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 w_class = WEIGHT_CLASS_SMALL item_flags = ISWEAPON hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT custom_materials = list(/datum/material/iron=500, /datum/material/glass=500) resistance_flags = FIRE_PROOF @@ -371,7 +371,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/throwing_star/toy name = "toy throwing star" desc = "An aerodynamic disc strapped with adhesive for sticking to people, good for playing pranks and getting yourself killed by security." - sharpness = IS_BLUNT + sharpness = BLUNT force = 0 throwforce = 0 embedding = list("pain_mult" = 0, "jostle_pain_mult" = 0, "embed_chance" = 300, "fall_chance" = 25, "armour_block" = 70) @@ -424,7 +424,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT else force = initial(force) @@ -434,7 +434,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 attack_verb_continuous = list("stubs", "pokes") attack_verb_simple = list("stub", "poke") hitsound = 'sound/weapons/genhit.ogg' - sharpness = IS_BLUNT + sharpness = BLUNT bleed_force = 0 /obj/item/switchblade/suicide_act(mob/living/user) @@ -574,7 +574,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 throwforce = 0 throw_range = 0 throw_speed = 0 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_DEEP_WOUND attack_verb_continuous = list("saws", "tears", "lacerates", "cuts", "chops", "dices") attack_verb_simple = list("saw", "tear", "lacerate", "cut", "chop", "dice") @@ -1037,7 +1037,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 force = 18 block_upgrade_walk = 1 block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") @@ -1058,7 +1058,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 force = 20 throwforce = 20 throw_speed = 4 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT attack_verb_continuous = list("cuts", "slices", "dices") attack_verb_simple = list("cut", "slice", "dice") diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm index 0fdd01228f0de..5c109dd40fec8 100644 --- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -237,9 +237,9 @@ /obj/item/clothing/head/beret/sci = 2) generate_items_inside(items_inside,src) if(prob(40)) - new /obj/item/clothing/mask/bandana/skull(src) + new /obj/item/clothing/mask/bandana/skull/black(src) if(prob(40)) - new /obj/item/clothing/mask/bandana/skull(src) + new /obj/item/clothing/mask/bandana/skull/black(src) return @@ -321,7 +321,7 @@ /obj/item/clothing/suit/apron = 2, /obj/item/clothing/suit/apron/overalls = 2, /obj/item/clothing/under/rank/civilian/hydroponics = 3, - /obj/item/clothing/mask/bandana/botany = 3) + /obj/item/clothing/mask/bandana/striped/botany = 3) generate_items_inside(items_inside,src) /obj/structure/closet/wardrobe/curator diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index 824c549fbe094..151f62ba0727d 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -58,7 +58,7 @@ new /obj/item/clothing/mask/bandana/black(src) new /obj/item/clothing/mask/bandana/black(src) if(prob(40)) - new /obj/item/clothing/mask/bandana/skull(src) + new /obj/item/clothing/mask/bandana/skull/black(src) return @@ -120,6 +120,8 @@ new /obj/item/clothing/shoes/sneakers/white(src) for(var/i in 1 to 3) new /obj/item/clothing/head/soft(src) + new /obj/item/clothing/mask/bandana/white(src) + new /obj/item/clothing/mask/bandana/white(src) return /obj/structure/closet/wardrobe/pjs @@ -178,11 +180,8 @@ new /obj/item/storage/box/suitbox/wardrobe/mixed(src) new /obj/item/storage/box/suitbox/wardrobe/mixed/jumpskirt(src) new /obj/item/clothing/mask/bandana/red(src) - new /obj/item/clothing/mask/bandana/red(src) - new /obj/item/clothing/mask/bandana/blue(src) new /obj/item/clothing/mask/bandana/blue(src) new /obj/item/clothing/mask/bandana/gold(src) - new /obj/item/clothing/mask/bandana/gold(src) new /obj/item/clothing/shoes/sneakers/black(src) new /obj/item/clothing/shoes/sneakers/brown(src) new /obj/item/clothing/shoes/sneakers/white(src) diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index c4e3061cc1862..e9837c2980790 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -159,6 +159,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( if(old_opacity != opacity && SSticker) GLOB.cameranet.bareMajorChunkChange(src) + // we need to update gravity for any mob on a tile that is being created or destroyed + for(var/mob/living/target in new_turf.contents) + target.refresh_gravity() + return new_turf /turf/open/ChangeTurf(path, list/new_baseturfs, flags) diff --git a/code/game/turfs/open/floor/fancy_floor.dm b/code/game/turfs/open/floor/fancy_floor.dm index 212a1c61c6fff..c7e9f061f41b4 100644 --- a/code/game/turfs/open/floor/fancy_floor.dm +++ b/code/game/turfs/open/floor/fancy_floor.dm @@ -144,7 +144,7 @@ user.visible_message("[user] digs up [src].", "You [turfverb] [src].") playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) make_plating() - else if(C.sharpness != IS_BLUNT) + else if(C.sharpness != BLUNT) QUEUE_SMOOTH(src) QUEUE_SMOOTH_NEIGHBORS(src) icon_state = "grass" diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index 852e4acb84f2e..a2aa5a888839c 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -165,5 +165,5 @@ /area/shuttle_arena name = "arena" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY requires_power = FALSE diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 944211ece19e1..d3bd3381f5f24 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1319,8 +1319,7 @@ if(!ismob(M)) to_chat(usr, "This can only be used on instances of type /mob.") return - var/datum/language_holder/H = M.get_language_holder() - H.open_language_menu(usr) + M.get_language_holder().open_language_menu(usr) else if(href_list["traitor"]) if(!check_rights(R_ADMIN)) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index df2673666bc22..4a14f26c7d54d 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -1,20 +1,57 @@ #define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) + +// defines of hints for how a proc should build strings +#define STYLE_READ_ONLY (1) +#define STYLE_NORMAL (2) +#define STYLE_LIST (3) +#define STYLE_SPECIAL (4) +#define STYLE_EMPTY (5) + /// Get displayed variable in VV variable list /proc/debug_variable(name, value, level, datum/owner, sanitize = TRUE, display_flags = NONE) //if D is a list, name will be index, and value will be assoc value. + // variables to store values + var/index + var/list/owner_list + var/datum/vv_ghost/vv_spectre + + // ------------------------------------------------------------ + // checks if a thing is /list, or /vv_ghost to deliver a special list, and then reassign name/value if(owner) - if(islist(owner)) - var/index = name - var/list/owner_list = owner + if(istype(owner, /datum/vv_ghost)) + vv_spectre = owner + if(islist(owner) || vv_spectre) + index = name + owner_list = vv_spectre?.dmlist_holder || owner if (value) name = owner_list[name] //name is really the index until this line else value = owner_list[name] - . = "
  • ([VV_HREF_TARGET_1V(owner_list, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(owner_list, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(owner_list, VV_HK_LIST_REMOVE, "-", index)]) " - else + + // ------------------------------------------------------------ + // Builds hyperlink strings with edit options + var/special_list_secure_level = (istext(name) && (isdatum(owner) || vv_spectre) ) ? GLOB.vv_special_lists[name] : null + var/is_read_only = CHECK_BITFIELD(display_flags, VV_READ_ONLY) || (special_list_secure_level && (special_list_secure_level <= VV_LIST_READ_ONLY)) + var/hyperlink_style =\ + (is_read_only && level) ? STYLE_EMPTY \ + : is_read_only ? STYLE_READ_ONLY \ + : vv_spectre ? STYLE_SPECIAL \ + : owner_list ? STYLE_LIST \ + : owner ? STYLE_NORMAL \ + : STYLE_EMPTY + + switch(hyperlink_style) + if(STYLE_READ_ONLY) + . = "
  • (Disabled) " + if(STYLE_NORMAL) . = "
  • ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_MASSEDIT, "M", name)]) " - else - . = "
  • " + if(STYLE_LIST) + . = "
  • ([VV_HREF_TARGET_1V(owner_list, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(owner_list, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(owner_list, VV_HK_LIST_REMOVE, "-", index)]) " + if(STYLE_SPECIAL) + . = "
  • ([VV_HREF_SPECIAL(vv_spectre.dmlist_origin_ref, VV_HK_LIST_EDIT, "E", index, vv_spectre.dmlist_varname)]) ([VV_HREF_SPECIAL(vv_spectre.dmlist_origin_ref, VV_HK_LIST_CHANGE, "C", index, vv_spectre.dmlist_varname)]) ([VV_HREF_SPECIAL(vv_spectre.dmlist_origin_ref, VV_HK_LIST_REMOVE, "-", index, vv_spectre.dmlist_varname)]) " + if(STYLE_EMPTY) + . = "
  • " + // ------------------------------------------------------------ var/name_part = VV_HTML_ENCODE(name) if(level > 0 || islist(owner)) //handling keys in assoc lists if(istype(name,/datum)) @@ -30,7 +67,7 @@ return "[.][item]
  • " // This is split into a seperate proc mostly to make errors that happen not break things too much -/proc/_debug_variable_value(name, value, level, datum/owner, sanitize, display_flags) +/proc/_debug_variable_value(name, datum/value, level, datum/owner, sanitize, display_flags) . = "DISPLAY_ERROR: ([value] [REF(value)])" // Make sure this line can never runtime if(isnull(value)) @@ -60,9 +97,12 @@ var/image/image = value return "[image.type] ([get_appearance_vv_summary_name(image)]) [REF(value)]" - if(isfilter(value)) - var/datum/filter_value = value - return "/filter ([filter_value.type] [REF(filter_value)])" + // fun fact: there are two types of /filters. `/filters(/filters(), /filters(), ...)` + // isfilter() doesn't know if it's a parent filter(that has [/filters]s inside of itself), or a child filter + var/isfilter = isfilter(value) + var/is_child_filter = isfilter && !isdatum(owner) && !isappearance(owner) // 'child_filter' means each /filters in /atom.filters + if(is_child_filter) + return "/filters\[child\] ([value.type])" if(isfile(value)) return "'[value]'" @@ -71,17 +111,37 @@ var/datum/datum_value = value return datum_value.debug_variable_value(name, level, owner, sanitize, display_flags) - if(islist(value) || (name in GLOB.vv_special_lists)) // Some special lists arent detectable as a list through istype + var/special_list_secure_level = (istext(name) && isdatum(owner)) ? GLOB.vv_special_lists[name] : null + var/islist = islist(value) || special_list_secure_level + if(islist) var/list/list_value = value - var/list/items = list() - - // This is becuse some lists either dont count as lists or a locate on their ref will return null - var/link_vars = "Vars=[REF(value)]" - if(name in GLOB.vv_special_lists) - link_vars = "Vars=[REF(owner)];special_varname=[name]" - if (!(display_flags & VV_ALWAYS_CONTRACT_LIST) && list_value.len > 0 && list_value.len <= (IS_NORMAL_LIST(list_value) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD)) - for (var/i in 1 to list_value.len) + var/list_type = \ + isfilter ? "/filters\[parent\]" \ + : special_list_secure_level ? "/special_list" \ + : /list + + // Hyperlink to open a /list window. + var/a_open = null + var/a_close = null + + // some '/list' instance is dangerous to open. + var/can_open_list_window = !( (special_list_secure_level == VV_LIST_PROTECTED) || isappearance(owner) ) + if(can_open_list_window) + var/href_reference_string = \ + special_list_secure_level \ + ? "dmlist_origin_ref=[REF(owner)];dmlist_varname=[name]" \ + : "Vars=[REF(value)]" + a_open = "" + a_close = "" + + var/should_fold_list_items = (display_flags & VV_ALWAYS_CONTRACT_LIST) || length(list_value) > VV_BIG_SIZED_LIST_THRESHOLD + if(can_open_list_window && should_fold_list_items) + return "[a_open][list_type] ([length(list_value)])[a_close]" + else + var/flag = (special_list_secure_level && (special_list_secure_level <= VV_LIST_READ_ONLY)) ? VV_READ_ONLY : null + var/list/items = list() + for (var/i in 1 to length(list_value)) var/key = list_value[i] var/val if (IS_NORMAL_LIST(list_value) && !isnum(key)) @@ -90,11 +150,9 @@ val = key key = i - items += debug_variable(key, val, level + 1, sanitize = sanitize) + items += debug_variable(key, val, level + 1, sanitize = sanitize, display_flags = flag) - return "/list ([list_value.len])" - else - return "/list ([list_value.len])" + return "[a_open][list_type] ([length(list_value)])[a_close]" if(name in GLOB.bitfields) var/list/flags = list() @@ -130,3 +188,8 @@  "} //TODO link to modify_transform wrapper for all matrices #undef VV_HTML_ENCODE +#undef STYLE_READ_ONLY +#undef STYLE_NORMAL +#undef STYLE_LIST +#undef STYLE_SPECIAL +#undef STYLE_EMPTY diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index f9fa46664469f..4deac4d4a6389 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -4,17 +4,37 @@ if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list)) return var/target = GET_VV_TARGET + var/vv_refresh_target /// If this var has a reference, vv window will be auto-refreshed + vv_do_basic(target, href_list, href) - if(istype(target, /datum)) - var/datum/D = target - D.vv_do_topic(href_list) + // for non-standard special list + if(href_list["dmlist_origin_ref"]) + var/datum/located = locate(href_list["dmlist_origin_ref"]) + var/dmlist_varname = href_list["dmlist_varname"] + if(!isdatum(located) || !GLOB.vv_special_lists[dmlist_varname] || !(dmlist_varname in located.vars)) + return + if(GET_VV_VAR_TARGET || href_list[VV_HK_DO_LIST_EDIT]) // if href_list["targetvar"] exists, we do vv_edit to list. if not, it's just viewing. + vv_do_list(located.vars[dmlist_varname], href_list) + GLOB.vv_ghost.mark_special(href_list["dmlist_origin_ref"], dmlist_varname) + vv_refresh_target = GLOB.vv_ghost + // for standard /list else if(islist(target)) vv_do_list(target, href_list) - if(href_list["Vars"]) - var/datum/vars_target = locate(href_list["Vars"]) - if(href_list["special_varname"]) // Some special vars can't be located even if you have their ref, you have to use this instead - vars_target = vars_target.vars[href_list["special_varname"]] - debug_variables(vars_target) + GLOB.vv_ghost.mark_list(target) + vv_refresh_target = GLOB.vv_ghost + // for standard /datum + else if(istype(target, /datum)) + var/datum/D = target + D.vv_do_topic(href_list) + + // if there is no `href_list["target"]`, we check `href_list["Vars"]` to see if we want see it + if(!target && !vv_refresh_target) + vv_refresh_target = locate(href_list["Vars"]) + // "Vars" means we want to view-variables this thing. + + if(vv_refresh_target) + debug_variables(vv_refresh_target) + return //Stuff below aren't in dropdowns/etc. @@ -122,11 +142,3 @@ log_admin(log_msg) admin_ticket_log(L, "[log_msg]") vv_update_display(L, Text, "[newamt]") - - - //Finally, refresh if something modified the list. - if(href_list["datumrefresh"]) - var/datum/DAT = locate(href_list["datumrefresh"]) - if(istype(DAT, /datum) || istype(DAT, /client) || islist(DAT)) - debug_variables(DAT) - diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 5765199b84bb9..b17d2a219d924 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -36,7 +36,7 @@ if(!target) to_chat(usr, "The object you tried to expose to [C] no longer exists (nulled or hard-deled)") return - message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]") to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") C.debug_variables(target) diff --git a/code/modules/admin/view_variables/topic_list.dm b/code/modules/admin/view_variables/topic_list.dm index 3922254288b4b..4a3c4b01b2711 100644 --- a/code/modules/admin/view_variables/topic_list.dm +++ b/code/modules/admin/view_variables/topic_list.dm @@ -1,7 +1,24 @@ //LISTS - CAN NOT DO VV_DO_TOPIC BECAUSE LISTS AREN'T DATUMS :( /client/proc/vv_do_list(list/target, href_list) + if(IsAdminAdvancedProcCall()) + to_chat(usr, "Advanced ProcCall detected - You shouldn't call /vv_do_list() directly.") + return var/target_index = text2num(GET_VV_VAR_TARGET) if(check_rights(R_VAREDIT)) + var/dmlist_varname = href_list["dmlist_varname"] + if(dmlist_varname) + var/dmlist_secure_level = GLOB.vv_special_lists[dmlist_varname] + if(isnull(dmlist_secure_level)) // href protection to make sure + log_admin("[key_name(src)] attempted to edit a special list ([dmlist_varname]), but this doesn't exist.") + return + else if(dmlist_secure_level == VV_LIST_EDITABLE) + log_world("### vv_do_list() called: [src] attempted to edit a special list ([dmlist_varname]) Security-level:[dmlist_secure_level](allowed)") + log_admin("[key_name(src)] attempted to edit a special list ([dmlist_varname]) Security-level:[dmlist_secure_level](allowed)") + else // fuck you exploiters + log_world("### vv_do_list() called: [src] attempted to edit a special list ([dmlist_varname]), but denied due to the Security-level:[dmlist_secure_level]") + log_admin("[key_name(src)] attempted to edit a special list ([dmlist_varname]), but denied due to the Security-level:[dmlist_secure_level]") + message_admins("[key_name_admin(src)] attempted to edit a special list ([dmlist_varname]), but denied due to the Security-level:[dmlist_secure_level]. Bonk this guy.") + return if(target_index) if(href_list[VV_HK_LIST_EDIT]) mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index a330c337b7fa1..accf08eef4c98 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,6 +1,13 @@ #define ICON_STATE_CHECKED 1 /// this dmi is checked. We don't check this one anymore. #define ICON_STATE_NULL 2 /// this dmi has null-named icon_state, allowing it to show a sprite on vv editor. +// defines of hints for how a proc should build output data +#define STYLE_DATUM (1) +#define STYLE_APPEARANCE (2) +#define STYLE_READ_ONLY_LIST (3) +#define STYLE_LIST (4) +#define STYLE_SPECIAL_LIST (5) + /client/proc/debug_variables(datum/thing in world) set category = "Debug" set name = "View Variables" @@ -17,17 +24,95 @@ var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv) asset_cache_datum.send(usr) - var/isappearance = isappearance(thing) - var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists dont count as lists, but can be detected by if they have list procs + + // -------------------------------------------------------------- + // ------------ Preparation part ------------ + // -------------------------------------------------------------- + + // vv_ghost part. exotique abyss code. + var/static/datum/vv_ghost/vv_spectre = new() /// internal purpose + var/special_list_secure_level /// secure level of a special list + if(thing == GLOB.vv_ghost) + if(GLOB.vv_ghost.dmlist_origin_ref) + thing = vv_spectre.deliver_special() + special_list_secure_level = GLOB.vv_special_lists[vv_spectre.dmlist_varname] + if(special_list_secure_level == VV_LIST_PROTECTED) // investigating this is not recommended. force return. + vv_spectre.reset() + return + else if(GLOB.vv_ghost.list_holder) + thing = vv_spectre.deliver_list() + else + return // vv_ghost is not meant to be vv'ed + + + // Prepares often-used-values into variables + var/isappearance = isappearance(thing) // TG has a version of handling /appearance stuff, by mirroring the appearance. Our version is accessing /appearance directly. Just be noted. + var/islist = islist(thing) || special_list_secure_level // dm internal special list isn't detectable by 'islist()', but having 'secure_level' means it's detected + if(!islist && !isdatum(thing) && !isappearance) return - - var/title = "" + var/refid = REF(thing) - var/icon/sprite - var/hash - var/type = islist? /list : (isappearance ? "/appearance" : thing.type) + // Prepares '/fake_type' for better readibility. + var/type = \ + isappearance ? "/appearance" \ + : vv_spectre.dmlist_varname ? "/special_list ([vv_spectre.dmlist_varname])" \ + : islist ? /list \ + : thing.type + + // special_list flag + var/read_only_special_list = (special_list_secure_level && (special_list_secure_level <= VV_LIST_READ_ONLY)) + + // Hints how this debug proc will write output data + var/debug_output_style = \ + isappearance ? STYLE_APPEARANCE \ + : read_only_special_list ? STYLE_READ_ONLY_LIST \ + : special_list_secure_level ? STYLE_SPECIAL_LIST \ + : islist ? STYLE_LIST \ + : STYLE_DATUM + + + // ------------------------------------------------------ + // ------------ Building output data --------------- + // ------------------------------------------------------ + + // Builds text: basic info + var/title = "[thing] ([refid]) = [type]" + var/formatted_type = replacetext("[type]", "/", "/") + var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay + + var/list/header + switch(debug_output_style) + if(STYLE_DATUM) + header = thing.vv_get_header() + if(STYLE_APPEARANCE) + header = vv_get_header_appearance(thing) + if(STYLE_LIST, STYLE_SPECIAL_LIST, STYLE_READ_ONLY_LIST) + header = list("/list") + + // Builds text: tells if a datum we're editing has some flags + var/marked_line + var/tagged_line + if(holder) + if(holder.marked_datum && holder.marked_datum == thing) + marked_line = VV_MSG_MARKED + if(LAZYFIND(holder.tagged_datums, thing)) + var/tag_index = LAZYFIND(holder.tagged_datums, thing) + tagged_line = VV_MSG_TAGGED(tag_index) + + var/varedited_line + var/deleted_line + if(!islist) + if(thing.datum_flags & DF_VAR_EDITED) + varedited_line = VV_MSG_EDITED + if(thing.gc_destroyed) + deleted_line = VV_MSG_DELETED + + + // ------------------------------------------------------ + // Builds icon info: shows icon image on vv window + var/icon/sprite var/no_icon = FALSE if(isatom(thing)) @@ -40,6 +125,7 @@ // This list remembers which dmi has null icon_state, to determine if icon_state=null should display a sprite // (NOTE: icon_state="" is correct, but saying null is obvious) var/static/list/dmi_nullstate_checklist = list() + var/image/image_object = thing var/icon_filename_text = "[image_object.icon]" // "icon(null)" type can exist. textifying filters it. if(icon_filename_text) @@ -56,83 +142,110 @@ if(dmi_nullstate_checklist[icon_filename_text] == ICON_STATE_NULL) sprite = icon(image_object.icon, image_object.icon_state) + var/sprite_hash var/sprite_text if(sprite) - hash = md5(sprite) - src << browse_rsc(sprite, "vv[hash].png") - sprite_text = no_icon ? "\[NO ICON\]" : "" - - title = "[thing] ([REF(thing)]) = [type]" - var/formatted_type = replacetext("[type]", "/", "/") - - var/list/header = islist ? list("/list") : (isappearance ? vv_get_header_appearance(thing) : thing.vv_get_header()) - - var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay - - var/marked_line - if(holder && holder.marked_datum && holder.marked_datum == thing) - marked_line = VV_MSG_MARKED - var/tagged_line - if(holder && LAZYFIND(holder.tagged_datums, thing)) - var/tag_index = LAZYFIND(holder.tagged_datums, thing) - tagged_line = VV_MSG_TAGGED(tag_index) - var/varedited_line - if(!islist && (thing.datum_flags & DF_VAR_EDITED)) - varedited_line = VV_MSG_EDITED - var/deleted_line - if(!islist && thing.gc_destroyed) - deleted_line = VV_MSG_DELETED - - var/list/dropdownoptions - if (islist) - dropdownoptions = list( - "---", - "Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD), - "Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS), - "Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES), - "Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH), - "Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE), - "Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE), - "---" + sprite_hash = md5(sprite) + src << browse_rsc(sprite, "vv[sprite_hash].png") + sprite_text = no_icon ? "\[NO ICON\]" : "" + + + // ------------------------------------------------------ + // Builds dropdown-options + var/list/dropdown_options + switch(debug_output_style) + if(STYLE_DATUM) + dropdown_options = thing.vv_get_dropdown() + if(STYLE_APPEARANCE) + dropdown_options = vv_get_dropdown_appearance(thing) + if(STYLE_READ_ONLY_LIST) + dropdown_options = list( + "---", + "Show VV To Player" = VV_HREF_SPECIAL_MENU(vv_spectre.dmlist_origin_ref, VV_HK_EXPOSE, vv_spectre.dmlist_varname), + "---" + ) + if(STYLE_SPECIAL_LIST) + dropdown_options = list( + "---", + "Add Item" = VV_HREF_SPECIAL_MENU(vv_spectre.dmlist_origin_ref, VV_HK_LIST_ADD, vv_spectre.dmlist_varname), + "Remove Nulls" = VV_HREF_SPECIAL_MENU(vv_spectre.dmlist_origin_ref, VV_HK_LIST_ERASE_NULLS, vv_spectre.dmlist_varname), + "Show VV To Player" = VV_HREF_SPECIAL_MENU(vv_spectre.dmlist_origin_ref, VV_HK_EXPOSE, vv_spectre.dmlist_varname), + "---" ) - for(var/i in 1 to length(dropdownoptions)) - var/name = dropdownoptions[i] - var/link = dropdownoptions[name] - dropdownoptions[i] = "" - else if(isappearance) - dropdownoptions = vv_get_dropdown_appearance(thing) - else - dropdownoptions = thing.vv_get_dropdown() - - var/list/names = list() - if(isappearance) - var/static/list/virtual_appearance_vars = build_virtual_appearance_vars() - names = virtual_appearance_vars.Copy() - else if(!islist) - for(var/varname in thing.vars) - names += varname + if(STYLE_LIST) + dropdown_options = list( + "---", + "Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD), + "Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS), + "Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES), + "Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH), + "Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE), + "Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE), + "---" + ) + // Finalize dropdown-options for /list + if(islist) + for(var/idx in 1 to length(dropdown_options)) + var/assoc_key = dropdown_options[idx] + var/assoc_val = dropdown_options[assoc_key] + var/href_string = assoc_val ? "value='[assoc_val]'" : null + dropdown_options[idx] = "" + + + // ------------------------------------------------------ + // Builds var-name list: gathers names of each variable in the thing you're editing. + var/list/varname_list = list() + switch(debug_output_style) + if(STYLE_DATUM) + for(var/each_varname in thing.vars) + varname_list += each_varname + if(STYLE_APPEARANCE) + var/static/list/virtual_appearance_vars = build_virtual_appearance_vars() + varname_list = virtual_appearance_vars.Copy() + // Does nothing to LIST STYLE defines sleep(1 TICKS) var/list/variable_html = list() - if(islist) - var/list/list_value = thing - for(var/i in 1 to list_value.len) - var/key = list_value[i] - var/value - if(IS_NORMAL_LIST(list_value) && IS_VALID_ASSOC_KEY(key)) - value = list_value[key] - variable_html += debug_variable(i, value, 0, list_value) - else if(isappearance) - names = sort_list(names) - for(var/varname in names) - variable_html += debug_variable_appearance(varname, thing) - else - names = sort_list(names) - for(var/varname in names) - if(thing.can_vv_get(varname)) - variable_html += thing.vv_get_var(varname) - + switch(debug_output_style) + if(STYLE_DATUM) + varname_list = sort_list(varname_list) + for(var/each_varname in varname_list) + if(thing.can_vv_get(each_varname)) + variable_html += thing.vv_get_var(each_varname) + if(STYLE_APPEARANCE) + varname_list = sort_list(varname_list) + for(var/each_varname in varname_list) + variable_html += debug_variable_appearance(each_varname, thing) + if(STYLE_LIST, STYLE_SPECIAL_LIST, STYLE_READ_ONLY_LIST) + // There is only VV_READ_ONLY for now + var/list_flags = (read_only_special_list ? VV_READ_ONLY : null) + // If TRUE, instead of sending actual '/special_list' instance, we send 'vv_spectre' which delegates that /special_list + var/should_delegate_list = (special_list_secure_level ? TRUE : FALSE) + + var/list/list_value = thing + for(var/i in 1 to list_value.len) + var/key = list_value[i] + var/value + if(IS_NORMAL_LIST(list_value) && IS_VALID_ASSOC_KEY(key)) + value = list_value[key] + variable_html += debug_variable(i, value, 0, (should_delegate_list ? vv_spectre : thing), display_flags = list_flags) + + // ------------------------------------------------------ + // Builds text: 'href string' based on the existence of 'vv_spectre' (which remembers actual refID of a special list) + var/href_reference_string = \ + vv_spectre.dmlist_varname \ + ? "dmlist_origin_ref=[vv_spectre.dmlist_origin_ref];dmlist_varname=[vv_spectre.dmlist_varname]" \ + : "Vars=[refid]" + /* + href key "Vars" only does refreshing. I hate that name because it's contextless. + "dmlist_origin_ref" and "dmlist_varname" must exist at the same time, to access a special list directly, because such special list is not possible to be accessed through 'locate(refID)' + You can't access /client/images (internal variable) by 'locate(that_client_images_list_ref)'. Yes, This sucks + */ + + + // ------------------------------------------------------ + // Builds html text - finalization var/html = {" @@ -261,14 +374,13 @@
    - Refresh + Refresh
    @@ -307,6 +419,9 @@ datumrefresh=[refid];[HrefToken()]'>Refresh "} + + // Resets vv_spectre, and shows it to user + vv_spectre.reset() src << browse(html, "window=variables[refid];size=475x650") /client/proc/vv_update_display(datum/thing, span, content) @@ -314,3 +429,9 @@ datumrefresh=[refid];[HrefToken()]'>Refresh #undef ICON_STATE_CHECKED #undef ICON_STATE_NULL + +#undef STYLE_DATUM +#undef STYLE_APPEARANCE +#undef STYLE_READ_ONLY_LIST +#undef STYLE_LIST +#undef STYLE_SPECIAL_LIST diff --git a/code/modules/admin/view_variables/vv_ghost.dm b/code/modules/admin/view_variables/vv_ghost.dm new file mode 100644 index 0000000000000..580b3cb07756b --- /dev/null +++ b/code/modules/admin/view_variables/vv_ghost.dm @@ -0,0 +1,104 @@ +GLOBAL_PROTECT(vv_ghost) +GLOBAL_DATUM_INIT(vv_ghost, /datum/vv_ghost, new) // Fake datum for vv debug_variables() proc. Am I real? + +/* + < What the hell is this vv_ghost? > + Our view-variables client proc doesn't like to investigate list() instances. + This means `debug_variables(list_reference)` won't work, because it only wants /datum - but /list is not /datum + vv_ghost exists to trick the proc, by storing values to bypass /datum restriction of the proc. + but also, it exists to deliever some special list that isn't possible to get through locate(). + < Can you just do `locate([0x0_list_ref_id])`? > + Only an ordinary /list is possible to be located through locate() + First, vv takes values from 'href' texts. + Of course, we can get ref_id of a special list, + BUT `locate(ref_id_of_special_list)` returns null. (only ordinary /list works this) + This is why we need to store 'dmlist_origin_ref', and 'dmlist_varname' + We locate(dmlist_origin_ref), then access their special list from their var list. + => dmlist_holder.vars[dmlist_varname] + < Summary > + Two usages exist: + 1. Store a list_ref into this datum, to deliver the list into the vv debugging system. + 2. Store a datum's ref_id with target varname, to deliver the special list into the vv debugging system. +*/ + +/datum/vv_ghost + // --- variables for vv special list --- + /// Ref ID of a thing. + var/dmlist_origin_ref + /// which var of the reference you're s eeing + var/dmlist_varname + /// instance holder for special list + var/datum/dmlist_holder + + // --- variable for ordinary lists --- + /// instance holder for normal list + var/list_holder + + // --- variable for internal use only --- + /// a failsafe variable + var/ready_to_del + +/datum/vv_ghost/New() + var/static/creation_count = 2 // to prevent something bullshit + + if(creation_count) + creation_count-- + ..() + return + + else + stack_trace("vv_ghost is not meant to be created more than 2 in the current logic. One for GLOB, one for vv internal") + ready_to_del = TRUE + qdel(src) + +/datum/vv_ghost/Destroy(force = FALSE) + if(ready_to_del || force) + reset() + return ..() + + stack_trace("Something breaks view-variables debugging tool... Check something.") + return QDEL_HINT_LETMELIVE + +/datum/vv_ghost/proc/mark_special(origin_ref, varname) + if(dmlist_origin_ref) + CRASH("vv_ghost has dmlist_origin_ref already: [dmlist_origin_ref]. It can be async issue.") + if(dmlist_varname) + CRASH("vv_ghost has dmlist_varname already: [dmlist_varname]. It can be async issue.") + dmlist_origin_ref = origin_ref + dmlist_varname = varname + +/datum/vv_ghost/proc/mark_list(actual_list) + if(list_holder) + CRASH("vv_ghost has list_ref already: [list_holder]. It can be async issue.") + list_holder = actual_list + +/// a proc that delivers values to vv_spectre (internal static one). +/// vv_spectre exists to prevent async error, just in case +/datum/vv_ghost/proc/deliver_special() + if(GLOB.vv_ghost == src) + CRASH("This proc isn't meant be called from GLOB one.") + + dmlist_origin_ref = GLOB.vv_ghost.dmlist_origin_ref // = [0x123456] + dmlist_varname = GLOB.vv_ghost.dmlist_varname // = "vis_contents" + GLOB.vv_ghost.dmlist_origin_ref = null + GLOB.vv_ghost.dmlist_varname = null + + var/datum/located = locate(dmlist_origin_ref) // = Clown [0x123456] + dmlist_holder = located.vars[dmlist_varname] // = Clown.vis_contents + return dmlist_holder + +/// a proc that delivers values to vv_spectre (internal static one). +/// vv_spectre exists to prevent async error, just in case +/datum/vv_ghost/proc/deliver_list() + if(GLOB.vv_ghost == src) + CRASH("This proc isn't meant be called from GLOB one.") + + var/return_target = GLOB.vv_ghost.list_holder + GLOB.vv_ghost.list_holder = null + return return_target + +/datum/vv_ghost/proc/reset() + dmlist_origin_ref = null + dmlist_varname = null + dmlist_holder = null + list_holder = null diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index 403ea59a3a549..c75541bd0e1b2 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -135,12 +135,12 @@ /obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, pref_load = FALSE) ..() owner.faction |= "slime" - owner.grant_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND) + owner.grant_language(/datum/language/slime, source = LANGUAGE_GLAND) /obj/item/organ/heart/gland/slime/Remove(mob/living/carbon/M, special = 0, pref_load = FALSE) ..() owner.faction -= "slime" - owner.remove_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND) + owner.remove_language(/datum/language/slime, source = LANGUAGE_GLAND) /obj/item/organ/heart/gland/slime/activate() to_chat(owner, "You feel nauseated!") diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index f37fc8cd758d8..5b042e87c0201 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -96,7 +96,8 @@ if(give_objectives) forge_objectives() handle_clown_mutation(owner.current, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.") - owner.current.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue. We are able to transform our body after all. + owner.current.get_language_holder().omnitongue = TRUE + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) . = ..() /datum/antagonist/changeling/on_removal() diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index c11aa30ed52e1..d379047ad2497 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -160,7 +160,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force = BLEED_DEEP_WOUND var/can_drop = FALSE var/fake = FALSE @@ -175,6 +175,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/melee/arm_blade) loc.visible_message("A grotesque blade forms around [loc.name]\'s arm!", "Our arm twists and mutates, transforming it into a deadly blade.", "You hear organic matter ripping and tearing!") if(synthetic) can_drop = TRUE + sharpness = SHARP_DISMEMBER AddComponent(/datum/component/butchering, 60, 80) /obj/item/melee/arm_blade/afterattack(atom/target, mob/user, proximity) diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index 44ff428fdaff9..a56a3e5a4a38e 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -128,6 +128,7 @@ /obj/item/melee/arm_blade/false desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless." + sharpness = BLUNT //Not actually sharp force = 5 //Basically as strong as a punch fake = TRUE diff --git a/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm b/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm index 97c61732910c2..9caee25a385a9 100644 --- a/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm +++ b/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm @@ -19,7 +19,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "lacerates", "gores") attack_verb_simple = list("attack", "poke", "jab", "tear", "lacerate", "gore") - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP bleed_force = BLEED_CUT max_integrity = 200 var/clockwork_hint = "" @@ -99,7 +99,7 @@ worn_icon_state = "mining_hammer1" throwforce = 25 armour_penetration = 6 - sharpness = IS_BLUNT + sharpness = BLUNT attack_verb_continuous = list("bashes", "bludgeons", "thrashes", "whacks") attack_verb_simple = list("bash", "bludgeon", "thrash", "whack") clockwork_hint = "Enemies hit by this will be flung back while on Reebe." diff --git a/code/modules/antagonists/clock_cult/servant_of_ratvar.dm b/code/modules/antagonists/clock_cult/servant_of_ratvar.dm index 155e456db44e9..ca40507c138f2 100644 --- a/code/modules/antagonists/clock_cult/servant_of_ratvar.dm +++ b/code/modules/antagonists/clock_cult/servant_of_ratvar.dm @@ -74,7 +74,7 @@ owner.current.throw_alert("clockinfo", /atom/movable/screen/alert/clockwork/clocksense) SSticker.mode.update_clockcult_icons_added(owner) var/datum/language_holder/LH = owner.current.get_language_holder() - LH.grant_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_CULTIST) + LH.grant_language(/datum/language/ratvar, source = LANGUAGE_CULTIST) /datum/antagonist/servant_of_ratvar/remove_innate_effects(mob/living/M) owner.current.faction -= "ratvar" @@ -86,7 +86,7 @@ owner_mob.remove_overlay(forbearance) qdel(forbearance) var/datum/language_holder/LH = owner.current.get_language_holder() - LH.remove_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_CULTIST) + LH.remove_language(/datum/language/ratvar, source = LANGUAGE_CULTIST) . = ..() /datum/antagonist/servant_of_ratvar/proc/equip_servant_conversion() diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 0f5fe03d59f8a..a778d6cf0bd65 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -114,7 +114,7 @@ if(mob_override) current = mob_override current.faction |= "cult" - current.grant_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST) + current.grant_language(/datum/language/narsie, source = LANGUAGE_CULTIST) if(!cult_team.cult_master) vote.Grant(current) communion.Grant(current) @@ -142,7 +142,7 @@ if(mob_override) current = mob_override current.faction -= "cult" - current.remove_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST) + current.remove_language(/datum/language/narsie, source = LANGUAGE_CULTIST) vote.Remove(current) communion.Remove(current) magic.Remove(current) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index cf05b79bfbcaf..ae43b26f59559 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -47,7 +47,7 @@ Striking a noncultist, however, will tear their flesh."} lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' flags_1 = CONDUCT_1 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT w_class = WEIGHT_CLASS_BULKY block_level = 1 @@ -576,7 +576,7 @@ Striking a noncultist, however, will tear their flesh."} block_upgrade_walk = 1 attack_verb_continuous = list("attacks", "impales", "stabs", "tears", "lacerates", "gores") attack_verb_simple = list("attack", "impale", "stab", "tear", "lacerate", "gore") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT hitsound = 'sound/weapons/bladeslice.ogg' var/datum/action/innate/cult/spear/spear_act diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index 1f3385c65b49d..cbdca6a8bf1f3 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -9,7 +9,7 @@ inhand_x_dimension = 64 inhand_y_dimension = 64 flags_1 = CONDUCT_1 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force = BLEED_CUT w_class = WEIGHT_CLASS_LARGE force = 24 diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm index cadfaff47ef48..357d568717197 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm @@ -88,7 +88,7 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) /area/heretic_sacrifice name = "Mansus" icon_state = "away" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambience_index = AMBIENCE_SPOOKY sound_environment = SOUND_ENVIRONMENT_CAVE area_flags = UNIQUE_AREA | HIDDEN_AREA | BLOCK_SUICIDE diff --git a/code/modules/antagonists/heretic/structures/carving_knife.dm b/code/modules/antagonists/heretic/structures/carving_knife.dm index eed18614df296..516c3f914a763 100644 --- a/code/modules/antagonists/heretic/structures/carving_knife.dm +++ b/code/modules/antagonists/heretic/structures/carving_knife.dm @@ -6,7 +6,7 @@ icon = 'icons/obj/heretic.dmi' icon_state = "rune_carver" flags_1 = CONDUCT_1 - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT w_class = WEIGHT_CLASS_SMALL force = 10 diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index 4c43bd564af0d..ad245568a6d72 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -65,12 +65,12 @@ . = ..() var/mob/living/owner_mob = mob_override || owner.current var/datum/language_holder/holder = owner_mob.get_language_holder() - holder.grant_language(/datum/language/piratespeak, TRUE, TRUE, LANGUAGE_PIRATE) + holder.grant_language(/datum/language/piratespeak, source = LANGUAGE_PIRATE) holder.selected_language = /datum/language/piratespeak /datum/antagonist/pirate/remove_innate_effects(mob/living/mob_override) var/mob/living/owner_mob = mob_override || owner.current - owner_mob.remove_language(/datum/language/piratespeak, TRUE, TRUE, LANGUAGE_PIRATE) + owner_mob.remove_language(/datum/language/piratespeak, source = LANGUAGE_PIRATE) return ..() /datum/team/pirate diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index d420e06b81032..984ef90c9fb0d 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -84,7 +84,7 @@ check_rev_teleport() // they're spawned in non-station for some reason... random_revenant_name() AddComponent(/datum/component/tracking_beacon, "ghost", null, null, TRUE, "#9e4d91", TRUE, TRUE, "#490066") - grant_all_languages(TRUE, FALSE, FALSE, LANGUAGE_REVENANT) // rev can understand every langauge + grant_all_languages(UNDERSTOOD_LANGUAGE, grant_omnitongue = FALSE, source = LANGUAGE_REVENANT) // rev can understand every langauge ADD_TRAIT(src, TRAIT_FREE_HYPERSPACE_MOVEMENT, INNATE_TRAIT) AddElement(/datum/element/movetype_handler) ADD_TRAIT(src, TRAIT_MOVE_FLOATING, "ghost") diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index c90dbffffa045..8ffaca9fcd298 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -96,7 +96,7 @@ if(TRAITOR_AI) add_law_zero() owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', vol = 100, vary = FALSE, channel = CHANNEL_ANTAG_GREETING, pressure_affected = FALSE, use_reverb = FALSE) - owner.current.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MALF) + owner.current.grant_language(/datum/language/codespeak, source = LANGUAGE_MALF) if(TRAITOR_HUMAN) ui_interact(owner.current) owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', vol = 100, vary = FALSE, channel = CHANNEL_ANTAG_GREETING, pressure_affected = FALSE, use_reverb = FALSE) diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 411269dfffb60..4b72737714311 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -353,9 +353,9 @@ S.real_name = "Shade of [T.real_name]" S.key = shade_controller.key S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder. - S.copy_languages(user, LANGUAGE_MASTER) - S.update_atom_languages() - grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue + if(user) + S.copy_languages(user, LANGUAGE_MASTER) + S.get_language_holder().omnitongue = TRUE //Grants omnitongue if(user) S.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation if(user && iscultist(user)) diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index efb313a639375..650e65709d65f 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -20,6 +20,7 @@ resistance_flags = FIRE_PROOF max_integrity = 200 obj_flags = CAN_BE_HIT | ON_BLUEPRINTS + flags_1 = STAT_UNIQUE_1 var/can_unwrench = 0 var/initialize_directions = 0 var/pipe_color diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index be7bf34de53a6..128f6ce75e683 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -77,7 +77,7 @@ /obj/item/clothing/suit/jacket/leather/overcoat, /obj/item/clothing/gloves/color/black, /obj/item/clothing/head/soft/cargo, - /obj/item/clothing/mask/bandana/skull)//so you can properly #cargoniabikergang + /obj/item/clothing/mask/bandana/skull/black)//so you can properly #cargoniabikergang crate_name = "Biker Kit" crate_type = /obj/structure/closet/crate/large diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 31802de2e8c0d..e936068946c1f 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -115,6 +115,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( cmd_mentor_pm(href_list["mentor_msg"], null) return TRUE + if(href_list["commandbar_typing"]) + handle_commandbar_typing(href_list) + switch(href_list["_src_"]) if("holder") hsrc = holder @@ -209,6 +212,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( tgui_say = new(src, "tgui_say") tgui_asay = new(src, "tgui_asay") + initialize_commandbar_spy() + GLOB.ahelp_tickets.ClientLogin(src) GLOB.mhelp_tickets.ClientLogin(src) GLOB.interviews.client_login(src) diff --git a/code/modules/client/loadout/loadout_accessories.dm b/code/modules/client/loadout/loadout_accessories.dm index 60c18fcbc94be..2c6cf051a21d0 100644 --- a/code/modules/client/loadout/loadout_accessories.dm +++ b/code/modules/client/loadout/loadout_accessories.dm @@ -209,7 +209,7 @@ /datum/gear/accessory/bandana/skull display_name = "skull bandana" - path = /obj/item/clothing/mask/bandana/skull + path = /obj/item/clothing/mask/bandana/skull/black cost = 2000 //LIPSTICK diff --git a/code/modules/client/verbs/typing.dm b/code/modules/client/verbs/typing.dm new file mode 100644 index 0000000000000..0fa583baa1cb6 --- /dev/null +++ b/code/modules/client/verbs/typing.dm @@ -0,0 +1,70 @@ +#define IC_VERBS list("say", "me", "whisper") + +/client/var/commandbar_thinking = FALSE +/client/var/commandbar_typing = FALSE + +/client/proc/initialize_commandbar_spy() + src << output('html/typing_indicator.html', "commandbar_spy") + +/client/proc/handle_commandbar_typing(href_list) + //if (!typing_indicators) //check pref + // return + if (length(href_list["verb"]) < 1 || !(LOWER_TEXT(href_list["verb"]) in IC_VERBS) || text2num(href_list["argument_length"]) < 1) + if (commandbar_typing) + commandbar_typing = FALSE + stop_typing() + + if (commandbar_thinking) + commandbar_thinking = FALSE + stop_thinking() + return + + if (!commandbar_thinking) + commandbar_thinking = TRUE + start_thinking() + + if (!commandbar_typing) + commandbar_typing = TRUE + start_typing() + + +/** Sets the mob as "thinking" - with indicator and the TRAIT_THINKING_IN_CHARACTER trait */ +/client/proc/start_thinking() + //if(!typing_indicators) + // return FALSE + /// Special exemptions + if(isabductor(mob)) + return FALSE + ADD_TRAIT(mob, TRAIT_THINKING_IN_CHARACTER, CURRENTLY_TYPING_TRAIT) + mob.create_thinking_indicator() + +/** Removes typing/thinking indicators and flags the mob as not thinking */ +/client/proc/stop_thinking() + mob?.remove_all_indicators() + +/** + * Handles the user typing. After a brief period of inactivity, + * signals the client mob to revert to the "thinking" icon. + */ +/client/proc/start_typing() + var/mob/client_mob = mob + client_mob.remove_thinking_indicator() + if(!HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER)) + return FALSE + client_mob.create_typing_indicator() + addtimer(CALLBACK(src, PROC_REF(stop_typing)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE) + +/** + * Callback to remove the typing indicator after a brief period of inactivity. + * If the user was typing IC, the thinking indicator is shown. + */ +/client/proc/stop_typing() + if(isnull(mob)) + return FALSE + var/mob/client_mob = mob + client_mob.remove_typing_indicator() + if(!HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER)) + return FALSE + client_mob.create_thinking_indicator() + +#undef IC_VERBS diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 5741630d0d3f4..a73b48b71a3e2 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -123,7 +123,7 @@ attack_verb_continuous = list("slices") attack_verb_simple = list("slice") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE /obj/item/clothing/glasses/meson/prescription @@ -244,7 +244,7 @@ attack_verb_continuous = list("slices") attack_verb_simple = list("slice") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE glass_colour_type = /datum/client_colour/glass_colour/lightgreen @@ -329,7 +329,7 @@ attack_verb_continuous = list("slices") attack_verb_simple = list("slice") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE /obj/item/clothing/glasses/sunglasses/advanced/garb/supergarb @@ -351,7 +351,7 @@ attack_verb_continuous = list("slices") attack_verb_simple = list("slice") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE glass_colour_type = /datum/client_colour/glass_colour/orange diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index b3beba00edd23..743fe43f953c1 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -293,7 +293,7 @@ attack_verb_continuous = list("slices") attack_verb_simple = list("slice") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE /obj/item/clothing/glasses/hud/security/sunglasses/gars/supergars diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 8fc44b0c65e68..9e1f03a9daf06 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -148,17 +148,16 @@ /obj/item/clothing/head/costume/speedwagon name = "hat of ultimate masculinity" desc = "Even the mere act of wearing this makes you want to pose menacingly." - worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi' icon_state = "speedwagon" item_state = "speedwagon" - worn_x_dimension = 64 - worn_y_dimension = 64 + worn_y_offset = 4 /obj/item/clothing/head/costume/speedwagon/cursed name = "ULTIMATE HAT" desc = "You feel weak and pathetic in comparison to this exceptionally beautiful hat." - icon_state = "speedwagon_cursed" - item_state = "speedwagon_cursed" + icon_state = "speedwagon" + item_state = "speedwagon" + worn_y_offset = 6 /obj/item/clothing/head/franks_hat name = "Frank's Hat" diff --git a/code/modules/clothing/head/pirate.dm b/code/modules/clothing/head/pirate.dm index 5ddb96ae5ff77..bc377306b94bb 100644 --- a/code/modules/clothing/head/pirate.dm +++ b/code/modules/clothing/head/pirate.dm @@ -13,7 +13,7 @@ if(!ishuman(user)) return if(slot == ITEM_SLOT_HEAD) - user.grant_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT) + user.grant_language(/datum/language/piratespeak/, source = LANGUAGE_HAT) to_chat(user, "You suddenly know how to speak like a pirate!") /obj/item/clothing/head/costume/pirate/dropped(mob/user) @@ -22,7 +22,7 @@ return var/mob/living/carbon/human/H = user if(H.get_item_by_slot(ITEM_SLOT_HEAD) == src && !QDELETED(src)) //This can be called as a part of destroy - user.remove_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT) + user.remove_language(/datum/language/piratespeak/, source = LANGUAGE_HAT) to_chat(user, "You can no longer speak like a pirate.") /obj/item/clothing/head/costume/pirate/captain diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index 48816303b8c96..50dc44d8e44f8 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -6,7 +6,7 @@ strip_delay = 40 equip_delay_other = 40 var/modifies_speech = FALSE - var/mask_adjusted = 0 + var/mask_adjusted = FALSE var/adjusted_flags = null var/voice_change = FALSE //Used to mask/change the user's voice, only specific masks can set this to TRUE var/obj/item/organ/tongue/chosen_tongue = null diff --git a/code/modules/clothing/masks/bandana.dm b/code/modules/clothing/masks/bandana.dm new file mode 100644 index 0000000000000..f2a560ef4d234 --- /dev/null +++ b/code/modules/clothing/masks/bandana.dm @@ -0,0 +1,192 @@ +/obj/item/clothing/mask/bandana + w_class = WEIGHT_CLASS_TINY + flags_cover = MASKCOVERSMOUTH + flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT + visor_flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT + visor_flags_cover = MASKCOVERSMOUTH + slot_flags = ITEM_SLOT_MASK + adjusted_flags = ITEM_SLOT_HEAD + dying_key = DYE_REGISTRY_BANDANA + //flags_1 = IS_PLAYER_COLORABLE_1 + name = "bandana" + desc = "A fine bandana with nanotech lining." + icon_state = "bandana" + worn_icon_state = "bandana_worn" + greyscale_config = /datum/greyscale_config/bandana + greyscale_config_worn = /datum/greyscale_config/bandana_worn + var/greyscale_config_up = /datum/greyscale_config/bandana_up + var/greyscale_config_worn_up = /datum/greyscale_config/bandana_worn_up + greyscale_colors = "#2e2e2e" + +/obj/item/clothing/mask/bandana/attack_self(mob/user) + if(slot_flags & ITEM_SLOT_NECK) + to_chat(user, "You must undo [src] in order to push it into a hat!") + return + adjustmask(user) + if(greyscale_config == initial(greyscale_config) && greyscale_config_worn == initial(greyscale_config_worn)) + worn_icon_state += "_up" + undyeable = TRUE + set_greyscale( + new_config = greyscale_config_up, + new_worn_config = greyscale_config_worn_up + ) + else + worn_icon_state = initial(worn_icon_state) + undyeable = initial(undyeable) + set_greyscale( + new_config = initial(greyscale_config), + new_worn_config = initial(greyscale_config_worn) + ) + +/obj/item/clothing/mask/bandana/AltClick(mob/user) + . = ..() + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/matrix/widen = matrix() + if(!user.is_holding(src)) + to_chat(user, "You must be holding [src] in order to tie it!") + return + if((C.get_item_by_slot(ITEM_SLOT_HEAD == src)) || (C.get_item_by_slot(ITEM_SLOT_MASK) == src)) + to_chat(user, "You can't tie [src] while wearing it!") + return + if(slot_flags & ITEM_SLOT_HEAD) + to_chat(user, "You must undo [src] before you can tie it into a neckerchief!") + return + if(slot_flags & ITEM_SLOT_MASK) + undyeable = TRUE + slot_flags = ITEM_SLOT_NECK + worn_y_offset = -3 + widen.Scale(1.25, 1) + transform = widen + user.visible_message("[user] ties [src] up like a neckerchief.", "You tie [src] up like a neckerchief.") + else + undyeable = initial(undyeable) + slot_flags = initial(slot_flags) + worn_y_offset = initial(worn_y_offset) + transform = initial(transform) + user.visible_message("[user] unties the neckerchief.", "You untie the neckerchief.") + +/obj/item/clothing/mask/bandana/red + name = "red bandana" + desc = "A fine red bandana with nanotech lining." + greyscale_colors = "#A02525" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/blue + name = "blue bandana" + desc = "A fine blue bandana with nanotech lining." + greyscale_colors = "#294A98" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/purple + name = "purple bandana" + desc = "A fine purple bandana with nanotech lining." + greyscale_colors = "#8019a0" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/green + name = "green bandana" + desc = "A fine green bandana with nanotech lining." + greyscale_colors = "#3D9829" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/gold + name = "gold bandana" + desc = "A fine gold bandana with nanotech lining." + greyscale_colors = "#DAC20E" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/orange + name = "orange bandana" + desc = "A fine orange bandana with nanotech lining." + greyscale_colors = "#da930e" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/black + name = "black bandana" + desc = "A fine black bandana with nanotech lining." + greyscale_colors = "#2e2e2e" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/white + name = "white bandana" + desc = "A fine white bandana with nanotech lining." + greyscale_colors = "#DCDCDC" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/durathread + name = "durathread bandana" + desc = "A bandana made from durathread, you wish it would provide some protection to its wearer, but it's far too thin..." + greyscale_colors = "#5c6d80" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped + name = "striped bandana" + desc = "A fine bandana with nanotech lining and a stripe across." + icon_state = "bandstriped" + worn_icon_state = "bandstriped_worn" + greyscale_config = /datum/greyscale_config/bandstriped + greyscale_config_worn = /datum/greyscale_config/bandstriped_worn + greyscale_config_up = /datum/greyscale_config/bandstriped_up + greyscale_config_worn_up = /datum/greyscale_config/bandstriped_worn_up + greyscale_colors = "#2e2e2e#C6C6C6" + undyeable = TRUE + +/obj/item/clothing/mask/bandana/striped/black + name = "striped bandana" + desc = "A fine black and white bandana with nanotech lining and a stripe across." + greyscale_colors = "#2e2e2e#C6C6C6" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped/security + name = "striped security bandana" + desc = "A fine bandana with nanotech lining, a stripe across and security colors." + greyscale_colors = "#A02525#2e2e2e" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped/science + name = "striped science bandana" + desc = "A fine bandana with nanotech lining, a stripe across and science colors." + greyscale_colors = "#DCDCDC#8019a0" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped/engineering + name = "striped engineering bandana" + desc = "A fine bandana with nanotech lining, a stripe across and engineering colors." + greyscale_colors = "#dab50e#ec7404" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped/medical + name = "striped medical bandana" + desc = "A fine bandana with nanotech lining, a stripe across and medical colors." + greyscale_colors = "#DCDCDC#5995BA" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped/cargo + name = "striped cargo bandana" + desc = "A fine bandana with nanotech lining, a stripe across and cargo colors." + greyscale_colors = "#967032#5F350B" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/striped/botany + name = "striped botany bandana" + desc = "A fine bandana with nanotech lining, a stripe across and botany colors." + greyscale_colors = "#3D9829#294A98" + flags_1 = NONE + +/obj/item/clothing/mask/bandana/skull + name = "skull bandana" + desc = "A fine bandana with nanotech lining and a skull emblem." + icon_state = "bandskull" + worn_icon_state = "bandskull_worn" + greyscale_config = /datum/greyscale_config/bandskull + greyscale_config_worn = /datum/greyscale_config/bandskull_worn + greyscale_config_up = /datum/greyscale_config/bandskull_up + greyscale_config_worn_up = /datum/greyscale_config/bandskull_worn_up + greyscale_colors = "#2e2e2e#C6C6C6" + undyeable = TRUE + +/obj/item/clothing/mask/bandana/skull/black + desc = "A fine black bandana with nanotech lining and a skull emblem." + greyscale_colors = "#2e2e2e#C6C6C6" + flags_1 = NONE diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 1cc8af863b241..d472999cf14df 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -255,90 +255,6 @@ icon_state = "bumba" item_state = "bumba" -/obj/item/clothing/mask/bandana - name = "white bandana" - desc = "A fine white bandana with nanotech lining." - w_class = WEIGHT_CLASS_TINY - flags_cover = MASKCOVERSMOUTH - flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT - visor_flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT - visor_flags_cover = MASKCOVERSMOUTH - slot_flags = ITEM_SLOT_MASK - adjusted_flags = ITEM_SLOT_HEAD - icon_state = "bandwhite" - -/obj/item/clothing/mask/bandana/attack_self(mob/user) - adjustmask(user) - if (mask_adjusted) - worn_icon = 'icons/mob/clothing/head/costume.dmi' - else - worn_icon = 'icons/mob/clothing/mask.dmi' - -/obj/item/clothing/mask/bandana/AltClick(mob/user) - if(!user.canUseTopic(src, BE_CLOSE)) - return - if(iscarbon(user)) - var/mob/living/carbon/C = user - if((C.get_item_by_slot(ITEM_SLOT_HEAD == src)) || (C.get_item_by_slot(ITEM_SLOT_MASK) == src)) - to_chat(user, "You can't tie [src] while wearing it!") - return - if(slot_flags & ITEM_SLOT_HEAD) - to_chat(user, "You must undo [src] before you can tie it into a neckerchief!") - else - if(user.is_holding(src)) - var/obj/item/clothing/neck/neckerchief/nk = new(src) - nk.name = "[name] neckerchief" - nk.desc = "[desc] It's tied up like a neckerchief." - nk.icon_state = icon_state - nk.sourceBandanaType = src.type - var/currentHandIndex = user.get_held_index_of_item(src) - user.transferItemToLoc(src, null) - user.put_in_hand(nk, currentHandIndex) - user.visible_message("[user] ties [src] up like a neckerchief.", "You tie [src] up like a neckerchief.") - qdel(src) - else - to_chat(user, "You must be holding [src] in order to tie it!") - -/obj/item/clothing/mask/bandana/red - name = "red bandana" - desc = "A fine red bandana with nanotech lining." - icon_state = "bandred" - -/obj/item/clothing/mask/bandana/blue - name = "blue bandana" - desc = "A fine blue bandana with nanotech lining." - icon_state = "bandblue" - -/obj/item/clothing/mask/bandana/green - name = "green bandana" - desc = "A fine green bandana with nanotech lining." - icon_state = "bandgreen" - -/obj/item/clothing/mask/bandana/gold - name = "gold bandana" - desc = "A fine gold bandana with nanotech lining." - icon_state = "bandgold" - -/obj/item/clothing/mask/bandana/black - name = "black bandana" - desc = "A fine black bandana with nanotech lining." - icon_state = "bandblack" - -/obj/item/clothing/mask/bandana/skull - name = "skull bandana" - desc = "A fine black bandana with nanotech lining and a skull emblem." - icon_state = "bandskull" - -/obj/item/clothing/mask/bandana/botany - name = "botany bandana" - desc = "A fine bandana with nanotech lining and a hydroponics pattern." - icon_state = "bandbotany" - -/obj/item/clothing/mask/bandana/durathread - name = "durathread bandana" - desc = "A bandana made from durathread, you wish it would provide some protection to its wearer, but it's far too thin..." - icon_state = "banddurathread" - /obj/item/clothing/mask/mummy name = "mummy mask" desc = "Ancient bandages." diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 55505bbae412a..88a6144890a51 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -198,34 +198,6 @@ desc = "In nomine Patris, et Filii, et Spiritus Sancti." icon_state = "cross" -/obj/item/clothing/neck/neckerchief - worn_icon = "empty_bandana" - w_class = WEIGHT_CLASS_TINY - var/sourceBandanaType - -/obj/item/clothing/neck/neckerchief/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file, item_layer, atom/origin) - . = ..() - if(!isinhands) - var/mutable_appearance/realOverlay = mutable_appearance('icons/mob/clothing/mask.dmi', icon_state, item_layer) - realOverlay.pixel_y = -3 - . += realOverlay - -/obj/item/clothing/neck/neckerchief/AltClick(mob/user) - if(iscarbon(user)) - var/mob/living/carbon/C = user - if(C.get_item_by_slot(ITEM_SLOT_NECK) == src) - to_chat(user, "You can't untie [src] while wearing it!") - return - if(user.is_holding(src)) - var/obj/item/clothing/mask/bandana/newBand = new sourceBandanaType(user) - var/currentHandIndex = user.get_held_index_of_item(src) - var/oldName = src.name - qdel(src) - user.put_in_hand(newBand, currentHandIndex) - user.visible_message("[user] unties [oldName] back into a [newBand.name]", "You untie [oldName] back into a [newBand.name]") - else - to_chat(user, "You must be holding [src] in order to untie it!") - ///////////////// //DONATOR ITEMS// ///////////////// diff --git a/code/modules/clothing/suits/chaplainsuits.dm b/code/modules/clothing/suits/chaplainsuits.dm index 8ac269fe03a6d..03bddfa26507d 100644 --- a/code/modules/clothing/suits/chaplainsuits.dm +++ b/code/modules/clothing/suits/chaplainsuits.dm @@ -156,6 +156,7 @@ icon = 'icons/obj/clothing/head/chaplain.dmi' worn_icon = 'icons/mob/clothing/head/chaplain.dmi' icon_state = "crusader" + item_state = null w_class = WEIGHT_CLASS_NORMAL flags_inv = HIDEHAIR|HIDEEARS|HIDEFACE armor_type = /datum/armor/plate_crusader @@ -185,12 +186,11 @@ name = "Prophet's Hat" desc = "A religious-looking hat." icon_state = null - worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi' + worn_icon = 'icons/mob/clothing/head/helmet.dmi' item_state = null flags_1 = 0 armor_type = /datum/armor/crusader_prophet - worn_x_dimension = 64 - worn_y_dimension = 64 + worn_y_offset = 6 /datum/armor/crusader_prophet @@ -218,12 +218,10 @@ name = "cage" desc = "A cage that restrains the will of the self, allowing one to see the profane world for what it is." flags_inv = NONE - worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi' icon_state = "cage" item_state = null - worn_x_dimension = 64 - worn_y_dimension = 64 dynamic_hair_suffix = "" + worn_y_offset = 7 /obj/item/clothing/head/helmet/chaplain/ancient name = "ancient helmet" diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm index 4197b5e5da6e2..a72e9d2e5c4e3 100644 --- a/code/modules/error_handler/error_viewer.dm +++ b/code/modules/error_handler/error_viewer.dm @@ -128,7 +128,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) var/const/viewtext = "\[view]" // Nesting these in other brackets went poorly //log_debug("Runtime in [e.file], line [e.line]: [html_encode(e.name)] [error_entry.make_link(viewtext)]") var/err_msg_delay - if(config) + if(config?.loaded) err_msg_delay = CONFIG_GET(number/error_msg_delay) else var/datum/config_entry/CE = /datum/config_entry/number/error_msg_delay diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm index 7139a65377a6d..940ddbef01ebe 100644 --- a/code/modules/events/sentience.dm +++ b/code/modules/events/sentience.dm @@ -82,7 +82,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( SA.key = SG.key - SA.grant_all_languages(TRUE, FALSE, FALSE) + SA.grant_all_languages(UNDERSTOOD_LANGUAGE, grant_omnitongue = FALSE, source = LANGUAGE_ATOM) SA.sentience_act() diff --git a/code/modules/food_and_drinks/plate.dm b/code/modules/food_and_drinks/plate.dm index d7a68c3567884..7bd30f14fea3a 100644 --- a/code/modules/food_and_drinks/plate.dm +++ b/code/modules/food_and_drinks/plate.dm @@ -91,7 +91,7 @@ base_icon_state = "plate_shard" force = 5 throwforce = 5 - sharpness = IS_SHARP + sharpness = SHARP /// How many variants of shard there are var/variants = 5 diff --git a/code/modules/holoparasite/abilities/lesser/babel.dm b/code/modules/holoparasite/abilities/lesser/babel.dm index 036e2c6f1c3fc..c785f72a1902d 100644 --- a/code/modules/holoparasite/abilities/lesser/babel.dm +++ b/code/modules/holoparasite/abilities/lesser/babel.dm @@ -6,7 +6,7 @@ /datum/holoparasite_ability/lesser/babelfish/apply() ..() - owner.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_HOLOPARA) + owner.grant_all_languages(source = LANGUAGE_HOLOPARA) /datum/holoparasite_ability/lesser/babelfish/remove() ..() diff --git a/code/modules/holoparasite/holoparasite_language.dm b/code/modules/holoparasite/holoparasite_language.dm index b2fe09a276ad8..5c33ca28e2adc 100644 --- a/code/modules/holoparasite/holoparasite_language.dm +++ b/code/modules/holoparasite/holoparasite_language.dm @@ -7,36 +7,30 @@ /// The parent holder of the holoparasite, which is the holder of the summoner. var/datum/holoparasite_holder/holder -/datum/language_holder/holoparasite/New(atom/owner, datum/holoparasite_holder/_holder) - if(!istype(_holder)) - CRASH("Attempted to create holoparasite language holder for [key_name(owner)] without a valid holoparasite holder!") - holder = _holder +/datum/language_holder/holoparasite/New(atom/owner, datum/holoparasite_holder/new_holder) + holder = new_holder return ..() /** * Ensures that the holoparasite can understand any language that its summoner can understand. */ -/datum/language_holder/holoparasite/has_language(language, spoken) - var/datum/language_holder/summoner_mind_language_holder = holder.owner.get_language_holder() +/datum/language_holder/holoparasite/has_language(language, flags_to_check) var/datum/language_holder/summoner_body_language_holder = holder.owner.current?.get_language_holder() - return ..() || summoner_mind_language_holder.has_language(language, spoken) || summoner_body_language_holder?.has_language(language, spoken) + return ..() || summoner_body_language_holder?.has_language(language, flags_to_check) /** * Ensures that the holoparasite can speak any language that its summoner can understand. */ /datum/language_holder/holoparasite/can_speak_language(language) - var/datum/language_holder/summoner_mind_language_holder = holder.owner.get_language_holder() var/datum/language_holder/summoner_body_language_holder = holder.owner.current?.get_language_holder() - return ..() || summoner_mind_language_holder.can_speak_language(language) || summoner_body_language_holder?.can_speak_language(language) + return ..() || summoner_body_language_holder?.can_speak_language(language) /** * Picks a random understood language, combining the holoparasite's understood languages with that of the summoner's mind and body. */ /datum/language_holder/holoparasite/get_random_understood_language() - var/datum/language_holder/summoner_mind_language_holder = holder.owner.get_language_holder() var/datum/language_holder/summoner_body_language_holder = holder.owner.current?.get_language_holder() var/list/choices = understood_languages.Copy() - choices |= summoner_mind_language_holder.understood_languages if(summoner_body_language_holder) choices |= summoner_body_language_holder.understood_languages return pick(choices) @@ -45,10 +39,8 @@ * Picks a random spoken language, combining the holoparasite's spoken languages with that of the summoner's mind and body. */ /datum/language_holder/holoparasite/get_random_spoken_language() - var/datum/language_holder/summoner_mind_language_holder = holder.owner.get_language_holder() var/datum/language_holder/summoner_body_language_holder = holder.owner.current?.get_language_holder() var/list/choices = spoken_languages.Copy() - choices |= summoner_mind_language_holder.spoken_languages if(summoner_body_language_holder) choices |= summoner_body_language_holder.spoken_languages return pick(choices) diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index 8b995fb82dafe..f213159854662 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -87,7 +87,7 @@ attack_verb_continuous = list("chops", "tears", "lacerates", "cuts") attack_verb_simple = list("chop", "tear", "lacerate", "cut") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT /obj/item/hatchet/Initialize(mapload) diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index a50627fbe99a8..2fa8559a6db82 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -57,4 +57,4 @@ if(visualsOnly) return - H.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_CURATOR) + H.grant_all_languages(source = LANGUAGE_CURATOR) diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm index 0f1bd035a3a25..0b84b8f84027f 100644 --- a/code/modules/language/codespeak.dm +++ b/code/modules/language/codespeak.dm @@ -47,7 +47,7 @@ return to_chat(user, "You start skimming through [src], and suddenly your mind is filled with codewords and responses.") - user.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) + user.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND) use_charge(user) @@ -66,7 +66,7 @@ M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.") else M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], codewords and responses flow through your mind.", "You hear smacking.") - M.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) + M.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND) use_charge(user) /obj/item/codespeak_manual/proc/use_charge(mob/user) diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index e5c6e65c03d49..d3c6a80640bb4 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -1,4 +1,4 @@ -/*!Language holders will either exist in an atom/movable or a mind. Creation of language holders happens +/*!Language holders will either exist in an atom/movable. Creation of language holders happens automatically when they are needed, for example when something tries to speak. Where a mind is available, the mind language holder will be the one "in charge". The mind holder will update its languages based on the atom holder, and will get updated as part of @@ -33,35 +33,36 @@ Key procs * [has_language](atom/movable.html#proc/has_language) * [can_speak_language](atom/movable.html#proc/can_speak_language) * [get_selected_language](atom/movable.html#proc/get_selected_language) -* [update_atom_languages](atom/movable.html#proc/update_atom_languages) */ /datum/language_holder - /// Understood languages. - var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_MIND)) - /// A list of languages that can be spoken. Tongue organ may also set limits beyond this list. + /// Lazyassoclist of all understood languages + var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) + /// Lazyassoclist of languages that can be spoken. + /// Tongue organ may also set limits beyond this list. var/list/spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) - /// A list of blocked languages. Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc. - var/list/blocked_languages = list() - /// If true, overrides tongue limitations. + /// Lazyassoclist of blocked languages. + /// Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc. + var/list/blocked_languages + /// If true, overrides tongue aforementioned limitations. var/omnitongue = FALSE /// Handles displaying the language menu UI. var/datum/language_menu/language_menu /// Currently spoken language var/selected_language /// Tracks the entity that owns the holder. - var/atom/owner + var/atom/movable/owner /// Initializes, and copies in the languages from the current atom if available. -/datum/language_holder/New(atom/_owner) - if(_owner && QDELING(_owner)) - CRASH("Langauge holder added to a qdeleting thing, what the fuck [REF(_owner)]") - owner = _owner - if(istype(owner, /datum/mind)) - var/datum/mind/M = owner - if(M.current) - update_atom_languages(M.current) - grant_language(/datum/language/metalanguage, understood=TRUE, spoken=FALSE, source=LANGUAGE_MIND) // Gets metalanguage that you can only understand +/datum/language_holder/New(atom/new_owner) + if(new_owner) + if(QDELETED(new_owner)) + CRASH("Langauge holder added to a qdeleting thing, what the fuck [text_ref(new_owner)]") + if(!ismovable(new_owner)) + CRASH("Language holder being added to a non-movable thing, this is invalid (was: [new_owner] / [new_owner.type])") + + owner = new_owner + grant_language(/datum/language/metalanguage, language_flags = ALL, source = LANGUAGE_MIND) // Gets metalanguage that you can only understand // If we have an owner, we'll set a default selected language if(owner) get_selected_language() @@ -72,54 +73,50 @@ Key procs return ..() /// Grants the supplied language. -/datum/language_holder/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_MIND) - if(understood) - if(!understood_languages[language]) - understood_languages[language] = list() - understood_languages[language] |= source +/datum/language_holder/proc/grant_language(language, language_flags = ALL, source = LANGUAGE_MIND) + if(language_flags & UNDERSTOOD_LANGUAGE) + LAZYORASSOCLIST(understood_languages, language, source) . = TRUE - if(spoken) - if(!spoken_languages[language]) - spoken_languages[language] = list() - spoken_languages[language] |= source + if(language_flags & SPOKEN_LANGUAGE) + LAZYORASSOCLIST(spoken_languages, language, source) . = TRUE + return . + /// Grants every language to understood and spoken, and gives omnitongue. -/datum/language_holder/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND) +/datum/language_holder/proc/grant_all_languages(language_flags = ALL, grant_omnitongue = TRUE, source = LANGUAGE_MIND) for(var/language in GLOB.all_languages) if(language == /datum/language/metalanguage) continue // metalanguage shouldn't be given by this method - grant_language(language, understood, spoken, source) - if(grant_omnitongue) // Overrides tongue limitations. + grant_language(language, language_flags, source) + if(grant_omnitongue) // Overrides tongue limitations. omnitongue = TRUE return TRUE /// Removes a single language or source, removing all sources returns the pre-removal state of the language. -/datum/language_holder/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL) - if(understood && understood_languages[language]) +/datum/language_holder/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL) + if(language_flags & UNDERSTOOD_LANGUAGE) if(source == LANGUAGE_ALL) - understood_languages -= language + LAZYREMOVE(understood_languages, language) else - understood_languages[language] -= source - if(!length(understood_languages[language])) - understood_languages -= language + LAZYREMOVEASSOC(understood_languages, language, source) . = TRUE - if(spoken && spoken_languages[language]) + if(language_flags & SPOKEN_LANGUAGE) if(source == LANGUAGE_ALL) - spoken_languages -= language + LAZYREMOVE(spoken_languages, language) else - spoken_languages[language] -= source - if(!length(spoken_languages[language])) - spoken_languages -= language + LAZYREMOVEASSOC(spoken_languages, language, source) . = TRUE + return . + /// Removes every language and optionally sets omnitongue false. If a non default source is supplied, only removes that source. /datum/language_holder/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE) for(var/language in GLOB.all_languages) if(language == /datum/language/metalanguage) // this language is important. Don't remove it by remove_all continue - remove_language(language, TRUE, TRUE, source) + remove_language(language, ALL, source) if(remove_omnitongue) omnitongue = FALSE return TRUE @@ -128,41 +125,41 @@ Key procs /datum/language_holder/proc/add_blocked_language(languages, source = LANGUAGE_MIND) if(!islist(languages)) languages = list(languages) + for(var/language in languages) - if(!blocked_languages[language]) - blocked_languages[language] = list() - blocked_languages[language] |= source + LAZYORASSOCLIST(blocked_languages, language, source) return TRUE /// Removes a single language or list of languages from the blocked language list. /datum/language_holder/proc/remove_blocked_language(languages, source = LANGUAGE_MIND) if(!islist(languages)) languages = list(languages) + for(var/language in languages) - if(blocked_languages[language]) - if(source == LANGUAGE_ALL) - blocked_languages -= language - else - blocked_languages[language] -= source - if(!length(blocked_languages[language])) - blocked_languages -= language + if(source == LANGUAGE_ALL) + LAZYREMOVE(blocked_languages, language) + else + LAZYREMOVEASSOC(blocked_languages, language, source) + return TRUE -/// Checks if you have the language. If spoken is true, only checks if you can speak the language. -/datum/language_holder/proc/has_language(language, spoken = FALSE) +/// Checks if you have the language passed. +/datum/language_holder/proc/has_language(language, flag_to_check = UNDERSTOOD_LANGUAGE) if(language in blocked_languages) return FALSE - if(spoken) - return language in spoken_languages - return language in understood_languages + + var/list/langs_to_check = list() + if(flag_to_check & SPOKEN_LANGUAGE) + langs_to_check |= spoken_languages + if(flag_to_check & UNDERSTOOD_LANGUAGE) + langs_to_check |= understood_languages + + return language in langs_to_check /// Checks if you can speak the language. Tongue limitations should be supplied as an argument. /datum/language_holder/proc/can_speak_language(language) - var/atom/movable/our_atom = get_atom() - var/tongue = our_atom.could_speak_language(language) - if((omnitongue || tongue) && has_language(language, TRUE)) - return TRUE - return FALSE + var/can_speak_language_path = omnitongue || owner.could_speak_language(language) + return (can_speak_language_path && has_language(language, SPOKEN_LANGUAGE)) /// Returns selected language if it can be spoken, or decides, sets and returns a new selected language if possible. /datum/language_holder/proc/get_selected_language() @@ -195,40 +192,15 @@ Key procs language_menu = new (src) language_menu.ui_interact(user) -/// Gets the atom, since we some times need to check if the tongue has limitations. -/datum/language_holder/proc/get_atom() - if(owner) - if(istype(owner, /datum/mind)) - var/datum/mind/M = owner - return M.current - return owner - return FALSE - -/// Empties out the atom specific languages and updates them according to the supplied atoms language holder. -/datum/language_holder/proc/update_atom_languages(atom/movable/thing) - var/datum/language_holder/from_atom = thing.get_language_holder(FALSE) //Gets the atoms language holder - if(from_atom == src) //This could happen if called on an atom without a mind. - return FALSE - for(var/language in understood_languages) - remove_language(language, TRUE, FALSE, LANGUAGE_ATOM) - for(var/language in spoken_languages) - remove_language(language, FALSE, TRUE, LANGUAGE_ATOM) - for(var/language in blocked_languages) - remove_blocked_language(language, LANGUAGE_ATOM) - - copy_languages(from_atom, blocked=TRUE) // full-copy - get_selected_language() - return TRUE - /// Copies all languages from the supplied atom/language holder. Source should be overridden when you /// do not want the language overwritten by later atom updates or want to avoid blocked languages. /datum/language_holder/proc/copy_languages(var/datum/language_holder/from_holder, source_override=FALSE, spoken=TRUE, understood=TRUE, blocked=FALSE) if(understood) for(var/language in from_holder.understood_languages) - grant_language(language, TRUE, FALSE, source_override || from_holder.understood_languages[language]) // if you don't have 'source_override' argument, source from 'from_holder' will be used. + grant_language(language, UNDERSTOOD_LANGUAGE, source_override || from_holder.understood_languages[language]) // if you don't have 'source_override' argument, source from 'from_holder' will be used. if(spoken) for(var/language in from_holder.spoken_languages) - grant_language(language, FALSE, TRUE, source_override || from_holder.spoken_languages[language]) + grant_language(language, SPOKEN_LANGUAGE, source_override || from_holder.spoken_languages[language]) if(blocked) // blocked is set to FALSE by default because there's no reason to copy blocked languages in standard situations. // 'blocked=TRUE' is recommanded when 'source_override=FALSE' because it means full-copy @@ -236,55 +208,117 @@ Key procs add_blocked_language(language, source_override || from_holder.blocked_languages[language]) return TRUE +/// Transfers all mind languages to the supplied language holder. +/datum/language_holder/proc/transfer_mind_languages(datum/language_holder/to_holder) + for(var/language in understood_languages) + if(LANGUAGE_MIND in understood_languages[language]) + remove_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_MIND) + to_holder.grant_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_MIND) + for(var/language in spoken_languages) + if(LANGUAGE_MIND in spoken_languages[language]) + remove_language(language, SPOKEN_LANGUAGE, LANGUAGE_MIND) + to_holder.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_MIND) + for(var/language in blocked_languages) + if(LANGUAGE_MIND in blocked_languages[language]) + remove_blocked_language(language, LANGUAGE_MIND) + to_holder.add_blocked_language(language, LANGUAGE_MIND) + + if(owner) + get_selected_language() + if(to_holder.owner) + to_holder.get_selected_language() + +/// A global assoc list containing prototypes of all language holders +/// [Language holder typepath] to [language holder instance] +/// Used for easy reference of what can speak what without needing to constantly recreate language holders. +GLOBAL_LIST_INIT(prototype_language_holders, init_language_holder_prototypes()) -//************************************************ -//* Specific language holders * -//* Use atom language sources only. * -//************************************************/ +/// Inits the global list of language holder prototypes. +/proc/init_language_holder_prototypes() + var/list/prototypes = list() + for(var/holdertype in typesof(/datum/language_holder)) + prototypes[holdertype] = new holdertype() + return prototypes + +/* + * Specific language holders presets + * + * Prefer to use [LANGUGAE_ATOM]. Atom languages will stick through species changes but not mindswaps. + */ /datum/language_holder/alien - understood_languages = list(/datum/language/xenocommon = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/xenocommon = list(LANGUAGE_ATOM)) - blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/xenocommon = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/xenocommon = list(LANGUAGE_ATOM) + ) + blocked_languages = list( + /datum/language/common = list(LANGUAGE_ATOM) + ) /datum/language_holder/apid - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/apidite = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/apidite = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/apidite = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/apidite = list(LANGUAGE_ATOM) + ) /datum/language_holder/clockmob - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/ratvar = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/ratvar = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/ratvar = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/ratvar = list(LANGUAGE_ATOM) + ) /datum/language_holder/construct - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/narsie = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/narsie = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/narsie = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/narsie = list(LANGUAGE_ATOM), + ) /datum/language_holder/drone understood_languages = list(/datum/language/drone = list(LANGUAGE_ATOM), - /datum/language/machine = list(LANGUAGE_ATOM)) + /datum/language/machine = list(LANGUAGE_ATOM)) spoken_languages = list(/datum/language/drone = list(LANGUAGE_ATOM)) blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/drone/syndicate - blocked_languages = list() + blocked_languages = null + +/datum/language_holder/human_basic + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM) + ) /datum/language_holder/jelly - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/slime = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/slime = list(LANGUAGE_ATOM), + ) /datum/language_holder/oozeling understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) + /datum/language/slime = list(LANGUAGE_ATOM)) spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) + /datum/language/slime = list(LANGUAGE_ATOM)) /datum/language_holder/lightbringer understood_languages = list(/datum/language/slime = list(LANGUAGE_ATOM)) @@ -292,10 +326,14 @@ Key procs blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/lizard - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/draconic = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/draconic = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM), + ) /datum/language_holder/lizard/ash understood_languages = list(/datum/language/draconic = list(LANGUAGE_ATOM)) @@ -303,19 +341,29 @@ Key procs blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/monkey - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/monkey = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/monkey = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/monkey = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/monkey = list(LANGUAGE_ATOM), + ) /datum/language_holder/mushroom - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/mushroom = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/mushroom = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/mushroom = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/mushroom = list(LANGUAGE_ATOM), + ) /datum/language_holder/slime - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/slime = list(LANGUAGE_ATOM), + ) spoken_languages = list(/datum/language/slime = list(LANGUAGE_ATOM)) /datum/language_holder/swarmer @@ -330,7 +378,7 @@ Key procs /datum/language_holder/spider understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/buzzwords = list(LANGUAGE_ATOM)) + /datum/language/buzzwords = list(LANGUAGE_ATOM)) spoken_languages = list(/datum/language/buzzwords = list(LANGUAGE_ATOM)) /datum/language_holder/venus @@ -339,95 +387,143 @@ Key procs blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/synthetic - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/uncommon = list(LANGUAGE_ATOM), - /datum/language/machine = list(LANGUAGE_ATOM), - /datum/language/draconic = list(LANGUAGE_ATOM), - /datum/language/moffic = list(LANGUAGE_ATOM), - /datum/language/calcic = list(LANGUAGE_ATOM), - /datum/language/voltaic = list(LANGUAGE_ATOM), - /datum/language/apidite = list(LANGUAGE_ATOM), - /datum/language/sonus = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/uncommon = list(LANGUAGE_ATOM), - /datum/language/machine = list(LANGUAGE_ATOM), - /datum/language/draconic = list(LANGUAGE_ATOM), - /datum/language/moffic = list(LANGUAGE_ATOM), - /datum/language/calcic = list(LANGUAGE_ATOM), - /datum/language/voltaic = list(LANGUAGE_ATOM), - /datum/language/apidite = list(LANGUAGE_ATOM), - /datum/language/sonus = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/uncommon = list(LANGUAGE_ATOM), + /datum/language/machine = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM), + /datum/language/moffic = list(LANGUAGE_ATOM), + /datum/language/calcic = list(LANGUAGE_ATOM), + /datum/language/voltaic = list(LANGUAGE_ATOM), + /datum/language/apidite = list(LANGUAGE_ATOM), + /datum/language/sonus = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/uncommon = list(LANGUAGE_ATOM), + /datum/language/machine = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM), + /datum/language/moffic = list(LANGUAGE_ATOM), + /datum/language/calcic = list(LANGUAGE_ATOM), + /datum/language/voltaic = list(LANGUAGE_ATOM), + /datum/language/apidite = list(LANGUAGE_ATOM), + /datum/language/sonus = list(LANGUAGE_ATOM) + ) /datum/language_holder/moth - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/moffic = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/moffic = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/moffic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/moffic = list(LANGUAGE_ATOM), + ) /datum/language_holder/skeleton - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/calcic = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/calcic = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/calcic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/calcic = list(LANGUAGE_ATOM), + ) /datum/language_holder/ethereal - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/voltaic = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/voltaic = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/voltaic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/voltaic = list(LANGUAGE_ATOM), + ) /datum/language_holder/golem - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/terrum = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/terrum = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/terrum = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/terrum = list(LANGUAGE_ATOM) + ) /datum/language_holder/golem/bone - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/terrum = list(LANGUAGE_ATOM), - /datum/language/calcic = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/terrum = list(LANGUAGE_ATOM), - /datum/language/calcic = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/terrum = list(LANGUAGE_ATOM), + /datum/language/calcic = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/terrum = list(LANGUAGE_ATOM), + /datum/language/calcic = list(LANGUAGE_ATOM) + ) /datum/language_holder/golem/runic - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/terrum = list(LANGUAGE_ATOM), - /datum/language/narsie = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/terrum = list(LANGUAGE_ATOM), - /datum/language/narsie = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/terrum = list(LANGUAGE_ATOM), + /datum/language/narsie = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/terrum = list(LANGUAGE_ATOM), + /datum/language/narsie = list(LANGUAGE_ATOM) + ) /datum/language_holder/fly - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/buzzwords = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/buzzwords = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/buzzwords = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/buzzwords = list(LANGUAGE_ATOM), + ) /datum/language_holder/diona - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/sylvan = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/sylvan = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/sylvan = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/sylvan = list(LANGUAGE_ATOM), + ) /datum/language_holder/shadowpeople - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/shadowtongue = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/shadowtongue = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/shadowtongue = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/shadowtongue = list(LANGUAGE_ATOM), + ) /datum/language_holder/psyphoza - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/sonus = list(LANGUAGE_ATOM), - /datum/language/sylvan = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/sonus = list(LANGUAGE_ATOM), - /datum/language/sylvan = list(LANGUAGE_ATOM)) + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/sonus = list(LANGUAGE_ATOM), + /datum/language/sylvan = list(LANGUAGE_ATOM) + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/sonus = list(LANGUAGE_ATOM), + /datum/language/sylvan = list(LANGUAGE_ATOM) + ) /datum/language_holder/empty - understood_languages = list() - spoken_languages = list() + understood_languages = null + spoken_languages = null + +/datum/language_holder/universal + understood_languages = null + spoken_languages = null /datum/language_holder/universal/New() - ..() + . = ..() grant_all_languages() diff --git a/code/modules/language/language_menu.dm b/code/modules/language/language_menu.dm index 47af82f578924..fbc9986768295 100644 --- a/code/modules/language/language_menu.dm +++ b/code/modules/language/language_menu.dm @@ -8,7 +8,6 @@ language_holder = null . = ..() - /datum/language_menu/ui_state(mob/user) return GLOB.language_menu_state @@ -43,46 +42,40 @@ var/list/data = list() var/is_admin = check_rights_for(user.client, R_ADMIN) || check_rights_for(user.client, R_DEBUG) - var/atom/movable/AM = language_holder.get_atom() - if(isliving(AM)) - data["is_living"] = TRUE - else - data["is_living"] = FALSE + var/atom/movable/speaker = language_holder.owner + data["is_living"] = isliving(speaker) data["known_languages"] = list() - for(var/lang in GLOB.all_languages) - var/result = language_holder.has_language(lang) || language_holder.has_language(lang, TRUE) + for(var/datum/language/language as anything in GLOB.all_languages) + var/result = language_holder.has_language(language) || language_holder.has_language(language, SPOKEN_LANGUAGE) if(!result) continue - var/datum/language/language = lang - var/list/L = list() + var/list/lang_data = list() - L["name"] = initial(language.name) - L["is_default"] = (language == language_holder.selected_language) - if(AM) - L["can_speak"] = AM.can_speak_language(language) - L["can_understand"] = AM.has_language(language) + lang_data["name"] = initial(language.name) + lang_data["is_default"] = (language == language_holder.selected_language) + if(speaker) + lang_data["can_speak"] = speaker.can_speak_language(language) + lang_data["can_understand"] = speaker.has_language(language) - if(lang == /datum/language/metalanguage) // metalanguage is only visible to admins + if(language == /datum/language/metalanguage) // metalanguage is only visible to admins if(!(is_admin || HAS_TRAIT(user, TRAIT_METALANGUAGE_KEY_ALLOWED))) continue - data["known_languages"] += list(L) + UNTYPED_LIST_ADD(data["known_languages"], lang_data) - if(is_admin || isobserver(AM)) + if(is_admin || isobserver(speaker)) data["admin_mode"] = TRUE data["omnitongue"] = language_holder.omnitongue - data["unknown_languages"] = list() - for(var/lang in GLOB.all_languages) - if(language_holder.has_language(lang) || language_holder.has_language(lang, TRUE)) + for(var/datum/language/language as anything in GLOB.all_languages) + if(language_holder.has_language(language) || language_holder.has_language(language, TRUE)) continue - var/datum/language/language = lang - var/list/L = list() + var/list/lang_data = list() - L["name"] = initial(language.name) + lang_data["name"] = initial(language.name) - data["unknown_languages"] += list(L) + UNTYPED_LIST_ADD(data["unknown_languages"], lang_data) else data["admin_mode"] = null data["omnitongue"] = null @@ -90,18 +83,17 @@ return data /datum/language_menu/ui_act(action, params) - if(..()) + . = ..() + if(.) return var/mob/user = usr - var/atom/movable/AM = language_holder.get_atom() - + var/atom/movable/speaker = language_holder.owner + var/is_admin = check_rights_for(user.client, R_ADMIN) || check_rights_for(user.client, R_DEBUG) var/language_name = params["language_name"] var/datum/language/language_datum - for(var/lang in GLOB.all_languages) - var/datum/language/language = lang + for(var/datum/language/language as anything in GLOB.all_languages) if(language_name == initial(language.name)) language_datum = language - var/is_admin = check_rights_for(user.client, R_ADMIN) || check_rights_for(user.client, R_DEBUG) switch(action) if("select_default") @@ -111,67 +103,68 @@ language_datum != /datum/language/metalanguage && \ !HAS_TRAIT(user, TRAIT_METALANGUAGE_KEY_ALLOWED) && \ !is_admin) - var/no = alert(user, "You're giving up your power to speak in a powerful language that everyone understands. Do you really wish to do that?", "WARNING!", "Yes", "No") - if(no != "Yes") + var/metachoice = tgui_alert(user, "You're giving up your power to speak in a powerful language that everyone understands. Do you really wish to do that?", "WARNING!", list("Yes", "No")) + if(metachoice != "Yes") return - if(AM.can_speak_language(language_datum)) + if(speaker.can_speak_language(language_datum)) language_holder.selected_language = language_datum . = TRUE if("grant_language") - if((is_admin || isobserver(AM)) && language_datum) + if((is_admin || isobserver(speaker)) && language_datum) var/list/choices = list("Only Spoken", "Only Understood", "Both") - var/choice = input(user,"How do you want to add this language?","[language_datum]",null) as null|anything in choices - var/spoken = FALSE - var/understood = FALSE + var/choice = tgui_input_list(user, "How do you want to add this language?", "[language_datum]", choices) + if(isnull(choice)) + return + var/adding_flags = NONE switch(choice) if("Only Spoken") - spoken = TRUE + adding_flags |= SPOKEN_LANGUAGE if("Only Understood") - understood = TRUE + adding_flags |= UNDERSTOOD_LANGUAGE if("Both") - spoken = TRUE - understood = TRUE - if(language_holder.blocked_languages.Find(language_datum)) - var/blocked_language_choice = alert(user,"The [language_name] language is in this mob's list of blocked languages. Do you wish to remove it so you may give the mob the [language_name] language?","[language_datum]", "Yes", "No") - if(blocked_language_choice == "Yes") - language_holder.remove_blocked_language(language_datum) - message_admins("[key_name_admin(user)] removed the [language_name] language from [key_name_admin(AM)]'s blocked languages list.") - log_admin("[key_name(user)] removed the language [language_name] from [key_name(AM)]'s blocked languages list.") - language_holder.grant_language(language_datum, understood, spoken) - if(spoken && language_datum == /datum/language/metalanguage) - var/yes = alert(user, "You have added speakable Metalanguage. Do you wish to give them a trait that they can use language key(,`) to say that? Otherwise, they'll have no way to say that, or, instead, you should set their default language to metalanguage.", "Give Metalangauge trait?", "Yes", "No") + adding_flags |= ALL + if(LAZYACCESS(language_holder.blocked_languages, language_datum)) + choice = tgui_alert(user, "Do you want to lift the blockage that's also preventing the language to be spoken or understood?", "[language_datum]", list("Yes", "No")) + if(choice == "Yes") + language_holder.remove_blocked_language(language_datum, LANGUAGE_ALL) + message_admins("[key_name_admin(user)] removed the [language_name] language from [key_name_admin(speaker)]'s blocked languages list.") + log_admin("[key_name(user)] removed the language [language_name] from [key_name(speaker)]'s blocked languages list.") + language_holder.grant_language(language_datum, adding_flags) + if((adding_flags & SPOKEN_LANGUAGE) && (language_datum == /datum/language/metalanguage)) + var/yes = tgui_alert(user, "You have added speakable Metalanguage. Do you wish to give them a trait that they can use language key(,`) to say that? Otherwise, they'll have no way to say that, or, instead, you should set their default language to metalanguage.", "Give Metalangauge trait?", list("Yes", "No")) if(yes == "Yes") ADD_TRAIT(user, TRAIT_METALANGUAGE_KEY_ALLOWED, "lang_added_by_admin") if(is_admin) - message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(AM)].") - log_admin("[key_name(user)] granted the language [language_name] to [key_name(AM)].") + message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(speaker)].") + log_admin("[key_name(user)] granted the language [language_name] to [key_name(speaker)].") . = TRUE if("remove_language") - if((is_admin || isobserver(AM)) && language_datum) + if((is_admin || isobserver(speaker)) && language_datum) var/list/choices = list("Only Spoken", "Only Understood", "Both") - var/choice = input(user,"Which part do you wish to remove?","[language_datum]",null) as null|anything in choices - var/spoken = FALSE - var/understood = FALSE + var/choice = tgui_input_list(user, "Which part do you wish to remove?", "[language_datum]", choices) + if(isnull(choice)) + return + var/removing_flags = NONE switch(choice) if("Only Spoken") - spoken = TRUE + removing_flags |= SPOKEN_LANGUAGE if("Only Understood") - understood = TRUE + removing_flags |= UNDERSTOOD_LANGUAGE if("Both") - spoken = TRUE - understood = TRUE - language_holder.remove_language(language_datum, understood, spoken) - if(spoken && language_datum == /datum/language/metalanguage) + removing_flags |= ALL + + language_holder.remove_language(language_datum, removing_flags) + if((removing_flags & SPOKEN_LANGUAGE) && (language_datum == /datum/language/metalanguage)) REMOVE_TRAIT(user, TRAIT_METALANGUAGE_KEY_ALLOWED, "lang_added_by_admin") if(is_admin) - message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(AM)].") - log_admin("[key_name(user)] removed the language [language_name] to [key_name(AM)].") + message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(speaker)].") + log_admin("[key_name(user)] removed the language [language_name] to [key_name(speaker)].") . = TRUE if("toggle_omnitongue") - if(is_admin || isobserver(AM)) + if(is_admin || isobserver(speaker)) language_holder.omnitongue = !language_holder.omnitongue if(is_admin) - message_admins("[key_name_admin(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that they know) of [key_name_admin(AM)].") - log_admin("[key_name(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that_they know) of [key_name(AM)].") + message_admins("[key_name_admin(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that they know) of [key_name_admin(speaker)].") + log_admin("[key_name(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that_they know) of [key_name(speaker)].") . = TRUE diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 7199aa1e6b220..105deac6bf761 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -18,7 +18,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("smashes", "crushes", "cleaves", "chops", "pulps") attack_verb_simple = list("smash", "crush", "cleave", "chop", "pulp") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_CUT actions_types = list(/datum/action/item_action/toggle_light) light_system = MOVABLE_LIGHT diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm index f2a5a5add17c3..e835264d1c353 100644 --- a/code/modules/mining/equipment/mining_tools.dm +++ b/code/modules/mining/equipment/mining_tools.dm @@ -128,7 +128,7 @@ custom_materials = list(/datum/material/iron=50) attack_verb_continuous = list("bashes", "batters", "bludgeons", "whacks") attack_verb_simple = list("bash", "batter", "bludgeon", "whack") - sharpness = IS_SHARP + sharpness = SHARP /obj/item/shovel/Initialize(mapload) . = ..() diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index ff5b9ac353ce1..8083967f78af0 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -4,7 +4,7 @@ icon_state = "away" dynamic_lighting = DYNAMIC_LIGHTING_ENABLED requires_power = FALSE - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY area_flags = BLOBS_ALLOWED | UNIQUE_AREA //Survival Capsule diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 2ec126b7947dd..c2c8abb594648 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -582,7 +582,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/shared_storage/blue) if(!user.can_read(src)) return FALSE to_chat(user, "You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops.") - user.grant_all_languages() + user.grant_all_languages(source = LANGUAGE_BABEL) new /obj/effect/decal/cleanable/ash(get_turf(user)) qdel(src) @@ -765,7 +765,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/shared_storage/blue) hitsound = 'sound/weapons/bladeslice.ogg' hitsound_on = 'sound/weapons/bladeslice.ogg' w_class = WEIGHT_CLASS_BULKY - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT faction_bonus_force = 45 nemesis_factions = list("mining", "boss") @@ -859,7 +859,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/shared_storage/blue) lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' flags_1 = CONDUCT_1 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT w_class = WEIGHT_CLASS_BULKY force = 1 diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 3b46d8299efa2..bd793766da4f6 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -78,6 +78,7 @@ var/hit_amount = (100 - armour_block) / 100 add_bleeding(I.bleed_force * hit_amount) if(I.force) + var/limb_damage = affecting.get_damage() //We need to save this for later to simplify dismemberment var/armour_block = run_armor_check(affecting, MELEE, armour_penetration = I.armour_penetration) apply_damage(I.force, I.damtype, affecting, armour_block) if(I.damtype == BRUTE && (IS_ORGANIC_LIMB(affecting))) @@ -102,18 +103,26 @@ to_chat(src, "The heat from [I] cauterizes your bleeding!") playsound(src, 'sound/surgery/cautery2.ogg', 70) - //dismemberment - var/dismemberthreshold = (((affecting.max_damage * 2) / max(I.is_sharp(), 0.5)) - (affecting.get_damage() + ((I.w_class - 3) * 10) + ((I.attack_weight - 1) * 15))) - if(HAS_TRAIT(src, TRAIT_EASYDISMEMBER)) - dismemberthreshold -= 50 - if(I.is_sharp()) - dismemberthreshold = min(((affecting.max_damage * 2) - affecting.get_damage()), dismemberthreshold) //makes it so limbs wont become immune to being dismembered if the item is sharp - if(stat == DEAD) - dismemberthreshold = dismemberthreshold / 3 - if(I.force >= dismemberthreshold && I.force >= 10) - if(affecting.dismember(I.damtype)) - I.add_mob_blood(src) - playsound(get_turf(src), I.get_dismember_sound(), 80, 1) + var/dismember_limb = FALSE + var/weapon_sharpness = I.is_sharp() + + if(((HAS_TRAIT(src, TRAIT_EASYDISMEMBER) && limb_damage) || (weapon_sharpness == SHARP_DISMEMBER_EASY)) && prob(I.force)) + dismember_limb = TRUE + //Easy dismemberment on the mob allows even blunt weapons to potentially delimb, but only if the limb is already damaged + //Certain weapons are so sharp/strong they have a chance to cleave right through a limb without following the normal restrictions + + else if(weapon_sharpness > SHARP || (weapon_sharpness == SHARP && stat == DEAD)) + //Delimbing cannot normally occur with blunt weapons + //You also aren't cutting someone's arm off with a scalpel unless they're already dead + + if(limb_damage >= affecting.max_damage) + dismember_limb = TRUE + //You can only cut a limb off if it is already damaged enough to be fully disabled + + if(dismember_limb && (affecting.body_zone != BODY_ZONE_HEAD || stat != CONSCIOUS) && affecting.dismember(I.damtype)) + I.add_mob_blood(src) + playsound(get_turf(src), I.get_dismember_sound(), 80, 1) + return TRUE //successful attack /mob/living/carbon/send_item_attack_message(obj/item/I, mob/living/user, hit_area, obj/item/bodypart/hit_bodypart) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 06d5bf93df7b0..57b1155aed6bf 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -32,7 +32,10 @@ GLOBAL_LIST_EMPTY(features_by_species) var/skinned_type var/list/no_equip = list() // slots the race can't equip stuff to var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids - var/species_language_holder = /datum/language_holder + /// What languages this species can understand and say. + /// Use a [language holder datum][/datum/language_holder] typepath in this var. + /// Should never be null. + var/datum/language_holder/species_language_holder = /datum/language_holder/human_basic /** * Visible CURRENT bodyparts that are unique to a species. * DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK @@ -481,6 +484,16 @@ GLOBAL_LIST_EMPTY(features_by_species) C.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, multiplicative_slowdown=speedmod) + // All languages associated with this language holder are added with source [LANGUAGE_SPECIES] + // rather than source [LANGUAGE_ATOM], so we can track what to remove if our species changes again + var/datum/language_holder/gaining_holder = GLOB.prototype_language_holders[species_language_holder] + for(var/language in gaining_holder.understood_languages) + C.grant_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_SPECIES) + for(var/language in gaining_holder.spoken_languages) + C.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_SPECIES) + for(var/language in gaining_holder.blocked_languages) + C.add_blocked_language(language, LANGUAGE_SPECIES) + SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) @@ -511,6 +524,16 @@ GLOBAL_LIST_EMPTY(features_by_species) for(var/i in inherent_factions) C.faction -= i C.remove_movespeed_modifier(/datum/movespeed_modifier/species) + + // Removes all languages previously associated with [LANGUAGE_SPECIES], gaining our new species will add new ones back + var/datum/language_holder/losing_holder = GLOB.prototype_language_holders[species_language_holder] + for(var/language in losing_holder.understood_languages) + C.remove_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_SPECIES) + for(var/language in losing_holder.spoken_languages) + C.remove_language(language, SPOKEN_LANGUAGE, LANGUAGE_SPECIES) + for(var/language in losing_holder.blocked_languages) + C.remove_blocked_language(language, LANGUAGE_SPECIES) + SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src) /datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour) @@ -1773,6 +1796,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/armor_block = H.run_armor_check(affecting, MELEE, "Your armor has protected your [hit_area]!", "Your armor has softened a hit to your [hit_area]!",I.armour_penetration) var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) + var/limb_damage = affecting.get_damage() //We need to save this for later to simplify dismemberment apply_damage(I.force, I.damtype, def_zone, armor_block, H) if (I.bleed_force) @@ -1808,17 +1832,25 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!I.force) return 0 //item force is zero - //dismemberment - var/dismemberthreshold = ((affecting.max_damage * 2) - affecting.get_damage()) //don't take the current hit into account. - var/attackforce = (((I.w_class - 3) * 5) + ((I.attack_weight - 1) * 14) + ((I.is_sharp()-1) * 20)) //all the variables that go into ripping off a limb in one handy package. Force is absent because it's already been taken into account by the limb being damaged - if(HAS_TRAIT(src, TRAIT_EASYDISMEMBER)) - dismemberthreshold -= 30 - if(I.is_sharp()) - attackforce = max(attackforce, I.force) - if(attackforce >= dismemberthreshold && I.force >= 10) - if(affecting.dismember(I.damtype)) - I.add_mob_blood(H) - playsound(get_turf(H), I.get_dismember_sound(), 80, 1) + var/dismember_limb = FALSE + var/weapon_sharpness = I.is_sharp() + + if(((HAS_TRAIT(H, TRAIT_EASYDISMEMBER) && limb_damage) || (weapon_sharpness == SHARP_DISMEMBER_EASY)) && prob(I.force)) + dismember_limb = TRUE + //Easy dismemberment on the mob allows even blunt weapons to potentially delimb, but only if the limb is already damaged + //Certain weapons are so sharp/strong they have a chance to cleave right through a limb without following the normal restrictions + + else if(weapon_sharpness > SHARP || (weapon_sharpness == SHARP && H.stat == DEAD)) + //Delimbing cannot normally occur with blunt weapons + //You also aren't cutting someone's arm off with a scalpel unless they're already dead + + if(limb_damage >= affecting.max_damage) + dismember_limb = TRUE + //You can only cut a limb off if it is already damaged enough to be fully disabled + + if(dismember_limb && (affecting.body_zone != BODY_ZONE_HEAD || H.stat != CONSCIOUS) && affecting.dismember(I.damtype)) + I.add_mob_blood(H) + playsound(get_turf(H), I.get_dismember_sound(), 80, 1) if(I.damtype == BRUTE && (I.force >= max(10, armor_block) && hit_area == BODY_ZONE_HEAD)) if(!I.is_sharp() && H.mind && H.stat == CONSCIOUS && H != user && (H.health - (I.force * I.attack_weight)) <= 0) // rev deconversion through blunt trauma. @@ -2937,21 +2969,23 @@ GLOBAL_LIST_EMPTY(features_by_species) * Returns a list containing perks, or an empty list. */ /datum/species/proc/create_pref_language_perk() - var/list/to_add = list() // Grab galactic common as a path, for comparisons var/datum/language/common_language = /datum/language/common // Now let's find all the languages they can speak that aren't common var/list/bonus_languages = list() - var/datum/language_holder/temp_holder = new species_language_holder() - for(var/datum/language/language_type as anything in temp_holder.spoken_languages) + var/datum/language_holder/basic_holder = GLOB.prototype_language_holders[species_language_holder] + for(var/datum/language/language_type as anything in basic_holder.spoken_languages) if(ispath(language_type, common_language)) continue bonus_languages += initial(language_type.name) - // If we have any languages we can speak: create a perk for them all - if(length(bonus_languages)) + if(!length(bonus_languages)) + return // You're boring + + var/list/to_add = list() + if(common_language in basic_holder.spoken_languages) to_add += list(list( SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, SPECIES_PERK_ICON = "comment", @@ -2959,7 +2993,13 @@ GLOBAL_LIST_EMPTY(features_by_species) SPECIES_PERK_DESC = "Alongside [initial(common_language.name)], [plural_form] gain the ability to speak [english_list(bonus_languages)].", )) - qdel(temp_holder) + else + to_add += list(list( + SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, + SPECIES_PERK_ICON = "comment", + SPECIES_PERK_NAME = "Foreign Speaker", + SPECIES_PERK_DESC = "[plural_form] may not speak [initial(common_language.name)], but they can speak [english_list(bonus_languages)].", + )) return to_add diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index 17a6a73e58717..b32ddee29e193 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -225,7 +225,7 @@ righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' item_flags = ABSTRACT | DROPDEL | ISWEAPON w_class = WEIGHT_CLASS_HUGE - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force = BLEED_DEEP_WOUND /obj/item/light_eater/Initialize(mapload) diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 337cba0d5413e..66175a6d3eb75 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -42,12 +42,12 @@ /mob/living/carbon/human/set_drugginess(amount) ..() if(!amount) - remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_DRUGGY) + remove_language(/datum/language/beachbum, source = LANGUAGE_DRUGGY) /mob/living/carbon/human/adjust_drugginess(amount) ..() if(!dna.check_mutation(STONER)) if(druggy) - grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_DRUGGY) + grant_language(/datum/language/beachbum, source = LANGUAGE_DRUGGY) else - remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_DRUGGY) + remove_language(/datum/language/beachbum, source = LANGUAGE_DRUGGY) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 9cd3a1486c1ba..8803ff19701e5 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -736,31 +736,36 @@ generate/load female uniform sprites matching all previously decided variables standing = center_image(standing, isinhands ? inhand_x_dimension : worn_x_dimension, isinhands ? inhand_y_dimension : worn_y_dimension) - //Handle held offsets - var/mob/M = loc - if(istype(M)) - var/list/L = get_held_offsets() - if(L) - standing.pixel_x += L["x"] //+= because of center()ing - standing.pixel_y += L["y"] + //Worn offsets + var/list/offsets = get_worn_offsets(isinhands) + standing.pixel_x += offsets[1] + standing.pixel_y += offsets[2] standing.alpha = alpha standing.color = color return standing -/obj/item/proc/get_held_offsets() - var/list/L - if(ismob(loc)) - if(ishuman(loc)) - var/mob/living/carbon/human/H = loc - L = H.dna?.species.get_item_offsets_for_index(src) - if(L) - return L - var/mob/M = loc - L = M.get_item_offsets_for_index(M.get_held_index_of_item(src)) - - return L +/// Returns offsets used for equipped item overlays in list(px_offset,py_offset) form. +/obj/item/proc/get_worn_offsets(isinhands) + . = list(0,0) //(px,py) + if(isinhands) + //Handle held offsets + var/mob/holder = loc + var/list/offsets + if(ismob(loc)) + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + offsets = H.dna?.species.get_item_offsets_for_index(src) + if(offsets) + return offsets + if(istype(holder)) + offsets = holder.get_item_offsets_for_index(holder.get_held_index_of_item(src)) + if(offsets) + .[1] = offsets["x"] + .[2] = offsets["y"] + else + .[2] = worn_y_offset //Can't think of a better way to do this, sadly diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm index 398f794bac0da..18e96feca1a30 100644 --- a/code/modules/mob/living/carbon/say.dm +++ b/code/modules/mob/living/carbon/say.dm @@ -18,10 +18,10 @@ return FALSE return ..() -/mob/living/carbon/could_speak_language(datum/language/dt) - if(CHECK_BITFIELD(initial(dt.flags), TONGUELESS_SPEECH)) +/mob/living/carbon/could_speak_language(datum/language/language_path) + if(CHECK_BITFIELD(initial(language_path.flags), TONGUELESS_SPEECH)) return TRUE - var/obj/item/organ/tongue/T = getorganslot(ORGAN_SLOT_TONGUE) - if(T) - return T.could_speak_language(dt) + var/obj/item/organ/tongue/spoken_with = getorganslot(ORGAN_SLOT_TONGUE) + if(spoken_with) + return spoken_with.could_speak_language(language_path) return FALSE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index e182215eff8d8..d44cc72c47cd7 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1309,6 +1309,7 @@ buckled.unbuckle_mob(src, force = TRUE) if(has_buckled_mobs()) unbuckle_all_mobs(force = TRUE) + refresh_gravity() . = ..() if(.) if(client) diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 25b8815ef6b45..d8ef6435e45ab 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -24,7 +24,7 @@ var/area/old_area = get_area(old_turf) var/area/new_area = get_area(new_turf) // If the area gravity has changed, then it's possible that our state has changed, so update - if(old_area.has_gravity != new_area.has_gravity) + if(old_area.default_gravity != new_area.default_gravity) refresh_gravity() /mob/living/onTransitZ(old_z, new_z, same_z_layer, notify_contents) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index f53dccfad0991..78fcdc3b789c2 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -124,10 +124,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return TRUE if(!language) // get_message_mods() proc finds a language key, and add the language to LANGUAGE_EXTENSION - language = message_mods[LANGUAGE_EXTENSION] - - if(!language) // there's no language argument and LANGUAGE_EXTENSION has no language. failsafe. - language = get_selected_language() + language = message_mods[LANGUAGE_EXTENSION] || get_selected_language() // if you add a new language that works like everyone doesn't understand (i.e. anti-metalanguage), add an additional condition after this // i.e.) if(!language) language = /datum/language/nobody_understands @@ -259,8 +256,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list( var/eavesdrop_range = 0 if(message_mods[WHISPER_MODE]) //If we're whispering eavesdrop_range = EAVESDROP_EXTRA_RANGE + var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source, SEE_INVISIBLE_MAXIMUM) var/list/the_dead = list() + for(var/mob/M as() in GLOB.player_list) if(!M) //yogs continue //yogs | null in player_list for whatever reason :shrug: @@ -434,12 +433,3 @@ GLOBAL_LIST_INIT(department_radio_keys, list( /mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced) - -/mob/living/get_language_holder(shadow=TRUE) - if(mind && shadow) - // Mind language holders shadow mob holders. - . = mind.get_language_holder() - if(.) - return . - - . = ..() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index d5ac9e90095f7..b355c0c9f4864 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -629,19 +629,21 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/silicon/ai) if(incapacitated()) return + var/mob/user = src var/input - switch(alert("Would you like to select a hologram based on a crew member, an animal, or switch to a unique avatar?",,"Crew Member","Unique","Animal")) + var/list/hologram_choice = list("Crew Member","Unique","Animal") + switch(tgui_alert(user, "Would you like to select a hologram based on a crew member, an animal, or switch to a unique avatar?", "Choices", hologram_choice)) if("Crew Member") var/list/personnel_list = list() - for(var/datum/record/crew/record in GLOB.manifest.locked)//Look in data core locked. + for(var/datum/record/locked/record in GLOB.manifest.locked)//Look in data core locked. personnel_list["[record.name]: [record.rank]"] = record.character_appearance//Pull names, rank, and image. if(!length(personnel_list)) alert("No suitable records found. Aborting.") return - if(personnel_list.len) - input = input("Select a crew member:") as null|anything in sort_list(personnel_list) + if(length(personnel_list)) + input = tgui_input_list(user, "Select a crew member", "AI Hologram Selection", sort_list(personnel_list)) var/mutable_appearance/character_icon = personnel_list[input] if(character_icon) qdel(holo_icon)//Clear old icon so we're not storing it in memory. @@ -667,7 +669,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/silicon/ai) "spider" = 'icons/mob/animal.dmi' ) - input = input("Please select a hologram:") as null|anything in sort_list(icon_list) + input = tgui_input_list(user, "Please select a hologram:", "Animal Choice", sort_list(icon_list)) if(input) qdel(holo_icon) switch(input) @@ -687,7 +689,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/silicon/ai) "horror" = 'icons/mob/ai.dmi' ) - input = input("Please select a hologram:") as null|anything in sort_list(icon_list) + input = tgui_input_list(user, "Please select a hologram", "Hologram Choice", sort_list(icon_list)) if(input) qdel(holo_icon) switch(input) diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 5c498dd31ad53..66131fc677c49 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -180,7 +180,7 @@ sec.remove_hud_from(src) if("universal_translator") if(!languages_granted) - grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_SOFTWARE) + grant_all_languages(source = LANGUAGE_SOFTWARE) languages_granted = TRUE if("wipe_core") var/confirm = alert(src, "Are you certain you want to wipe yourself?", "Personality Wipe", "Yes", "No") diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm index 131ac488b324d..588289cb1767a 100644 --- a/code/modules/mob/living/simple_animal/slime/powers.dm +++ b/code/modules/mob/living/simple_animal/slime/powers.dm @@ -244,7 +244,7 @@ M.maxHealth = round(M.maxHealth * 1.3) M.health = M.maxHealth if(transformeffects & SLIME_EFFECT_PINK) - M.grant_language(/datum/language/common, TRUE, TRUE) + M.grant_language(/datum/language/common) var/datum/language_holder/LH = M.get_language_holder() LH.selected_language = /datum/language/common if(transformeffects & SLIME_EFFECT_BLUESPACE) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4ba48a2af5a5e..0b04e5ecbd70c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1279,12 +1279,11 @@ fully_replace_character_name(real_name, new_name) ///Show the language menu for this mob -/mob/verb/open_language_menu() +/mob/verb/open_language_menu_verb() set name = "Open Language Menu" set category = "IC" - var/datum/language_holder/H = get_language_holder() - H.open_language_menu(usr) + get_language_holder().open_language_menu(usr) ///Adjust the nutrition of a mob /mob/proc/adjust_nutrition(var/change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 6161f9d1e4901..9969981ccadf7 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -233,9 +233,7 @@ CREATION_TEST_IGNORE_SELF(/mob) ///Is the mob actively shifting? var/shifting - ///Currently possesses a typing indicator icon - var/typing_indicator = FALSE - /// Thinking indicator - mob has input window open - var/thinking_indicator = FALSE - /// User is thinking in character. Used to revert to thinking state after stop_typing - var/thinking_IC = FALSE + ///the icon currently used for the typing indicator's bubble + var/active_typing_indicator + ///the icon currently used for the thinking indicator's bubble + var/active_thinking_indicator diff --git a/code/modules/mob/mob_stat.dm b/code/modules/mob/mob_stat.dm index 604db92362d38..8f75fde9dc687 100644 --- a/code/modules/mob/mob_stat.dm +++ b/code/modules/mob/mob_stat.dm @@ -118,6 +118,7 @@ tab_data[REF(src)] = list( text="[name]", tag = STAT_PANEL_TAG(src), + image = FAST_REF(src), type=STAT_ATOM ) var/max_item_sanity = MAX_ITEMS_TO_READ @@ -150,11 +151,13 @@ var/image/override_image = overrides[A] atom_name = override_image.name image_overrides[A] = override_image - var/list/item_group = atom_count["[atom_type][atom_name]"] + // use the max item sanity as an extention if the unique flag is set, since its unique + var/extension = (A.flags_1 & STAT_UNIQUE_1) && max_item_sanity + var/list/item_group = atom_count["[atom_type][atom_name][extension]"] if (item_group) item_group += A else - atom_count["[A.type][A.name]"] = list(A) + atom_count["[A.type][A.name][extension]"] = list(A) // To many icon types per tile if (icon_count_sanity-- <= 0) break @@ -168,20 +171,26 @@ for (var/obj/item/stack/stack_item as() in atom_items) item_count += stack_item.amount var/atom_name = first_atom.name + var/image_icon if (image_overrides[first_atom]) var/image/override_image = image_overrides[first_atom] atom_name = override_image.name + image_icon = FAST_REF(override_image) + else + image_icon = FAST_REF(first_atom) tab_data[REF(first_atom)] = list( text = "[atom_name][item_count > 1 ? " (x[item_count])" : ""]", tag = STAT_PANEL_TAG(first_atom), + image = image_icon, type = STAT_ATOM ) // Display self tab_data[REF(client.mob)] = list( - text = client.mob.name, - tag = "You", - type = STAT_ATOM - ) + text = client.mob.name, + tag = "You", + image = FAST_REF(client.mob), + type = STAT_ATOM + ) /mob/proc/get_all_verbs() var/list/all_verbs = new diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm index e1e7b7c15f154..fd52baf236c79 100644 --- a/code/modules/ninja/energy_katana.dm +++ b/code/modules/ninja/energy_katana.dm @@ -18,7 +18,7 @@ attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER_EASY bleed_force = BLEED_DEEP_WOUND max_integrity = 200 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 6d1b2b5d3e4fd..7b18ba27d539c 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -97,7 +97,7 @@ throw_speed = 4 colour = "crimson" custom_materials = list(/datum/material/gold = 750) - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE resistance_flags = FIRE_PROOF unique_reskin_icon = list("Oak" = "pen-fountain-o", @@ -252,7 +252,7 @@ hitsound = 'sound/weapons/edagger.ogg' embedding = list(embed_chance = 200, max_damage_mult = 15, armour_block = 40) //rule of cool throwforce = 35 - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_CUT playsound(user, 'sound/weapons/saberon.ogg', 5, 1) to_chat(user, "[src] is now active.") diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 0a28124b85fbf..77e0d572c62a6 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -42,6 +42,7 @@ By design, d1 is the smallest direction and d2 is the highest layer = WIRE_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER anchored = TRUE obj_flags = CAN_BE_HIT | ON_BLUEPRINTS + flags_1 = STAT_UNIQUE_1 var/d1 = 0 // cable direction 1 (see above) var/d2 = 1 // cable direction 2 (see above) var/datum/powernet/powernet diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 0a1b5360dfd39..948273ea8c49f 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -28,6 +28,8 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF var/sprite_number = 0 var/ztrait //Set to a valid ZTRAIT define to have the gravgen provide gravity to all of the zlevels with said trait. Ex: ZTRAIT_STATION + /// The gravity field created by the generator. + var/datum/proximity_monitor/advanced/gravity/gravity_field /obj/machinery/gravity_generator/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG) return FALSE @@ -97,12 +99,6 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/main/station ztrait = ZTRAIT_STATION -/obj/machinery/gravity_generator/main/station/Initialize(mapload) - . = ..() - setup_parts() - middle.add_overlay("activated") - update_list() - // // Generator an admin can spawn // @@ -131,6 +127,13 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne var/broken_state = 0 var/setting = 1 //Gravity value when on +/obj/machinery/gravity_generator/main/Initialize(mapload) + . = ..() + setup_parts() + middle.add_overlay("activated") + update_list() + update_mobs() + /obj/machinery/gravity_generator/main/Destroy() // If we somehow get deleted, remove all of our other parts. investigate_log("was destroyed!", INVESTIGATE_GRAVITY) on = FALSE @@ -173,7 +176,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne charge_count = 0 breaker = 0 set_power() - set_state(0) + disable() investigate_log("has broken down.", INVESTIGATE_GRAVITY) /obj/machinery/gravity_generator/main/set_fix() @@ -304,8 +307,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne investigate_log("is now [charging_state == POWER_UP ? "charging" : "discharging"].", INVESTIGATE_GRAVITY) update_appearance() -// Set the state of the gravity. -/obj/machinery/gravity_generator/main/proc/set_state(new_state) +/obj/machinery/gravity_generator/main/proc/enable() charging_state = POWER_IDLE on = new_state update_use_power(on ? ACTIVE_POWER_USE : IDLE_POWER_USE) @@ -323,11 +325,35 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne investigate_log("was brought offline and there is now no gravity for this level.", INVESTIGATE_GRAVITY) message_admins("The gravity generator was brought offline with no backup generator. [ADMIN_VERBOSEJMP(src)]") + var/old_gravity = gravity_in_level() + complete_state_update() + gravity_field = new(src, 2, TRUE, 6) + + if (!old_gravity) + if(SSticker.current_state == GAME_STATE_PLAYING) + investigate_log("was brought online and is now producing gravity for this level.", INVESTIGATE_GRAVITY) + message_admins("The gravity generator was brought online [ADMIN_VERBOSEJMP(src)]") + shake_everyone() + +/obj/machinery/gravity_generator/main/proc/disable() + charging_state = POWER_IDLE + on = FALSE + use_power = IDLE_POWER_USE + + QDEL_NULL(gravity_field) + var/old_gravity = gravity_in_level() + complete_state_update() + + if (old_gravity) + if(SSticker.current_state == GAME_STATE_PLAYING) + investigate_log("was brought offline and there is now no gravity for this level.", INVESTIGATE_GRAVITY) + message_admins("The gravity generator was brought offline with no backup generator. [ADMIN_VERBOSEJMP(src)]") + shake_everyone() + +/obj/machinery/gravity_generator/main/proc/complete_state_update() update_appearance() update_list() ui_update() - if(alert) - shake_everyone() // Charge/Discharge and turn on/off gravity when you reach 0/100 percent. // Also emit radiation and handle the overlays. @@ -336,9 +362,9 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne return if(charging_state != POWER_IDLE) if(charging_state == POWER_UP && charge_count >= 100) - set_state(1) + enable() else if(charging_state == POWER_DOWN && charge_count <= 0) - set_state(0) + disable() else if(charging_state == POWER_UP) charge_count += 2 @@ -417,11 +443,6 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne GLOB.gravity_generators["[theZ]"] -= src SSmapping.calculate_z_level_gravity(z) -/obj/machinery/gravity_generator/main/proc/change_setting(value) - if(value != setting) - setting = value - shake_everyone() - /obj/machinery/gravity_generator/main/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock) . = ..() on = FALSE @@ -433,6 +454,9 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne on = TRUE update_list() +/obj/machinery/gravity_generator/main/proc/update_mobs() + for(var/mob/living/animal in GLOB.mob_living_list) + animal.refresh_gravity() // Misc diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 6fa3812ad6a64..5a734b282a3f5 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -107,7 +107,7 @@ attack_verb_continuous = list("attacks", "slashes", "cuts", "slices") attack_verb_simple = list("attack", "slash", "cut", "slice") force = 12 - sharpness = IS_SHARP + sharpness = SHARP can_charge = FALSE dead_cell = TRUE usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index e9b8d8b024021..bc911c1142cc9 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -107,7 +107,7 @@ force = 20 armour_penetration = 75 block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY | BLOCKING_PROJECTILE - sharpness = IS_SHARP + sharpness = SHARP_DISMEMBER bleed_force = BLEED_DEEP_WOUND max_charges = 4 diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index eafa82b4c8f10..fe71fbc591037 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2191,12 +2191,12 @@ /datum/reagent/consumable/ratlight/on_mob_metabolize(mob/living/L) L.add_blocked_language(subtypesof(/datum/language/) - /datum/language/ratvar, LANGUAGE_REAGENT) - L.grant_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_REAGENT) + L.grant_language(/datum/language/ratvar, source = LANGUAGE_REAGENT) ..() /datum/reagent/consumable/ratlight/on_mob_end_metabolize(mob/living/L) L.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_REAGENT) - L.remove_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_REAGENT) + L.remove_language(/datum/language/ratvar, source = LANGUAGE_REAGENT) L.set_light(-1) ..() diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index a9180e678bd38..186c650810fc3 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -126,7 +126,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb_continuous = list("stabs", "slashes", "attacks") attack_verb_simple = list("stab", "slash", "attack") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_SURFACE var/static/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken") diff --git a/code/modules/research/nanites/nanite_programs/buffing.dm b/code/modules/research/nanites/nanite_programs/buffing.dm index aadebf25e1776..65cd5241e6642 100644 --- a/code/modules/research/nanites/nanite_programs/buffing.dm +++ b/code/modules/research/nanites/nanite_programs/buffing.dm @@ -177,6 +177,7 @@ name = "metallic armblade" desc = "Nanites have formed this extremely sharp blade around your arm. Owie." force = 15 + sharpness = SHARP_DISMEMBER icon = 'icons/obj/nanite.dmi' icon_state = "nanite_blade" item_state = "nanite_blade" diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm index 62c196fb254e4..8e9bd675f5fd1 100644 --- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm +++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm @@ -9,6 +9,7 @@ Slimecrossing Weapons name = "slimy boneblade" desc = "What remains of the bones in your arm. Incredibly sharp, and painful for both you and your opponents." force = 15 + sharpness = SHARP_DISMEMBER force_string = "painful" /obj/item/melee/arm_blade/slime/attack(mob/living/L, mob/user) diff --git a/code/modules/research/xenobiology/crossbreeding/transformative.dm b/code/modules/research/xenobiology/crossbreeding/transformative.dm index 6f5ba4ce7ecdf..40b5cd0207658 100644 --- a/code/modules/research/xenobiology/crossbreeding/transformative.dm +++ b/code/modules/research/xenobiology/crossbreeding/transformative.dm @@ -128,7 +128,7 @@ transformative extracts: /obj/item/slimecross/transformative/pink/do_effect(mob/living/simple_animal/slime/S) ..() - S.grant_language(/datum/language/common, TRUE, TRUE) + S.grant_language(/datum/language/common) var/datum/language_holder/LH = S.get_language_holder() LH.selected_language = /datum/language/common diff --git a/code/modules/research/xenobiology/crossbreeding/warping.dm b/code/modules/research/xenobiology/crossbreeding/warping.dm index eff700d090aaf..81a2240be439c 100644 --- a/code/modules/research/xenobiology/crossbreeding/warping.dm +++ b/code/modules/research/xenobiology/crossbreeding/warping.dm @@ -825,7 +825,7 @@ GLOBAL_DATUM(warped_room, /datum/map_template/warped_room) icon_state = "yellow" dynamic_lighting = DYNAMIC_LIGHTING_ENABLED requires_power = FALSE - has_gravity = TRUE + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_NONE /area/warped_room/get_virtual_z(turf/T) diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm index ea4655efac38e..5e83faddef81d 100644 --- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm @@ -341,7 +341,7 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) name = "Hilbert's Hotel Room" icon_state = "hilbertshotel" requires_power = FALSE - has_gravity = TRUE + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_NONE area_flags = HIDDEN_AREA dynamic_lighting = DYNAMIC_LIGHTING_ENABLED @@ -426,7 +426,7 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) icon_state = "hilbertshotel" requires_power = FALSE area_flags = HIDDEN_AREA | UNIQUE_AREA - has_gravity = TRUE + default_gravity = STANDARD_GRAVITY teleport_restriction = TELEPORT_ALLOW_NONE /obj/item/abstracthotelstorage diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index 89c92e3f140e6..9c0ead370fe8a 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -22,6 +22,8 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new) var/datum/callback/ev var/event = "" var/obj/machinery/keycard_auth/event_source + ///Triggering ID card relayed to auth devices to make sure two keycards are used. + var/obj/item/card/id/triggering_card var/mob/triggerer = null var/waiting = 0 @@ -67,24 +69,31 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) /obj/machinery/keycard_auth/ui_act(action, params) if(..() || waiting || !allowed(usr)) return + var/obj/item/card/swipe_id = usr.get_idcard() + if(!swipe_id || !istype(swipe_id)) + to_chat(usr, "No ID card detected.") + return switch(action) if("red_alert") if(!event_source) - sendEvent(KEYCARD_RED_ALERT) + sendEvent(KEYCARD_RED_ALERT, swipe_id) . = TRUE if("emergency_maint") if(!event_source) - sendEvent(KEYCARD_EMERGENCY_MAINTENANCE_ACCESS) + sendEvent(KEYCARD_EMERGENCY_MAINTENANCE_ACCESS, swipe_id) . = TRUE if("auth_swipe") if(event_source) + if(swipe_id == event_source.triggering_card) + to_chat(usr, "Invalid ID. Confirmation ID must not equal trigger ID.") + return event_source.trigger_event(usr) event_source = null update_appearance() . = TRUE if("bsa_unlock") if(!event_source) - sendEvent(KEYCARD_BSA_UNLOCK) + sendEvent(KEYCARD_BSA_UNLOCK, swipe_id) . = TRUE /obj/machinery/keycard_auth/update_appearance(updates) @@ -102,8 +111,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) . += mutable_appearance(icon, "auth_on") . += emissive_appearance(icon, "auth_on", alpha = src.alpha) -/obj/machinery/keycard_auth/proc/sendEvent(event_type) +/obj/machinery/keycard_auth/proc/sendEvent(event_type, obj/item/card/id/swipe_id) triggerer = usr + triggering_card = swipe_id //Shouldn't need qdel registering due to very short time before this var resets. event = event_type waiting = 1 GLOB.keycard_events.fireEvent("triggerEvent", src) @@ -111,6 +121,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) /obj/machinery/keycard_auth/proc/eventSent() triggerer = null + triggering_card = null event = "" waiting = 0 diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm index 5631e7fd3ed61..fa2ee82768ce6 100644 --- a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm +++ b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm @@ -334,7 +334,7 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He newS.setup(str) newS.set_dynamic_lighting() //Shuttles always have gravity - newS.has_gravity = TRUE + newS.default_gravity = STANDARD_GRAVITY newS.requires_power = TRUE //Record the area for use when creating the docking port recorded_shuttle_area = newS diff --git a/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm b/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm index 761873d5532c7..f04fdbf4a7ea2 100644 --- a/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm +++ b/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm @@ -58,7 +58,7 @@ clockwork_warp_allowed = FALSE requires_power = FALSE mood_bonus = -999 - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY ambience_index = AMBIENCE_NONE sound_environment = SOUND_ENVIRONMENT_DRUGGED teleport_restriction = TELEPORT_ALLOW_NONE diff --git a/code/modules/shuttle/super_cruise/orbital_poi_generator/ruin_generator/exoplanets/biomes/_biome.dm b/code/modules/shuttle/super_cruise/orbital_poi_generator/ruin_generator/exoplanets/biomes/_biome.dm index 7708ca8473314..365e92ca4e0a8 100644 --- a/code/modules/shuttle/super_cruise/orbital_poi_generator/ruin_generator/exoplanets/biomes/_biome.dm +++ b/code/modules/shuttle/super_cruise/orbital_poi_generator/ruin_generator/exoplanets/biomes/_biome.dm @@ -18,7 +18,7 @@ /area/planet icon_state = "Unknown Planet" - has_gravity = STANDARD_GRAVITY + default_gravity = STANDARD_GRAVITY flags_1 = NONE sound_environment = SOUND_AREA_LAVALAND always_unpowered = TRUE diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 29b39806745f5..4523b3587140c 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -7,7 +7,15 @@ slot = ORGAN_SLOT_TONGUE attack_verb_continuous = list("licks", "slobbers", "slaps", "frenches", "tongues") attack_verb_simple = list("lick", "slobber", "slap", "french", "tongue") - var/list/languages_possible + /** + * A cached list of paths of all the languages this tongue is capable of speaking + * + * Relates to a mob's ability to speak a language - a mob must be able to speak the language + * and have a tongue able to speak the language (or omnitongue) in order to actually speak said language + * + * To modify this list for subtypes, see [/obj/item/organ/internal/tongue/proc/get_possible_languages]. Do not modify directly. + */ + VAR_PRIVATE/list/languages_possible var/say_mod = "says" var/ask_mod = "asks" var/yell_mod = "yells" @@ -15,9 +23,33 @@ var/liked_food = JUNKFOOD | FRIED var/disliked_food = GROSS | RAW | CLOTH | GORE var/toxic_food = TOXIC - var/taste_sensitivity = 15 // lower is more sensitive. + // Determines how "sensitive" this tongue is to tasting things, lower is more sensitive. + /// See [/mob/living/proc/get_taste_sensitivity]. + var/taste_sensitivity = 15 + /// Whether this tongue modifies speech via signal var/modifies_speech = FALSE - var/static/list/languages_possible_base = typecacheof(list( + +/obj/item/organ/tongue/Initialize(mapload) + . = ..() + // Setup the possible languages list + // - get_possible_languages gives us a list of language paths + // - then we cache it via string list + // this results in tongues with identical possible languages sharing a cached list instance + languages_possible = string_list(get_possible_languages()) + +/** + * Used in setting up the "languages possible" list. + * + * Override to have your tongue be only capable of speaking certain languages + * Extend to hvae a tongue capable of speaking additional languages to the base tongue + * + * While a user may be theoretically capable of speaking a language, they cannot physically speak it + * UNLESS they have a tongue with that language possible, UNLESS UNLESS they have omnitongue enabled. + */ +/obj/item/organ/tongue/proc/get_possible_languages() + RETURN_TYPE(/list) + // This is the default list of languages most humans should be capable of speaking + return list( /datum/language/aphasia, /datum/language/apidite, /datum/language/beachbum, @@ -36,11 +68,8 @@ /datum/language/sylvan, /datum/language/terrum, /datum/language/uncommon, - /datum/language/sonus)) - -/obj/item/organ/tongue/Initialize(mapload) - . = ..() - languages_possible = languages_possible_base + /datum/language/sonus, + ) /obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args) SIGNAL_HANDLER @@ -56,8 +85,8 @@ M.RegisterSignal(M, COMSIG_MOB_SAY, TYPE_PROC_REF(/mob/living/carbon, handle_tongueless_speech)) return ..() -/obj/item/organ/tongue/could_speak_language(datum/language/dt) - return is_type_in_typecache(dt, languages_possible) +/obj/item/organ/tongue/could_speak_language(datum/language/language_path) + return (language_path in languages_possible) /obj/item/organ/tongue/lizard name = "forked tongue" @@ -191,16 +220,17 @@ say_mod = "hisses" taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED modifies_speech = TRUE // not really, they just hiss - var/static/list/languages_possible_alien = typecacheof(list( + +// Aliens can only speak alien and a few other languages. +/obj/item/organ/tongue/alien/get_possible_languages() + return list( /datum/language/xenocommon, /datum/language/common, + /datum/language/uncommon, /datum/language/draconic, /datum/language/ratvar, - /datum/language/monkey)) - -/obj/item/organ/tongue/alien/Initialize(mapload) - . = ..() - languages_possible = languages_possible_alien + /datum/language/monkey, + ) /obj/item/organ/tongue/alien/handle_speech(datum/source, list/speech_args) playsound(owner, "hiss", 25, 1, 1) @@ -264,9 +294,8 @@ modifies_speech = TRUE taste_sensitivity = 25 // not as good as an organic tongue -/obj/item/organ/tongue/robot/Initialize(mapload) - . = ..() - languages_possible = languages_possible_base += typecacheof(/datum/language/machine) + typecacheof(/datum/language/voltaic) +/obj/item/organ/tongue/robot/get_possible_languages() + return ..() + /datum/language/machine + /datum/language/voltaic /obj/item/organ/tongue/robot/emp_act(severity) owner.emote("scream") @@ -301,9 +330,8 @@ taste_sensitivity = 101 // Not a tongue, they can't taste shit toxic_food = NONE -/obj/item/organ/tongue/ethereal/Initialize(mapload) - . = ..() - languages_possible = languages_possible_base += typecacheof(/datum/language/voltaic) +/obj/item/organ/tongue/ethereal/get_possible_languages() + return ..() + /datum/language/voltaic /obj/item/organ/tongue/golem name = "mineral tongue" @@ -312,9 +340,8 @@ taste_sensitivity = 101 //They don't eat. icon_state = "adamantine_cords" -/obj/item/organ/tongue/golem/Initialize(mapload) - . = ..() - languages_possible = languages_possible_base += typecacheof(/datum/language/terrum) +/obj/item/organ/tongue/golem/get_possible_languages() + return ..() + /datum/language/terrum /obj/item/organ/tongue/golem/bananium name = "bananium tongue" @@ -344,9 +371,8 @@ toxic_food = NONE disliked_food = NONE -/obj/item/organ/tongue/slime/Initialize(mapload) - . = ..() - languages_possible = languages_possible_base += typecacheof(/datum/language/slime) +/obj/item/organ/tongue/slime/get_possible_languages() + return ..() + /datum/language/slime /obj/item/organ/tongue/moth name = "mothic tongue" diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index d6bae900fb7ba..006dbda02f1f0 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -157,7 +157,7 @@ attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP bleed_force = BLEED_CUT tool_behaviour = TOOL_SCALPEL toolspeed = 1 @@ -182,7 +182,7 @@ attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") toolspeed = 0.5 hitsound = 'sound/weapons/bladeslice.ogg' - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP bleed_force = BLEED_CUT /obj/item/scalpel/suicide_act(mob/living/user) @@ -207,7 +207,7 @@ custom_materials = list(/datum/material/iron=10000, /datum/material/glass=6000) attack_verb_continuous = list("attacks", "slashes", "saws", "cuts") attack_verb_simple = list("attack", "slash", "saw", "cut") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_DEEP_WOUND tool_behaviour = TOOL_SAW toolspeed = 1 @@ -233,7 +233,7 @@ toolspeed = 0.5 attack_verb_continuous = list("attacks", "slashes", "saws", "cuts") attack_verb_simple = list("attack", "slash", "saw", "cut") - sharpness = IS_SHARP + sharpness = SHARP bleed_force = BLEED_DEEP_WOUND /obj/item/hacksaw @@ -252,7 +252,7 @@ custom_materials = list(/datum/material/iron=12000) attack_verb_continuous = list("attacks", "slashes", "saws", "cuts") attack_verb_simple = list("attack", "slash", "saw", "cut") - sharpness = IS_SHARP + sharpness = SHARP tool_behaviour = TOOL_SAW toolspeed = 2 @@ -358,7 +358,7 @@ light_system = MOVABLE_LIGHT light_range = 1 light_color = LIGHT_COLOR_GREEN - sharpness = IS_SHARP_ACCURATE + sharpness = SHARP // It cauterises the wound it causes bleed_force = 0 diff --git a/code/modules/tgui/states/language_menu.dm b/code/modules/tgui/states/language_menu.dm index 6389b05cd5e80..72f1c230c93e7 100644 --- a/code/modules/tgui/states/language_menu.dm +++ b/code/modules/tgui/states/language_menu.dm @@ -12,6 +12,6 @@ GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new) if(check_rights_for(user.client, R_ADMIN)) . = UI_INTERACTIVE else if(istype(src_object, /datum/language_menu)) - var/datum/language_menu/LM = src_object - if(LM.language_holder.get_atom() == user) + var/datum/language_menu/my_languages = src_object + if(my_languages.language_holder.owner == user) . = UI_INTERACTIVE diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm index 5e27f9b1c9cd6..bc060eae51bce 100644 --- a/code/modules/tgui/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -83,6 +83,8 @@ var/html = SStgui.basehtml html = replacetextEx(html, "\[tgui:windowId]", id) html = replacetextEx(html, "\[tgui:strictMode]", strict_mode) + html = replacetextEx(html, "\[tgui:byondMajor\]", client.byond_version) + html = replacetextEx(html, "\[tgui:byondMinor\]", client.byond_build) // Inject assets var/inline_assets_str = "" for(var/datum/asset/asset in assets) diff --git a/code/modules/tgui_input/say_modal/typing.dm b/code/modules/tgui_input/say_modal/typing.dm index 2325440d36ff3..248e419cc5fe5 100644 --- a/code/modules/tgui_input/say_modal/typing.dm +++ b/code/modules/tgui_input/say_modal/typing.dm @@ -1,8 +1,6 @@ -/// Thinking -GLOBAL_DATUM_INIT(thinking_indicator, /mutable_appearance, mutable_appearance('icons/mob/talk.dmi', "default3", CALCULATE_MOB_OVERLAY_LAYER(TYPING_LAYER))) + /// Typing GLOBAL_DATUM_INIT(blind_typing_indicator, /mutable_appearance, mutable_appearance('icons/mob/talk.dmi', "default0", (-TYPING_LAYER), BLIND_FEATURE_PLANE, appearance_flags = KEEP_TOGETHER)) -GLOBAL_DATUM_INIT(typing_indicator, /mutable_appearance, mutable_appearance('icons/mob/talk.dmi', "default0", CALCULATE_MOB_OVERLAY_LAYER(TYPING_LAYER))) /** Creates a thinking indicator over the mob. */ /mob/proc/create_thinking_indicator() @@ -33,21 +31,17 @@ GLOBAL_DATUM_INIT(typing_indicator, /mutable_appearance, mutable_appearance('ico remove_all_indicators() return ..() -/** Sets the mob as "thinking" - with indicator and variable thinking_IC */ +/** Sets the mob as "thinking" - with indicator and the TRAIT_THINKING_IN_CHARACTER trait */ /datum/tgui_say/proc/start_thinking() - if(!window_open || !istype(client.mob)) - return FALSE - /// Special exemptions - if(isabductor(client.mob)) + if(!window_open) return FALSE - client.mob.thinking_IC = TRUE - client.mob.create_thinking_indicator() + return client.start_thinking() /** Removes typing/thinking indicators and flags the mob as not thinking */ /datum/tgui_say/proc/stop_thinking() if(!istype(client.mob)) return FALSE - client.mob.remove_all_indicators() + return client.stop_thinking() /** * Handles the user typing. After a brief period of inactivity, @@ -56,53 +50,48 @@ GLOBAL_DATUM_INIT(typing_indicator, /mutable_appearance, mutable_appearance('ico /datum/tgui_say/proc/start_typing() if(!istype(client.mob)) return FALSE - client.mob.remove_thinking_indicator() - if(!window_open || !client.mob.thinking_IC) + if(!window_open) return FALSE - client.mob.create_typing_indicator() - addtimer(CALLBACK(src, PROC_REF(stop_typing)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE) + return client.start_typing() /** - * Callback to remove the typing indicator after a brief period of inactivity. + * Remove the typing indicator after a brief period of inactivity or during say events. * If the user was typing IC, the thinking indicator is shown. */ /datum/tgui_say/proc/stop_typing() - if(!client?.mob) - return FALSE - client.mob.remove_typing_indicator() - if(!window_open || !client.mob.thinking_IC) + if(!window_open) return FALSE - client.mob.create_thinking_indicator() + client.stop_typing() /// Overrides for overlay creation /mob/living/create_thinking_indicator() - if(thinking_indicator || typing_indicator || !thinking_IC || stat != CONSCIOUS ) + if(active_thinking_indicator || active_typing_indicator || stat != CONSCIOUS || !HAS_TRAIT(src, TRAIT_THINKING_IN_CHARACTER)) return FALSE - add_overlay(GLOB.thinking_indicator) - thinking_indicator = TRUE + active_thinking_indicator = mutable_appearance('icons/mob/talk.dmi', "[bubble_icon]3", TYPING_LAYER) + add_overlay(active_thinking_indicator) /mob/living/remove_thinking_indicator() - if(!thinking_indicator) + if(!active_thinking_indicator) return FALSE - cut_overlay(GLOB.thinking_indicator) - thinking_indicator = FALSE + cut_overlay(active_thinking_indicator) + active_thinking_indicator = null /mob/living/create_typing_indicator(override = FALSE) - if(typing_indicator || ((thinking_indicator || !thinking_IC) && !override) || stat != CONSCIOUS) + if(active_typing_indicator || ((active_thinking_indicator || !HAS_TRAIT(src, TRAIT_THINKING_IN_CHARACTER)) && !override) || stat != CONSCIOUS) return FALSE - add_overlay(GLOB.typing_indicator) + active_typing_indicator = mutable_appearance('icons/mob/talk.dmi', "[bubble_icon]0", TYPING_LAYER) + add_overlay(active_typing_indicator) add_overlay(GLOB.blind_typing_indicator) - typing_indicator = TRUE /mob/living/remove_typing_indicator() - if(!typing_indicator) + if(!active_typing_indicator) return FALSE - cut_overlay(GLOB.typing_indicator) + cut_overlay(active_typing_indicator) cut_overlay(GLOB.blind_typing_indicator) - typing_indicator = FALSE + active_typing_indicator = null /mob/living/remove_all_indicators() - thinking_IC = FALSE + REMOVE_TRAIT(src, TRAIT_THINKING_IN_CHARACTER, CURRENTLY_TYPING_TRAIT) remove_thinking_indicator() remove_typing_indicator() diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 6a8bf96075e3f..7788bda1ba68c 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -41,6 +41,7 @@ #include "heretic_rituals.dm" #include "icon_smoothing_unit_test.dm" #include "keybinding_init.dm" +#include "language_transfer.dm" #include "merge_type.dm" #include "metabolizing.dm" #include "missing_icons.dm" diff --git a/code/modules/unit_tests/language_transfer.dm b/code/modules/unit_tests/language_transfer.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 947d4163f75b9..d8c49e9a55811 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -32,10 +32,8 @@ var/custom_price ///Does the item have a custom premium price override var/custom_premium_price - /** GAGs recolorability ///Whether the product can be recolored by the GAGS system - var/colorable - **/ + //var/colorable ///List of items that have been returned to the vending machine. var/list/returned_products /// The category the product was in, if any. @@ -348,9 +346,7 @@ R.max_amount = amount R.custom_price = initial(temp.custom_price) R.custom_premium_price = initial(temp.custom_premium_price) - /* GAGS recolorability //R.colorable = !!(initial(temp.greyscale_config) && initial(temp.greyscale_colors) && (initial(temp.flags_1) & IS_PLAYER_COLORABLE_1)) - */ R.category = product_to_category[typepath] recordlist += R @@ -907,8 +903,8 @@ switch(action) if("vend") . = vend(params) - //if("select_colors") - // . = select_colors(params) + if("select_colors") + . = select_colors(params) /obj/machinery/vending/proc/can_vend(user, silent=FALSE) . = FALSE diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index ac09f4ba2563c..aba6405de02bf 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -28,6 +28,9 @@ /obj/item/clothing/head/beanie/rasta = 3, /obj/item/clothing/head/beret = 3, /obj/item/clothing/head/beret/black = 3, + /obj/item/clothing/mask/bandana = 3, + /obj/item/clothing/mask/bandana/striped = 3, + /obj/item/clothing/mask/bandana/skull = 3, /obj/item/clothing/neck/scarf/pink = 3, /obj/item/clothing/neck/scarf/red = 3, /obj/item/clothing/neck/scarf/green = 3, diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index c1cfd17d79391..85812f4d13bf4 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -27,7 +27,7 @@ /obj/item/clothing/shoes/jackboots = 3, /obj/item/clothing/head/beret/sec = 3, /obj/item/clothing/head/soft/sec = 3, - /obj/item/clothing/mask/bandana/red = 3, + /obj/item/clothing/mask/bandana/striped/security = 3, /obj/item/clothing/mask/gas/sechailer = 6, /obj/item/clothing/under/rank/security/officer/skirt = 3, /obj/item/clothing/under/rank/security/officer/white = 3, @@ -68,6 +68,7 @@ /obj/item/clothing/under/rank/medical/doctor/nurse = 4, /obj/item/clothing/head/costume/nursehat = 4, /obj/item/clothing/head/beret/med = 4, + /obj/item/clothing/mask/bandana/striped/medical = 4, /obj/item/clothing/under/rank/medical/doctor/blue = 4, /obj/item/clothing/under/rank/medical/doctor/green = 4, /obj/item/clothing/under/rank/medical/doctor/purple = 4, @@ -106,9 +107,11 @@ /obj/item/clothing/under/rank/engineering/engineer/skirt = 3, /obj/item/clothing/suit/hazardvest = 3, /obj/item/clothing/shoes/workboots = 3, + /obj/item/clothing/head/beret/eng = 3, + /obj/item/clothing/mask/bandana/striped/engineering = 3, /obj/item/clothing/head/utility/hardhat = 3, /obj/item/clothing/head/utility/hardhat/welding = 3, - /obj/item/clothing/head/beret/eng = 3) + ) contraband = list(/obj/item/clothing/suit/hooded/wintercoat/engineering/old = 3) refill_canister = /obj/item/vending_refill/wardrobe/engi_wardrobe dept_req_for_free = ACCOUNT_ENG_BITFLAG @@ -149,26 +152,33 @@ product_ads = "Upgraded Assistant Style! Pick yours today!;These shorts are comfy and easy to wear, get yours now!" vend_reply = "Thank you for using the CargoDrobe!" extra_price = 50 - products = list(/obj/item/clothing/suit/hooded/wintercoat/cargo = 3, - /obj/item/clothing/under/rank/cargo/tech = 3, - /obj/item/clothing/under/rank/cargo/tech/skirt = 3, - /obj/item/clothing/under/plasmaman/cargo = 3, - /obj/item/clothing/head/helmet/space/plasmaman/cargo = 3, - /obj/item/clothing/shoes/sneakers/black = 3, - /obj/item/clothing/gloves/fingerless = 3, - /obj/item/clothing/head/soft/cargo = 3, - /obj/item/clothing/head/beret/supply = 3, - /obj/item/radio/headset/headset_cargo = 3) - premium = list( /obj/item/clothing/under/rank/cargo/miner = 3, - /obj/item/clothing/head/costume/mailman = 2, - /obj/item/clothing/under/misc/mailman/skirt = 2, - /obj/item/clothing/under/misc/mailman = 2, - /obj/item/storage/backpack/satchel/mail = 2, - /obj/item/clothing/under/plasmaman/mailman = 2, - /obj/item/clothing/head/helmet/space/plasmaman/mailman = 2 + products = list( + /obj/item/clothing/suit/hooded/wintercoat/cargo = 3, + /obj/item/clothing/under/rank/cargo/tech = 3, + /obj/item/clothing/under/rank/cargo/tech/skirt = 3, + /obj/item/clothing/under/plasmaman/cargo = 3, + /obj/item/clothing/head/helmet/space/plasmaman/cargo = 3, + /obj/item/clothing/shoes/sneakers/black = 3, + /obj/item/clothing/gloves/fingerless = 3, + /obj/item/clothing/mask/bandana/striped/cargo = 3, + /obj/item/clothing/head/soft/cargo = 3, + /obj/item/clothing/head/beret/supply = 3, + /obj/item/radio/headset/headset_cargo = 3 + ) + + premium = list( + /obj/item/clothing/under/rank/cargo/miner = 3, + /obj/item/clothing/head/costume/mailman = 2, + /obj/item/clothing/under/misc/mailman/skirt = 2, + /obj/item/clothing/under/misc/mailman = 2, + /obj/item/storage/backpack/satchel/mail = 2, + /obj/item/clothing/under/plasmaman/mailman = 2, + /obj/item/clothing/head/helmet/space/plasmaman/mailman = 2 + ) + contraband = list( + /obj/item/radio/headset/headset_quartermaster = 1, + /obj/item/clothing/suit/hooded/wintercoat/cargo/old = 3 ) - contraband = list(/obj/item/radio/headset/headset_quartermaster = 1, - /obj/item/clothing/suit/hooded/wintercoat/cargo/old = 3) refill_canister = /obj/item/vending_refill/wardrobe/cargo_wardrobe dept_req_for_free = ACCOUNT_CAR_BITFLAG @@ -192,7 +202,7 @@ /obj/item/clothing/shoes/sneakers/black = 2, /obj/item/clothing/gloves/fingerless = 2, /obj/item/clothing/head/soft/black = 2, - /obj/item/clothing/mask/bandana/skull = 2, + /obj/item/clothing/mask/bandana/skull/black = 2, /obj/item/clothing/head/beret/sci = 2) contraband = list(/obj/item/clothing/suit/hooded/techpriest = 2, @@ -219,6 +229,7 @@ /obj/item/storage/backpack/satchel/tox = 3, /obj/item/storage/backpack/duffelbag/science = 3, /obj/item/clothing/suit/hooded/wintercoat/science = 3, + /obj/item/clothing/mask/bandana/striped/science = 3, /obj/item/clothing/under/rank/rnd/scientist = 3, /obj/item/clothing/under/rank/rnd/scientist/skirt = 3, /obj/item/clothing/under/plasmaman/science = 3, @@ -250,9 +261,9 @@ /obj/item/clothing/suit/apron/overalls = 3, /obj/item/clothing/under/rank/civilian/hydroponics = 3, /obj/item/clothing/under/rank/civilian/hydroponics/skirt = 3, + /obj/item/clothing/mask/bandana/striped/botany = 3, /obj/item/clothing/under/plasmaman/botany = 3, /obj/item/clothing/head/helmet/space/plasmaman/botany = 3, - /obj/item/clothing/mask/bandana/botany = 3, /obj/item/clothing/accessory/armband/hydro = 3, /obj/item/clothing/head/cowboy = 3) contraband = list(/obj/item/clothing/suit/hooded/wintercoat/hydro/old = 3) @@ -370,6 +381,7 @@ /obj/item/computer_hardware/hard_drive/role/janitor = 2, /obj/item/clothing/gloves/color/black = 2, /obj/item/clothing/head/soft/purple = 2, + /obj/item/clothing/mask/bandana/purple = 2, /obj/item/pushbroom = 2, /obj/item/paint/paint_remover = 2, /obj/item/melee/flyswatter = 2, diff --git a/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm b/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm index 8bfb1997822da..7a32176d15f95 100644 --- a/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm +++ b/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm @@ -80,7 +80,7 @@ return TRUE /datum/xenoartifact_trait/minor/sharp/on_init(obj/item/xenoartifact/X) - X.sharpness = IS_SHARP_ACCURATE + X.sharpness = SHARP X.bleed_force = BLEED_CUT X.force = X.charge_req*0.12 X.attack_verb_continuous = list("cleaves", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") diff --git a/html/changelog.html b/html/changelog.html index 664a876c0d137..b3678e7091064 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,68 @@ -->
    +

    24 December 2024

    +

    BarteG44 updated:

    +
      +
    • Removes the second wire from the c4 charge
    • +
    +

    DeltaFire15 updated:

    +
      +
    • keycard authentication devices require an ID to use.
    • +
    • IDs used to initiate / confirm keycard auth events must not be the same ID.
    • +
    +

    PowerfulBacon updated:

    +
      +
    • Clients running 515 will now be able to see icons in the alt-click stat panel menu.
    • +
    +

    Rukofamicom updated:

    +
      +
    • Completely overhauled dismemberment and weapon sharpness. Weapons now have four levels of sharpness: Blunt, Sharp, Dismember and Easy Dismember.
    • +
    • Blunt weapons are now only able to cause dismemberment on species that have the easy dismemberment trait, all of which can easily regenerate or otherwise slap their dismembered limb back into place.
    • +
    • Species with the easy dismemberment trait (Skeletons, IPCs, Oozelings) have a chance equal to the damage received to lose a targetted limb as long as the limb was already damaged before being struck.
    • +
    • Ordinary sharp weapons such as knives and surgical tools can only dismember a dead target.
    • +
    • Large weapons such as swords, axes and chainsaws are only able to dismember a limb which has already been fully disabled. This means that it will take at least three hits with a fire axe to take someone's leg off.
    • +
    • Bladed energy weapons have a chance equal to their damage to dismember a targetted limb regardless of how much damage it has taken, in addition to being guaranteed to dismember a limb that has been fully disabled by damage. The nightmare's light eater is the only non-energy weapon in this group right now.
    • +
    • Mobs cannot be decapitated through the simplified mechanics while they are fully conscious - they must at minimum be asleep or in crit in order for dismemberment to apply when targetting someone's head for balance reasons.
    • +
    +

    Therealdoooc213 updated:

    +
      +
    • the blackbox is now a large item
    • +
    +

    XeonMations updated:

    +
      +
    • Fixed AIs being unable to select a crew member as a hologram.
    • +
    • TGUI-ified the AI hologram selection menu.
    • +
    +

    XeonMations, ManiacalAnxiety, therealdoooc213 updated:

    +
      +
    • Split personalities can no longer throw out their original body's mind out of their own body permenantly.
    • +
    +

    XeonMations, timothymtorres updated:

    +
      +
    • Fixed a lot of oversights related to gravity, such as lavaland not having gravity or simplemobs floating roundstart.
    • +
    • You can no longer defy gravity through the power of love
    • +
    +

    rkz, Ebb-Real, AnturK updated:

    +
      +
    • GAGSifies bandanas
    • +
    • refactors large mob icons to no longer need snowflaked .dmi sizes. Just edit a variable
    • +
    +

    rkz, MrMelbert, Cyberboss updated:

    +
      +
    • refactored language holders, species changes will no longer delete all known languages
    • +
    • refactored tongue language lists to kill typecache nonsense and handle subtypes sanely
    • +
    • unit tests language transfers
    • +
    • fix config errors before /world/New()
    • +
    +

    rkz, haukeschaumann, JohnFulpWillard, jlsnow301, Crumpaloo, San7890, MrStonedOne, Lilah Novi updated:

    +
      +
    • fix custom typing indicators. Cyborgs, xenos, and lawyers (among others) now have unique typing indicators again after 3 years.
    • +
    • new *Animated* typing indicator sprites
    • +
    • typing in the command bar will now activate typing indicator.
    • +
    • traitified a typing indicator var
    • +
    +

    22 December 2024

    BarteG44 updated:

      diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index cc31079781f8b..be9c1b3cd1326 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -45235,3 +45235,64 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - bugfix: you can no longer get to centcom with warped runes Tsar-Salat: - bugfix: fixes segmented turf textures applying to nonsegmented turfs... very ugly... +2024-12-24: + BarteG44: + - tweak: Removes the second wire from the c4 charge + DeltaFire15: + - balance: keycard authentication devices require an ID to use. + - balance: IDs used to initiate / confirm keycard auth events must not be the same + ID. + PowerfulBacon: + - rscadd: Clients running 515 will now be able to see icons in the alt-click stat + panel menu. + Rukofamicom: + - balance: 'Completely overhauled dismemberment and weapon sharpness. Weapons now + have four levels of sharpness: Blunt, Sharp, Dismember and Easy Dismember.' + - balance: Blunt weapons are now only able to cause dismemberment on species that + have the easy dismemberment trait, all of which can easily regenerate or otherwise + slap their dismembered limb back into place. + - balance: Species with the easy dismemberment trait (Skeletons, IPCs, Oozelings) + have a chance equal to the damage received to lose a targetted limb as long + as the limb was already damaged before being struck. + - balance: Ordinary sharp weapons such as knives and surgical tools can only dismember + a dead target. + - balance: Large weapons such as swords, axes and chainsaws are only able to dismember + a limb which has already been fully disabled. This means that it will take at + least three hits with a fire axe to take someone's leg off. + - balance: Bladed energy weapons have a chance equal to their damage to dismember + a targetted limb regardless of how much damage it has taken, in addition to + being guaranteed to dismember a limb that has been fully disabled by damage. + The nightmare's light eater is the only non-energy weapon in this group right + now. + - balance: Mobs cannot be decapitated through the simplified mechanics while they + are fully conscious - they must at minimum be asleep or in crit in order for + dismemberment to apply when targetting someone's head for balance reasons. + Therealdoooc213: + - tweak: the blackbox is now a large item + XeonMations: + - bugfix: Fixed AIs being unable to select a crew member as a hologram. + - refactor: TGUI-ified the AI hologram selection menu. + XeonMations, ManiacalAnxiety, therealdoooc213: + - bugfix: Split personalities can no longer throw out their original body's mind + out of their own body permenantly. + XeonMations, timothymtorres: + - bugfix: Fixed a lot of oversights related to gravity, such as lavaland not having + gravity or simplemobs floating roundstart. + - bugfix: You can no longer defy gravity through the power of love + rkz, Ebb-Real, AnturK: + - rscadd: GAGSifies bandanas + - refactor: refactors large mob icons to no longer need snowflaked .dmi sizes. Just + edit a variable + rkz, MrMelbert, Cyberboss: + - refactor: refactored language holders, species changes will no longer delete all + known languages + - refactor: refactored tongue language lists to kill typecache nonsense and handle + subtypes sanely + - code_imp: unit tests language transfers + - code_imp: fix config errors before /world/New() + rkz, haukeschaumann, JohnFulpWillard, jlsnow301, Crumpaloo, San7890, MrStonedOne, Lilah Novi: + - bugfix: fix custom typing indicators. Cyborgs, xenos, and lawyers (among others) + now have unique typing indicators again after 3 years. + - rscadd: new *Animated* typing indicator sprites + - rscadd: typing in the command bar will now activate typing indicator. + - code_imp: traitified a typing indicator var diff --git a/html/typing_indicator.html b/html/typing_indicator.html new file mode 100644 index 0000000000000..2988edff55fa0 --- /dev/null +++ b/html/typing_indicator.html @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/icons/mob/clothing/head/costume.dmi b/icons/mob/clothing/head/costume.dmi index 5c7146529650f..13a743de03452 100644 Binary files a/icons/mob/clothing/head/costume.dmi and b/icons/mob/clothing/head/costume.dmi differ diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi index 130204b8bce9e..e5f8a40a057a4 100644 Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index b5514e6cadfdc..25e03333e6587 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/large-worn-icons/64x64/head.dmi b/icons/mob/large-worn-icons/64x64/head.dmi deleted file mode 100644 index 6486f3a4a1bea..0000000000000 Binary files a/icons/mob/large-worn-icons/64x64/head.dmi and /dev/null differ diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi index 429e54980382a..1beb0adf98636 100644 Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 13f977d2e0a16..23475b642f0a0 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index e8643569a7a5a..335f2d218e238 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -119,6 +119,15 @@ window "mainwindow" anchor2 = none is-visible = false saved-params = "" + elem "commandbar_spy" + type = BROWSER + is-default = false + pos = 0,0 + size = 200x200 + anchor1 = -1,-1 + anchor2 = -1,-1 + is-visible = false + saved-params = "" window "mapwindow" elem "mapwindow" diff --git a/tgui/global.d.ts b/tgui/global.d.ts index 6e28fc9be14a1..af2db9ac7fd59 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -34,6 +34,16 @@ type ByondType = { */ windowId: string; + /** + * The major version of byond. + */ + BYOND_MAJOR: string; + + /** + * The minor (build) version of byond. + */ + BYOND_MINOR: string; + /** * True if javascript is running in BYOND. */ diff --git a/tgui/packages/tgui-panel/stat/StatText.js b/tgui/packages/tgui-panel/stat/StatText.js index aa844f2a21642..f2c97846ad9c9 100644 --- a/tgui/packages/tgui-panel/stat/StatText.js +++ b/tgui/packages/tgui-panel/stat/StatText.js @@ -18,7 +18,7 @@ export const StatText = (props, context) => { } return (
      - + {statPanelData ? Object.keys(statPanelData) .filter((x) => x !== null) @@ -40,16 +40,25 @@ export const StatText = (props, context) => { /> )) || (statPanelData[key].type === STAT_ATOM && ( - + )) || (statPanelData[key].type === STAT_DIVIDER && ) || - (statPanelData[key].type === STAT_BLANK &&
      )) + (statPanelData[key].type === STAT_BLANK && ( + +
      +
      + ))) ) : 'No data'} {Object.keys(verbs).map((verb) => ( ))} -
      +
      ); }; @@ -101,7 +110,7 @@ const StatTagToClassName = (text) => { export const StatTextText = (props, context) => { const { title, text } = props; return ( - + {title}: {text} @@ -111,7 +120,7 @@ export const StatTextText = (props, context) => { export const StatTextButton = (props, context) => { const { title, text, action_id, params = [], multirow = false, buttons = [] } = props; return ( - + @@ -257,7 +275,11 @@ export const StatTextAtom = (props, context) => { }; export const StatTextDivider = (props, context) => { - return ; + return ( + + + + ); }; export const StatTextVerb = (props, context) => { diff --git a/tgui/packages/tgui-panel/styles/components/Stat.scss b/tgui/packages/tgui-panel/styles/components/Stat.scss index 3ac44c7cfe527..a80d2f6b9f0a4 100644 --- a/tgui/packages/tgui-panel/styles/components/Stat.scss +++ b/tgui/packages/tgui-panel/styles/components/Stat.scss @@ -100,3 +100,11 @@ $border-color: color.scale(colors.fg(colors.$primary), $lightness: 75%) !default background-color: #adadad; } } + +.StatMiddle { + vertical-align: middle; +} + +.StatWordWrap { + white-space: normal; +} diff --git a/tgui/public/tgui.html b/tgui/public/tgui.html index b84449c3fce8f..b60307601cb61 100644 --- a/tgui/public/tgui.html +++ b/tgui/public/tgui.html @@ -7,6 +7,8 @@ + +