diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 4998f10849e..c1d9e88786a 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -12,6 +12,8 @@ /// from /obj/item/toy/crayon/spraycan/afterattack: (user, spraycan, color_is_dark) #define COMSIG_OBJ_PAINTED "obj_painted" #define DONT_USE_SPRAYCAN_CHARGES (1<<0) +/// from /obj/obj_reskin: (mob/user, skin) +#define COMSIG_OBJ_RESKIN "obj_reskin" // /obj/machinery signals @@ -361,9 +363,9 @@ // /obj/projectile signals (sent to the firer) -///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, angle, hit_limb) +///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, angle, hit_limb, blocked) #define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" -///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, angle, hit_limb) +///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, angle, hit_limb, blocked) #define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target) #define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" @@ -387,6 +389,9 @@ ///sent to targets during the process_hit proc of projectiles #define COMSIG_FIRE_CASING "fire_casing" +///from the base of /obj/item/ammo_casing/ready_proj() : (atom/target, mob/living/user, quiet, zone_override, atom/fired_from) +#define COMSIG_CASING_READY_PROJECTILE "casing_ready_projectile" + ///sent to the projectile after an item is spawned by the projectile_drop element: (new_item) #define COMSIG_PROJECTILE_ON_SPAWN_DROP "projectile_on_spawn_drop" ///sent to the projectile when spawning the item (shrapnel) that may be embedded: (new_item) @@ -448,6 +453,12 @@ #define COMSIG_ITEM_AFTERATTACK_SECONDARY "item_afterattack_secondary" ///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params) #define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted" +///from base of obj/item/embedded(): (atom/target, obj/item/bodypart/part) +#define COMSIG_ITEM_EMBEDDED "item_embedded" +///from base of datum/component/embedded/safeRemove(): (mob/living/carbon/victim) +#define COMSIG_ITEM_UNEMBEDDED "item_unembedded" +/// from base of obj/item/failedEmbed() +#define COMSIG_ITEM_FAILED_EMBED "item_failed_embed" ///from /obj/item/assembly/proc/pulsed(mob/pulser) #define COMSIG_ASSEMBLY_PULSED "assembly_pulsed" @@ -481,3 +492,26 @@ /// from /obj/structure/cursed_slot_machine/determine_victor() when someone finally wins. #define COMSIG_GLOB_CURSED_SLOT_MACHINE_WON "cursed_slot_machine_won" + +/// from /datum/component/dart_insert/add_to_dart() : (obj/item/ammo_casing, mob/user) +#define COMSIG_DART_INSERT_ADDED "dart_insert_added" + +/// from /datum/component/dart_insert/remove_from_dart() : (obj/ammo_casing/dart, mob/user) +#define COMSIG_DART_INSERT_REMOVED "dart_insert_removed" + +/** + * from /datum/component/dart_insert/get_dart_var_modifiers() : (list/out_modifiers) + * + * valid indices for `out_modifiers` are: + * - `damage`: number + * - `speed`: number + * - `armour_penetration`: number + * - `wound_bonus`: number + * - `bare_wound_bonus`: number + * - `demolition_mod`: number + * - `embedding`: list with embedding params + */ +#define COMSIG_DART_INSERT_GET_VAR_MODIFIERS "dart_insert_get_var_modifiers" + +/// from /datum/component/dart_insert/on_reskin() +#define COMSIG_DART_INSERT_PARENT_RESKINNED "dart_insert_parent_reskinned" diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index dcdd1394253..6f078c28724 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -43,6 +43,8 @@ #define BODYPART_PSEUDOPART (1<<1) /// Bodypart did not match the owner's default bodypart limb_id when surgically implanted #define BODYPART_IMPLANTED (1<<2) +/// Bodypart never displays as a husk +#define BODYPART_UNHUSKABLE (1<<3) // Bodypart change blocking flags ///Bodypart does not get replaced during set_species() diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index a87142972fc..5a00323aacd 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -124,6 +124,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NUKEIMMUNE "nuke_immunity" /// Can't be given viruses #define TRAIT_VIRUSIMMUNE "virus_immunity" +/// Won't become a husk under any circumstances +#define TRAIT_UNHUSKABLE "trait_unhuskable" /// Reduces the chance viruses will spread to this mob, and if the mob has a virus, slows its advancement #define TRAIT_VIRUS_RESISTANCE "virus_resistance" #define TRAIT_GENELESS "geneless" @@ -538,6 +540,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Disables the floating animation. See above. #define TRAIT_NO_FLOATING_ANIM "no-floating-animation" +/// Cannot be turned into a funny skeleton by the plasma river +#define TRAIT_NO_PLASMA_TRANSFORM "no_plasma_transform" + /// Weather immunities, also protect mobs inside them. #define TRAIT_LAVA_IMMUNE "lava_immune" //Used by lava turfs and The Floor Is Lava. #define TRAIT_ASHSTORM_IMMUNE "ashstorm_immune" @@ -978,4 +983,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given to mobs that we do not want to mindswap #define TRAIT_NO_MINDSWAP "no_mindswap" +/// Trait given to foam darts that have an insert in them +#define TRAIT_DART_HAS_INSERT "dart_has_insert" // END TRAIT DEFINES diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index f6cb654b1d5..039533cffa5 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -103,6 +103,8 @@ #define VV_HK_ARMOR_MOD "mod_obj_armor" // /atom/movable +#define VV_HK_OBSERVE_FOLLOW "observe_follow" +#define VV_HK_GET_MOVABLE "get_movable" #define VV_HK_DEADCHAT_PLAYS "deadchat_plays" // /obj @@ -138,7 +140,6 @@ #define VV_HK_GIVE_GUARDIAN_SPIRIT "give_guardian_spirit" // /mob/living/carbon -#define VV_HK_MAKE_AI "aiify" #define VV_HK_MODIFY_BODYPART "mod_bodypart" #define VV_HK_MODIFY_ORGANS "organs_modify" #define VV_HK_MARTIAL_ART "give_martial_art" diff --git a/code/__DEFINES/~skyrat_defines/combat.dm b/code/__DEFINES/~skyrat_defines/combat.dm index 54659715cc3..a29811e9349 100644 --- a/code/__DEFINES/~skyrat_defines/combat.dm +++ b/code/__DEFINES/~skyrat_defines/combat.dm @@ -1,4 +1,3 @@ -#define PUNCH_STAMINA_MULTIPLIER 2.6 //Stamina threshold from which resisting a grab becomes hard #define STAMINA_THRESHOLD_HARD_RESIST 80 diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index cc3d083f640..58f4d61ea30 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -17,6 +17,18 @@ return final_color +/// Given a color in the format of "#RRGGBB" or "#RRGGBBAA", gives back a 4 entry list with the number values of each +/proc/split_color(color) + var/list/output = list() + output += hex2num(copytext(color, 2, 4)) + output += hex2num(copytext(color, 4, 6)) + output += hex2num(copytext(color, 6, 8)) + if(length(color) == 9) + output += hex2num(copytext(color, 8, 10)) + else + output += 255 + return output + ///Returns a random color picked from a list, has 2 modes (0 and 1), mode 1 doesn't pick white, black or gray /proc/random_colour(mode = 0) switch(mode) diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index 116fb34fad5..c28357eb478 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -217,3 +217,8 @@ return max(new_value, threshold) if(sign == -1) return min(new_value, threshold * -1) + +/// Takes two values x and y, and returns 1/((1/x) + y) +/// Useful for providing an additive modifier to a value that is used as a divisor, such as `/obj/projectile/var/speed` +/proc/reciprocal_add(x, y) + return 1/((1/x)+y) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index a1c9567814c..d9e28da2988 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -282,6 +282,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_DNA_SCRAMBLE" = TRAIT_NO_DNA_SCRAMBLE, "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, + "TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, "TRAIT_NO_GUN_AKIMBO" = TRAIT_NO_GUN_AKIMBO, "TRAIT_NO_IMMOBILIZE" = TRAIT_NO_IMMOBILIZE, "TRAIT_NO_JUMPSUIT" = TRAIT_NO_JUMPSUIT, @@ -423,6 +424,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNBREAKABLE" = TRAIT_UNBREAKABLE, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, + "TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, @@ -473,6 +475,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE, "TRAIT_WIELDED" = TRAIT_WIELDED, ), + /obj/item/ammo_casing = list( + "TRAIT_DART_HAS_INSERT" = TRAIT_DART_HAS_INSERT, + ), /obj/item/bodypart = list( "TRAIT_DISABLED_BY_WOUND" = TRAIT_DISABLED_BY_WOUND, "TRAIT_IGNORED_BY_LIVING_FLESH" = TRAIT_IGNORED_BY_LIVING_FLESH, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index b65a31c79f7..26c419723cb 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -129,6 +129,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY, "TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, + "TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, "TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, @@ -214,6 +215,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, + "TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/datums/components/dart_insert.dm b/code/datums/components/dart_insert.dm new file mode 100644 index 00000000000..03d1d689357 --- /dev/null +++ b/code/datums/components/dart_insert.dm @@ -0,0 +1,161 @@ +/** + * Component for allowing items to be inserted into foam darts. + * The parent can register signal handlers for `COMSIG_DART_INSERT_ADDED`, + * `COMSIG_DART_INSERT_REMOVED` to define custom behavior for when the item + * is added to/removed from a dart, and `COMSIG_DART_INSERT_GET_VAR_MODIFIERS` + * to define the modifications the item makes to the vars of the fired projectile. + */ +/datum/component/dart_insert + /// List for tracking the modifications this component has made to the vars of the containing projectile + var/list/var_modifiers + /// A reference to the ammo casing this component's parent was inserted into + var/obj/item/ammo_casing/holder_casing + /// A reference to the projectile this component's parent was inserted into + var/obj/projectile/holder_projectile + /// The icon file used for the overlay applied over the containing ammo casing + var/casing_overlay_icon + /// The icon state used for the overlay applied over the containing ammo casing + var/casing_overlay_icon_state + /// The icon file used for the overlay applied over the containing projectile + var/projectile_overlay_icon + /// The icon state used for the overlay applied over the containing projectile + var/projectile_overlay_icon_state + +/datum/component/dart_insert/Initialize(_casing_overlay_icon, _casing_overlay_icon_state, _projectile_overlay_icon, _projectile_overlay_icon_state) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + casing_overlay_icon = _casing_overlay_icon + casing_overlay_icon_state = _casing_overlay_icon_state + projectile_overlay_icon = _projectile_overlay_icon + projectile_overlay_icon_state = _projectile_overlay_icon_state + +/datum/component/dart_insert/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack)) + RegisterSignal(parent, COMSIG_OBJ_RESKIN, PROC_REF(on_reskin)) + +/datum/component/dart_insert/UnregisterFromParent() + . = ..() + var/obj/item/parent_item = parent + var/parent_loc = parent_item.loc + if(parent_loc && (parent_loc == holder_casing || parent_loc == holder_projectile)) + parent_item.forceMove(get_turf(parent_item)) + remove_from_dart(holder_casing, holder_projectile) + UnregisterSignal(parent, COMSIG_ITEM_PRE_ATTACK) + +/datum/component/dart_insert/proc/on_preattack(datum/source, atom/target, mob/user, params) + SIGNAL_HANDLER + var/obj/item/ammo_casing/foam_dart/dart = target + if(!istype(dart)) + return + if(!dart.modified) + to_chat(user, span_warning("The safety cap prevents you from inserting [parent] into [dart].")) + return COMPONENT_CANCEL_ATTACK_CHAIN + if(HAS_TRAIT(dart, TRAIT_DART_HAS_INSERT)) + to_chat(user, span_warning("There's already something in [dart].")) + return COMPONENT_CANCEL_ATTACK_CHAIN + add_to_dart(dart, user) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/component/dart_insert/proc/on_reskin(datum/source, mob/user, skin) + SIGNAL_HANDLER + SEND_SIGNAL(parent, COMSIG_DART_INSERT_PARENT_RESKINNED) + +/datum/component/dart_insert/proc/add_to_dart(obj/item/ammo_casing/dart, mob/user) + var/obj/projectile/dart_projectile = dart.loaded_projectile + var/obj/item/parent_item = parent + if(user) + if(!user.transferItemToLoc(parent_item, dart_projectile)) + return + to_chat(user, span_notice("You insert [parent_item] into [dart].")) + else + parent_item.forceMove(dart_projectile) + ADD_TRAIT(dart, TRAIT_DART_HAS_INSERT, REF(src)) + RegisterSignal(dart, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_dart_attack_self)) + RegisterSignal(dart, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_dart_examine_more)) + RegisterSignals(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED), PROC_REF(on_leave_dart)) + RegisterSignal(dart, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_casing_update_overlays)) + RegisterSignal(dart_projectile, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_projectile_update_overlays)) + RegisterSignals(dart_projectile, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(on_spawn_drop)) + apply_var_modifiers(dart_projectile) + dart.harmful = dart_projectile.damage > 0 || dart_projectile.wound_bonus > 0 || dart_projectile.bare_wound_bonus > 0 + SEND_SIGNAL(parent, COMSIG_DART_INSERT_ADDED, dart) + dart.update_appearance() + dart_projectile.update_appearance() + holder_casing = dart + holder_projectile = dart_projectile + +/datum/component/dart_insert/proc/remove_from_dart(obj/item/ammo_casing/dart, obj/projectile/projectile, mob/user) + holder_casing = null + holder_projectile = null + if(istype(dart)) + UnregisterSignal(dart, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ATOM_EXAMINE_MORE, COMSIG_ATOM_UPDATE_OVERLAYS)) + REMOVE_TRAIT(dart, TRAIT_DART_HAS_INSERT, REF(src)) + dart.update_appearance() + if(istype(projectile)) + remove_var_modifiers(projectile) + UnregisterSignal(projectile, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, COMSIG_ATOM_UPDATE_OVERLAYS)) + if(dart?.loaded_projectile == projectile) + dart.harmful = projectile.damage > 0 || projectile.wound_bonus > 0 || projectile.bare_wound_bonus > 0 + projectile.update_appearance() + SEND_SIGNAL(parent, COMSIG_DART_INSERT_REMOVED, dart, projectile, user) + UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED)) + if(user) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, put_in_hands), parent) + to_chat(user, span_notice("You remove [parent] from [dart].")) + +/datum/component/dart_insert/proc/on_dart_attack_self(datum/source, mob/user) + SIGNAL_HANDLER + remove_from_dart(holder_casing, holder_projectile, user) + +/datum/component/dart_insert/proc/on_dart_examine_more(datum/source, mob/user, list/examine_list) + var/obj/item/parent_item = parent + examine_list += span_notice("You can see a [parent_item.name] inserted into it.") + +/datum/component/dart_insert/proc/on_leave_dart() + SIGNAL_HANDLER + remove_from_dart(holder_casing, holder_projectile) + +/datum/component/dart_insert/proc/on_spawn_drop(datum/source, obj/item/ammo_casing/new_casing) + SIGNAL_HANDLER + UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED)) + add_to_dart(new_casing) + +/datum/component/dart_insert/proc/on_casing_update_overlays(datum/source, list/new_overlays) + SIGNAL_HANDLER + new_overlays += mutable_appearance(casing_overlay_icon, casing_overlay_icon_state) + +/datum/component/dart_insert/proc/on_projectile_update_overlays(datum/source, list/new_overlays) + SIGNAL_HANDLER + new_overlays += mutable_appearance(projectile_overlay_icon, projectile_overlay_icon_state) + +/datum/component/dart_insert/proc/apply_var_modifiers(obj/projectile/projectile) + LAZYINITLIST(var_modifiers) + SEND_SIGNAL(parent, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, var_modifiers) + projectile.damage += var_modifiers["damage"] + if(var_modifiers["speed"]) + var_modifiers["speed"] = reciprocal_add(projectile.speed, var_modifiers["speed"]) - projectile.speed + projectile.speed += var_modifiers["speed"] + projectile.armour_penetration += var_modifiers["armour_penetration"] + projectile.wound_bonus += var_modifiers["wound_bonus"] + projectile.bare_wound_bonus += var_modifiers["bare_wound_bonus"] + projectile.demolition_mod += var_modifiers["demolition_mod"] + if(islist(var_modifiers["embedding"])) + var/list/embed_params = var_modifiers["embedding"] + for(var/embed_param in embed_params - "ignore_throwspeed_threshold") + LAZYADDASSOC(projectile.embedding, embed_param, embed_params[embed_param]) + projectile.updateEmbedding() + +/datum/component/dart_insert/proc/remove_var_modifiers(obj/projectile/projectile) + projectile.damage -= var_modifiers["damage"] + projectile.speed -= var_modifiers["speed"] + projectile.armour_penetration -= var_modifiers["armour_penetration"] + projectile.wound_bonus -= var_modifiers["wound_bonus"] + projectile.bare_wound_bonus -= var_modifiers["bare_wound_bonus"] + projectile.demolition_mod -= var_modifiers["demolition_mod"] + if(islist(var_modifiers["embedding"])) + var/list/embed_params = var_modifiers["embedding"] + for(var/embed_param in embed_params - "ignore_throwspeed_threshold") + LAZYADDASSOC(projectile.embedding, embed_param, -embed_params[embed_param]) + projectile.updateEmbedding() + var_modifiers.Cut() diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index f4d7b5d7369..b62121d30d0 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -228,6 +228,7 @@ limb._unembed_object(weapon) UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) // have to do it here otherwise we trigger weaponDeleted() + SEND_SIGNAL(weapon, COMSIG_ITEM_UNEMBEDDED, victim) if(!weapon.unembedded()) // if it hasn't deleted itself due to drop del UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) if(to_hands) diff --git a/code/datums/components/udder.dm b/code/datums/components/udder.dm index 7a2f7b56b7b..3c8a0297897 100644 --- a/code/datums/components/udder.dm +++ b/code/datums/components/udder.dm @@ -10,11 +10,11 @@ var/datum/callback/on_milk_callback //udder_type and reagent_produced_typepath are typepaths, not reference -/datum/component/udder/Initialize(udder_type = /obj/item/udder, datum/callback/on_milk_callback, datum/callback/on_generate_callback, reagent_produced_typepath = /datum/reagent/consumable/milk) +/datum/component/udder/Initialize(udder_type = /obj/item/udder, datum/callback/on_milk_callback, datum/callback/on_generate_callback, reagent_produced_override) if(!isliving(parent)) //technically is possible to drop this on carbons... but you wouldn't do that to me, would you? return COMPONENT_INCOMPATIBLE udder = new udder_type(null) - udder.add_features(parent, on_generate_callback, reagent_produced_typepath) + udder.add_features(parent, on_generate_callback, reagent_produced_override) src.on_milk_callback = on_milk_callback /datum/component/udder/RegisterWithParent() @@ -67,6 +67,8 @@ var/reagent_produced_typepath = /datum/reagent/consumable/milk ///how much the udder holds var/size = 50 + ///the probability that the udder will produce the reagent (0 - 100) + var/production_probability = 5 ///mob that has the udder component var/mob/living/udder_mob ///optional proc to callback to when the udder generates milk @@ -78,11 +80,12 @@ ///hunger key we set to look for food var/hunger_key = BB_CHECK_HUNGRY -/obj/item/udder/proc/add_features(parent, callback, reagent = /datum/reagent/consumable/milk) +/obj/item/udder/proc/add_features(parent, callback, reagent_override) udder_mob = parent on_generate_callback = callback create_reagents(size, REAGENT_HOLDER_ALIVE) - reagent_produced_typepath = reagent + if(reagent_override) + reagent_produced_typepath = reagent_override initial_conditions() if(isnull(require_consume_type)) return @@ -157,12 +160,13 @@ */ /obj/item/udder/proc/generate() if(!isnull(require_consume_type) && !(locate(require_consume_type) in src)) - return - if(prob(95)) - return + return FALSE + if(!prob(production_probability)) + return FALSE reagents.add_reagent(reagent_produced_typepath, rand(5, 10), added_purity = 1) if(on_generate_callback) on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume) + return TRUE /** * Proc called from attacking the component parent with the correct item, moves reagents into the glass basically. diff --git a/code/datums/elements/caseless.dm b/code/datums/elements/caseless.dm index a8a1d3df3e4..587a32f2b30 100644 --- a/code/datums/elements/caseless.dm +++ b/code/datums/elements/caseless.dm @@ -13,15 +13,23 @@ if(!isammocasing(target)) return ELEMENT_INCOMPATIBLE src.reusable = reusable + RegisterSignal(target, COMSIG_CASING_READY_PROJECTILE, PROC_REF(on_ready_projectile)) RegisterSignal(target, COMSIG_FIRE_CASING, PROC_REF(on_fired_casing)) -/datum/element/caseless/proc/on_fired_casing(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj) +/datum/element/caseless/proc/on_ready_projectile(obj/item/ammo_casing/shell, atom/target, mob/living/user, quiet, zone_override, atom/fired_from) SIGNAL_HANDLER + var/obj/projectile/proj = shell.loaded_projectile if(isnull(proj)) return if(reusable) + if(!ispath(proj.shrapnel_type)) + proj.shrapnel_type = shell.type + proj.updateEmbedding() proj.AddElement(/datum/element/projectile_drop, shell.type) +/datum/element/caseless/proc/on_fired_casing(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj) + SIGNAL_HANDLER + if(isgun(fired_from)) var/obj/item/gun/shot_from = fired_from if(shot_from.chambered == shell) diff --git a/code/datums/mutations/tongue_spike.dm b/code/datums/mutations/tongue_spike.dm index b33b78d7d1b..e6249041250 100644 --- a/code/datums/mutations/tongue_spike.dm +++ b/code/datums/mutations/tongue_spike.dm @@ -73,6 +73,7 @@ unembedded() /obj/item/hardened_spike/embedded(atom/target) + . = ..() if(isbodypart(target)) missed = FALSE @@ -121,6 +122,7 @@ var/embedded_once_alread = FALSE /obj/item/hardened_spike/chem/embedded(mob/living/carbon/human/embedded_mob) + . = ..() if(embedded_once_alread) return embedded_once_alread = TRUE diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 9208ea7a9a2..b200e688caa 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1460,12 +1460,6 @@ animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform=rotated_transform, time = 1, easing=BACK_EASING|EASE_IN, flags = ANIMATION_PARALLEL) animate(pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform=initial_transform, time = 2, easing=SINE_EASING, flags = ANIMATION_PARALLEL) -/atom/movable/vv_get_dropdown() - . = ..() - . += "" - . += "" - - /* Language procs * Unless you are doing something very specific, these are the ones you want to use. */ @@ -1630,6 +1624,9 @@ /atom/movable/vv_get_dropdown() . = ..() + VV_DROPDOWN_OPTION("", "---------") + VV_DROPDOWN_OPTION(VV_HK_OBSERVE_FOLLOW, "Observe Follow") + VV_DROPDOWN_OPTION(VV_HK_GET_MOVABLE, "Get Movable") VV_DROPDOWN_OPTION(VV_HK_EDIT_PARTICLES, "Edit Particles") VV_DROPDOWN_OPTION(VV_HK_DEADCHAT_PLAYS, "Start/Stop Deadchat Plays") VV_DROPDOWN_OPTION(VV_HK_ADD_FANTASY_AFFIX, "Add Fantasy Affix") @@ -1640,6 +1637,19 @@ if(!.) return + if(href_list[VV_HK_OBSERVE_FOLLOW]) + if(!check_rights(R_ADMIN)) + return + usr.client?.admin_follow(src) + + if(href_list[VV_HK_GET_MOVABLE]) + if(!check_rights(R_ADMIN)) + return + + if(QDELETED(src)) + return + forceMove(get_turf(usr)) + if(href_list[VV_HK_EDIT_PARTICLES] && check_rights(R_VAREDIT)) var/client/C = usr.client C?.open_particle_editor(src) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 946bdb6d6cb..1a62fa0261b 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -64,11 +64,17 @@ /obj/machinery/autolathe/ui_static_data(mob/user) var/list/data = materials.ui_static_data() - data["designs"] = handle_designs(stored_research.researched_designs) + var/max_available = materials.total_amount() + for(var/datum/material/container_mat as anything in materials.materials) + var/available = materials.materials[container_mat] + if(available) + max_available = max(max_available, available) + + data["designs"] = handle_designs(stored_research.researched_designs, max_available) if(imported_designs.len) - data["designs"] += handle_designs(imported_designs) + data["designs"] += handle_designs(imported_designs, max_available) if(hacked) - data["designs"] += handle_designs(stored_research.hacked_designs) + data["designs"] += handle_designs(stored_research.hacked_designs, max_available) return data @@ -83,7 +89,7 @@ return data -/obj/machinery/autolathe/proc/handle_designs(list/designs) +/obj/machinery/autolathe/proc/handle_designs(list/designs, max_available) var/list/output = list() var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) @@ -108,7 +114,13 @@ else cost[i] = design_cost - max_multiplier = min(max_multiplier, 50, round((istype(mat) ? materials.get_material_amount(i) : 0) / design_cost)) + var/mat_available + if(istype(mat)) //regular mat + mat_available = materials.get_material_amount(mat) + else //category mat means we can make it from any mat, use largest available mat + mat_available = max_available + + max_multiplier = min(max_multiplier, 50, round(mat_available / design_cost)) //create & send ui data var/icon_size = spritesheet.icon_size_id(design.id) @@ -208,6 +220,7 @@ materials.use_materials(materials_used, coeff, multiplier) to_chat(usr, span_notice("You print [multiplier] item(s) from the [src]")) update_static_data_for_all_viewers() + //print item icon_state = "autolathe_n" var/time_per_item = is_stack ? 32 : ((32 * coeff * multiplier) ** 0.8) / multiplier @@ -215,21 +228,26 @@ return TRUE +/obj/machinery/autolathe/crowbar_act(mob/living/user, obj/item/tool) + if(default_deconstruction_crowbar(tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/autolathe/screwdriver_act_secondary(mob/living/user, obj/item/tool) + if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS + /obj/machinery/autolathe/attackby(obj/item/attacking_item, mob/living/user, params) + if(user.combat_mode) //so we can hit the machine + return ..() + if(busy) balloon_alert(user, "it's busy!") return TRUE - if(default_deconstruction_crowbar(attacking_item)) - return TRUE - if(panel_open && is_wire_tool(attacking_item)) wires.interact(user) return TRUE - if(user.combat_mode) //so we can hit the machine - return ..() - if(machine_stat) return TRUE @@ -258,45 +276,16 @@ balloon_alert(user, "close the panel first!") return FALSE - if(istype(attacking_item, /obj/item/storage/bag/trash)) - for(var/obj/item/content_item in attacking_item.contents) - if(!do_after(user, 0.5 SECONDS, src)) - return FALSE - attackby(content_item, user) - return TRUE - return ..() -/obj/machinery/autolathe/attackby_secondary(obj/item/weapon, mob/living/user, params) - . = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - if(busy) - balloon_alert(user, "it's busy!") - return - - if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", weapon)) - return - - if(machine_stat) - return SECONDARY_ATTACK_CALL_NORMAL - - if(panel_open) - balloon_alert(user, "close the panel first!") - return - - return SECONDARY_ATTACK_CALL_NORMAL - /obj/machinery/autolathe/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context) SIGNAL_HANDLER - if(ispath(item_inserted, /obj/item/stack/ore/bluespace_crystal)) - use_power(SHEET_MATERIAL_AMOUNT / 10) - else if(item_inserted.has_material_type(/datum/material/glass)) - flick("autolathe_r", src)//plays glass insertion animation by default otherwise - else - flick("autolathe_o", src)//plays metal insertion animation + flick("autolathe_[item_inserted.has_material_type(/datum/material/glass) ? "r" : "o"]", src) - use_power(min(active_power_usage * 0.25, amount_inserted / 100)) - update_static_data_for_all_viewers() + use_power(min(active_power_usage * 0.25, amount_inserted / 100)) + + update_static_data_for_all_viewers() /obj/machinery/autolathe/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) . = ..() @@ -311,7 +300,6 @@ /obj/machinery/autolathe/proc/make_items(list/picked_materials, multiplier, is_stack, mob/user, time_per_item) var/atom/our_loc = drop_location() var/atom/drop_loc = get_step(src, drop_direction) - var/client_awarded = FALSE busy = TRUE SStgui.update_uis(src) //so ui immediatly knows its busy @@ -327,12 +315,10 @@ //custom materials for toolboxes if(length(picked_materials)) - new_item.set_custom_materials(picked_materials, 1 / multiplier) //Ensure we get the non multiplied amount - if(!client_awarded) //so we dont award the medal multiple times - for(var/datum/material/mat in picked_materials) - if(!istype(mat, /datum/material/glass) && !istype(mat, /datum/material/iron)) - user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, user) - client_awarded = TRUE + new_item.set_custom_materials(picked_materials) //Ensure we get the non multiplied amount + for(var/datum/material/mat in picked_materials) + if(!istype(mat, /datum/material/glass) && !istype(mat, /datum/material/iron)) + user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, user) //no need to call if ontop of us if(drop_direction) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d592cd0790b..55cdf19f960 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1177,7 +1177,8 @@ return ..() /obj/item/proc/embedded(atom/embedded_target, obj/item/bodypart/part) - return + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ITEM_EMBEDDED, embedded_target, part) /obj/item/proc/unembedded() if(item_flags & DROPDEL && !QDELETED(src)) @@ -1206,6 +1207,8 @@ ///In case we want to do something special (like self delete) upon failing to embed in something. /obj/item/proc/failedEmbed() + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ITEM_FAILED_EMBED) if(item_flags & DROPDEL && !QDELETED(src)) qdel(src) diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 297c8a1eabd..ab97026a6a1 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -138,14 +138,14 @@ var/list/structures_to_ignore if(istype(target, /obj/structure/grille)) if(is_full_tile) //if we are trying to build full-tile windows we ignore the grille - structures_to_ignore = list(target) - else //no building directional windows on grills - return FALSE + structures_to_ignore = list(/obj/structure/grille) + else //when building directional windows we ignore the grill and other directional windows + structures_to_ignore = list(/obj/structure/grille, /obj/structure/window) else //for directional windows we ignore other directional windows as they can be in diffrent directions on the turf. structures_to_ignore = list(/obj/structure/window) //check if we can build our window on the grill - if(target_turf.is_blocked_turf(exclude_mobs = !is_full_tile, source_atom = null, ignore_atoms = structures_to_ignore, type_list = !is_full_tile)) + if(target_turf.is_blocked_turf(exclude_mobs = !is_full_tile, source_atom = null, ignore_atoms = structures_to_ignore, type_list = TRUE)) playsound(loc, 'sound/machines/click.ogg', 50, TRUE) balloon_alert(user, "something is blocking the turf") return FALSE diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 1c34e75c3d1..a7263520ad8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -292,7 +292,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) * Arguments: * * M The mob choosing a reskin option */ -/obj/proc/reskin_obj(mob/M) +/obj/proc/reskin_obj(mob/user) if(!LAZYLEN(unique_reskin)) return @@ -302,14 +302,15 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) items += list("[reskin_option]" = item_image) sort_list(items) - var/pick = show_radial_menu(M, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), M), radius = 38, require_near = TRUE) + var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), user), radius = 38, require_near = TRUE) if(!pick) return if(!unique_reskin[pick]) return current_skin = pick icon_state = unique_reskin[pick] - to_chat(M, "[src] is now skinned as '[pick].'") + to_chat(user, "[src] is now skinned as '[pick].'") + SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick) /** * Checks if we are allowed to interact with a radial menu for reskins diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index bb82c6fb294..73f3972ef83 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -68,7 +68,13 @@ var/cost = 0 var/delay = 0 - if(the_rcd.rcd_design_path == /obj/structure/window/fulltile) + if(the_rcd.rcd_design_path == /obj/structure/window) + cost = 4 + delay = 2 SECONDS + else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced) + cost = 6 + delay = 2.5 SECONDS + else if(the_rcd.rcd_design_path == /obj/structure/window/fulltile) cost = 8 delay = 3 SECONDS else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced/fulltile) @@ -101,8 +107,13 @@ var/obj/structure/window/window_path = rcd_data["[RCD_DESIGN_PATH]"] if(!ispath(window_path)) CRASH("Invalid window path type in RCD: [window_path]") - if(!initial(window_path.fulltile)) //only fulltile windows can be built here - return FALSE + + //checks if its a valid build direction + if(!initial(window_path.fulltile)) + if(!valid_build_direction(loc, user.dir, is_fulltile = FALSE)) + balloon_alert(user, "window already here!") + return FALSE + var/obj/structure/window/WD = new window_path(T, user.dir) WD.set_anchored(TRUE) return TRUE diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 4260e7ba19f..a1676f0d39f 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -26,7 +26,6 @@ var/fulltile = FALSE var/glass_type = /obj/item/stack/sheet/glass var/glass_amount = 1 - var/mutable_appearance/crack_overlay var/real_explosion_block //ignore this, just use explosion_block var/break_sound = SFX_SHATTER var/knock_sound = 'sound/effects/glassknock.ogg' @@ -419,11 +418,9 @@ var/ratio = atom_integrity / max_integrity ratio = CEILING(ratio*4, 1) * 25 - cut_overlay(crack_overlay) if(ratio > 75) return - crack_overlay = mutable_appearance('icons/obj/structures.dmi', "damage[ratio]", -(layer+0.1)) - . += crack_overlay + . += mutable_appearance('icons/obj/structures.dmi', "damage[ratio]", -(layer+0.1)) /obj/structure/window/should_atmos_process(datum/gas_mixture/air, exposed_temperature) return exposed_temperature > T0C + heat_resistance diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 3b382069f58..cce5a49e993 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -368,37 +368,40 @@ /turf/open/lava/plasma/do_burn(atom/movable/burn_target, seconds_per_tick = 1) . = TRUE - if(isobj(burn_target)) - return FALSE // Does nothing against objects. Old code. + if(!isliving(burn_target)) + return FALSE var/mob/living/burn_living = burn_target - burn_living.adjustFireLoss(2) - if(QDELETED(burn_living)) - return - burn_living.adjust_fire_stacks(20) //dipping into a stream of plasma would probably make you more flammable than usual - burn_living.adjust_bodytemperature(-rand(50,65)) //its cold, man - if(!ishuman(burn_living) || SPT_PROB(65, seconds_per_tick)) + var/need_mob_update + // This is from plasma, so it should obey plasma biotype requirements + need_mob_update += burn_living.adjustToxLoss(15, updating_health = FALSE, required_biotype = MOB_ORGANIC) + need_mob_update += burn_living.adjustFireLoss(25, updating_health = FALSE) + if(need_mob_update) + burn_living.updatehealth() + + if(QDELETED(burn_living) \ + || !ishuman(burn_living) \ + || HAS_TRAIT(burn_living, TRAIT_NODISMEMBER) \ + || HAS_TRAIT(burn_living, TRAIT_NO_PLASMA_TRANSFORM) \ + || SPT_PROB(65, seconds_per_tick) \ + ) return + var/mob/living/carbon/human/burn_human = burn_living - var/datum/species/burn_species = burn_human.dna.species - if(istype(burn_species, /datum/species/plasmaman) || istype(burn_species, /datum/species/android)) //ignore plasmamen/robotic species - return - var/list/plasma_parts = list()//a list of the organic parts to be turned into plasma limbs - var/list/robo_parts = list()//keep a reference of robotic parts so we know if we can turn them into a plasmaman + var/list/immune_parts = list() // Parts we can't transform because they're not organic or can't be dismembered + var/list/transform_parts = list() // Parts we want to transform + for(var/obj/item/bodypart/burn_limb as anything in burn_human.bodyparts) - if(IS_ORGANIC_LIMB(burn_limb) && burn_limb.limb_id != SPECIES_PLASMAMAN) //getting every organic, non-plasmaman limb (augments/androids are immune to this) - plasma_parts += burn_limb - if(IS_ROBOTIC_LIMB(burn_limb)) - robo_parts += burn_limb + if(!IS_ORGANIC_LIMB(burn_limb) || !burn_limb.can_dismember()) + immune_parts += burn_limb + continue + if(burn_limb.limb_id == SPECIES_PLASMAMAN) + continue + transform_parts += burn_limb - var/need_mob_update - need_mob_update += burn_human.adjustToxLoss(15, updating_health = FALSE, required_biotype = MOB_ORGANIC) // This is from plasma, so it should obey plasma biotype requirements - need_mob_update += burn_human.adjustFireLoss(25, updating_health = FALSE) - if(need_mob_update) - burn_human.updatehealth() - if(plasma_parts.len) - var/obj/item/bodypart/burn_limb = pick(plasma_parts) //using the above-mentioned list to get a choice of limbs + if(length(transform_parts)) + var/obj/item/bodypart/burn_limb = pick_n_take(transform_parts) burn_human.emote("scream") var/obj/item/bodypart/plasmalimb switch(burn_limb.body_zone) //get plasmaman limb to swap in @@ -414,16 +417,20 @@ plasmalimb = new /obj/item/bodypart/chest/plasmaman if(BODY_ZONE_HEAD) plasmalimb = new /obj/item/bodypart/head/plasmaman + burn_human.del_and_replace_bodypart(plasmalimb) burn_human.update_body_parts() burn_human.emote("scream") burn_human.visible_message(span_warning("[burn_human]'s [burn_limb.plaintext_zone] melts down to the bone!"), \ - span_userdanger("You scream out in pain as your [burn_limb.plaintext_zone] melts down to the bone, leaving an eerie plasma-like glow where flesh used to be!")) - if(!plasma_parts.len && !robo_parts.len) //a person with no potential organic limbs left AND no robotic limbs, time to turn them into a plasmaman - burn_human.ignite_mob() - burn_human.set_species(/datum/species/plasmaman) - burn_human.visible_message(span_warning("[burn_human] bursts into a brilliant purple flame as [burn_human.p_their()] entire body is that of a skeleton!"), \ - span_userdanger("Your senses numb as all of your remaining flesh is turned into a purple slurry, sloshing off your body and leaving only your bones to show in a vibrant purple!")) + span_userdanger("You scream out in pain as your [burn_limb.plaintext_zone] melts down to the bone, held together only by strands of purple fungus!")) + + // If all of your limbs are plasma then congrats: you are plasma man + if(length(immune_parts) || length(transform_parts)) + return + burn_human.ignite_mob() + burn_human.set_species(/datum/species/plasmaman) + burn_human.visible_message(span_warning("[burn_human] bursts into flame as the last of [burn_human.p_their()] body is coated in fungus!"), \ + span_userdanger("Your senses numb as what remains of your flesh sloughs off, revealing the plasma-encrusted bone beneath!")) //mafia specific tame happy plasma (normal atmos, no slowdown) /turf/open/lava/plasma/mafia diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index 060f7bfdd8f..d86531b5429 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -325,11 +325,9 @@ if(gas_visuals[icon_file]) return gas_visuals[icon_file] - var/obj/effect/abstract/new_overlay = new + var/obj/effect/abstract/gas_visual/new_overlay = new new_overlay.icon = icon_file - new_overlay.appearance_flags = RESET_COLOR | KEEP_APART - new_overlay.vis_flags = VIS_INHERIT_ICON_STATE | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID - new_overlay.color = gasmix_color + new_overlay.ChangeColor(gasmix_color) gas_visuals[icon_file] = new_overlay return new_overlay @@ -337,8 +335,8 @@ /// Called when the gasmix color has changed and the gas visuals need to be updated. /datum/pipeline/proc/UpdateGasVisuals() for(var/icon/source as anything in gas_visuals) - var/obj/effect/abstract/overlay = gas_visuals[source] - animate(overlay, time=5, color=gasmix_color) + var/obj/effect/abstract/gas_visual/overlay = gas_visuals[source] + overlay.ChangeColor(gasmix_color) /// After updating, this proc handles looking at the new gas mixture and blends the colors together according to percentage of the gas mix. /datum/pipeline/proc/CalculateGasmixColor(datum/gas_mixture/source) @@ -370,3 +368,24 @@ if(gasmix_color != current_color) gasmix_color = current_color UpdateGasVisuals() + +/obj/effect/abstract/gas_visual + appearance_flags = RESET_COLOR | KEEP_APART + vis_flags = VIS_INHERIT_ICON_STATE | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + var/current_color + var/color_filter + +/obj/effect/abstract/gas_visual/Initialize(mapload) + . = ..() + color_filter = filter(type="color", color=matrix()) + filters += color_filter + color_filter = filters[filters.len] + if(current_color) + animate(color_filter, color=current_color, time=5) + +/obj/effect/abstract/gas_visual/proc/ChangeColor(new_color) + current_color = new_color + if(isnull(color_filter)) + // Called before init + return + animate(color_filter, time=5, color=new_color) diff --git a/code/modules/client/preferences/pixel_size.dm b/code/modules/client/preferences/pixel_size.dm index cb166e0139a..ea375d91e43 100644 --- a/code/modules/client/preferences/pixel_size.dm +++ b/code/modules/client/preferences/pixel_size.dm @@ -4,7 +4,7 @@ savefile_identifier = PREFERENCE_PLAYER minimum = 0 - maximum = 3 + maximum = 5 step = 0.5 diff --git a/code/modules/library/skill_learning/skill_station.dm b/code/modules/library/skill_learning/skill_station.dm index d7fb5b7ff8e..697b34d742e 100644 --- a/code/modules/library/skill_learning/skill_station.dm +++ b/code/modules/library/skill_learning/skill_station.dm @@ -9,7 +9,8 @@ icon_state = "implantchair" occupant_typecache = list(/mob/living/carbon) //todo make occupant_typecache per type state_open = TRUE - interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND //Don't call ui_interac by default - we only want that when inside + // Only opens UI when inside; also, you can use the machine while lying down (for paraplegics and the like) + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_IGNORE_MOBILITY circuit = /obj/item/circuitboard/machine/skill_station /// Currently implanting/removing var/working = FALSE diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm index 797426058a1..91edf40615c 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm @@ -95,5 +95,9 @@ icon_living = "snowlegion_head" icon_dead = "snowlegion_head" +/mob/living/basic/legion_brood/snow/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT) + /mob/living/basic/legion_brood/snow/get_legion_type(mob/living/target) return /mob/living/basic/mining/legion/snow diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index ef6d846970d..64facb5cfa3 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -33,7 +33,6 @@ /mob/living/basic/mining/lobstrosity/Initialize(mapload) . = ..() - ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT) AddElement(/datum/element/mob_grabber) AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/basic_eating, food_types = target_foods) diff --git a/code/modules/mob/living/basic/lavaland/mining.dm b/code/modules/mob/living/basic/lavaland/mining.dm index 0b6c4f321b6..3bcdd1ceaa6 100644 --- a/code/modules/mob/living/basic/lavaland/mining.dm +++ b/code/modules/mob/living/basic/lavaland/mining.dm @@ -22,7 +22,7 @@ /mob/living/basic/mining/Initialize(mapload) . = ..() - add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE), INNATE_TRAIT) + add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE), INNATE_TRAIT) AddElement(/datum/element/mob_killed_tally, "mobs_killed_mining") var/static/list/vulnerable_projectiles if(!vulnerable_projectiles) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6a34c7fd005..5d8d6dd425c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1063,7 +1063,6 @@ /mob/living/carbon/vv_get_dropdown() . = ..() VV_DROPDOWN_OPTION("", "---------") - VV_DROPDOWN_OPTION(VV_HK_MAKE_AI, "Make AI") VV_DROPDOWN_OPTION(VV_HK_MODIFY_BODYPART, "Modify bodypart") VV_DROPDOWN_OPTION(VV_HK_MODIFY_ORGANS, "Modify organs") VV_DROPDOWN_OPTION(VV_HK_MARTIAL_ART, "Give Martial Arts") @@ -1121,12 +1120,6 @@ to_chat(usr, "Failed to replace bodypart! They might be incompatible.") admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") - if(href_list[VV_HK_MAKE_AI]) - if(!check_rights(R_SPAWN)) - return - if(tgui_alert(usr,"Confirm mob type change?",,list("Transform","Cancel")) != "Transform") - return - usr.client.holder.Topic("vv_override", list("makeai"=href_list[VV_HK_TARGET])) if(href_list[VV_HK_MODIFY_ORGANS]) if(!check_rights(NONE)) return diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index dcd29b32b6d..9183b2e4ac5 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1232,10 +1232,10 @@ GLOBAL_LIST_EMPTY(features_by_species) target.force_say() log_combat(user, target, grappled ? "grapple punched" : "kicked") target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction) - target.apply_damage(damage * PUNCH_STAMINA_MULTIPLIER, STAMINA, affecting, armor_block - limb_accuracy) // SKYRAT EDIT CHANGE - ORIGINAL : target.apply_damage(damage * 1.5, STAMINA, affecting, armor_block - limb_accuracy) + target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy) else // Normal attacks do not gain the benefit of armor penetration. target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction, sharpness = unarmed_sharpness) //SKYRAT EDIT - Applies sharpness if it does - ORIGINAL: target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction) - target.apply_damage(damage * PUNCH_STAMINA_MULTIPLIER, STAMINA, affecting, armor_block) //SKYRAT EDIT CHANGE: target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) + target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) if(damage >= 9) target.force_say() log_combat(user, target, "punched") diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 75c936fbadb..5988ad3b890 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -9,6 +9,7 @@ TRAIT_NOBLOOD, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, + TRAIT_NOCRITDAMAGE, TRAIT_NOFIRE, TRAIT_NOHUNGER, TRAIT_NO_DNA_COPY, @@ -22,7 +23,6 @@ TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, - TRAIT_NOCRITDAMAGE, ) inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index c86b8c9a276..01451a8db36 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -12,9 +12,12 @@ TRAIT_NOFIRE, TRAIT_NO_AUGMENTS, TRAIT_NO_DNA_COPY, + TRAIT_NO_PLASMA_TRANSFORM, TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, + TRAIT_SNOWSTORM_IMMUNE, // Shared with plasma river... but I guess if you can survive a plasma river a blizzard isn't a big deal + TRAIT_UNHUSKABLE, ) mutantheart = null mutantlungs = null diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 9facc517c1c..eaabee63485 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -10,10 +10,13 @@ TRAIT_HARDLY_WOUNDED, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, + TRAIT_NO_PLASMA_TRANSFORM, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, + TRAIT_UNHUSKABLE, ) + inherent_biotypes = MOB_HUMANOID|MOB_MINERAL inherent_respiration_type = RESPIRATION_PLASMA mutantlungs = /obj/item/organ/internal/lungs/plasmaman diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index f2682da2eba..4120f939d51 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -22,6 +22,7 @@ TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, + TRAIT_UNHUSKABLE, TRAIT_XENO_IMMUNE, ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 8f6dc8efeb9..6f4e8570099 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -30,11 +30,3 @@ . = ..() if(.) update_body_parts() - -/mob/living/carbon/human/become_husk(source) - if(istype(dna.species, /datum/species/skeleton)) //skeletons shouldn't be husks. - cure_husk() - return - . = ..() - if(.) - update_body_parts() diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index bbc37911bb1..96beb024fe9 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -497,18 +497,28 @@ /mob/living/proc/cure_husk(source) REMOVE_TRAIT(src, TRAIT_HUSK, source) - if(!HAS_TRAIT(src, TRAIT_HUSK)) - REMOVE_TRAIT(src, TRAIT_DISFIGURED, "husk") - update_body() - return TRUE + if(HAS_TRAIT(src, TRAIT_HUSK)) + return FALSE + REMOVE_TRAIT(src, TRAIT_DISFIGURED, "husk") + update_body() + UnregisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_UNHUSKABLE)) + return TRUE /mob/living/proc/become_husk(source) - if(!HAS_TRAIT(src, TRAIT_HUSK)) - ADD_TRAIT(src, TRAIT_HUSK, source) - ADD_TRAIT(src, TRAIT_DISFIGURED, "husk") - update_body() - else - ADD_TRAIT(src, TRAIT_HUSK, source) + if(HAS_TRAIT(src, TRAIT_UNHUSKABLE)) + return + var/was_husk = HAS_TRAIT(src, TRAIT_HUSK) + ADD_TRAIT(src, TRAIT_HUSK, source) + if (was_husk) + return + ADD_TRAIT(src, TRAIT_DISFIGURED, "husk") + update_body() + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_UNHUSKABLE), PROC_REF(became_unhuskable)) + +/// Called when we become unhuskable while already husked +/mob/living/proc/became_unhuskable() + SIGNAL_HANDLER + cure_husk() /mob/living/proc/cure_fakedeath(source) remove_traits(list(TRAIT_FAKEDEATH, TRAIT_DEATHCOMA), source) diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 69af56d3419..3750acddc42 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -31,6 +31,32 @@ var/requires_gravity = TRUE // can you use this to write in zero-g embedding = list(embed_chance = 50) sharpness = SHARP_POINTY + var/dart_insert_icon = 'icons/obj/weapons/guns/toy.dmi' + var/dart_insert_casing_icon_state = "overlay_pen" + var/dart_insert_projectile_icon_state = "overlay_pen_proj" + +/obj/item/pen/Initialize(mapload) + . = ..() + AddComponent(/datum/component/dart_insert, dart_insert_icon, dart_insert_casing_icon_state, dart_insert_icon, dart_insert_projectile_icon_state) + RegisterSignal(src, COMSIG_DART_INSERT_ADDED, PROC_REF(on_inserted_into_dart)) + RegisterSignal(src, COMSIG_DART_INSERT_REMOVED, PROC_REF(on_removed_from_dart)) + RegisterSignal(src, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, PROC_REF(get_dart_var_modifiers)) + +/obj/item/pen/proc/on_inserted_into_dart(datum/source, obj/projectile/dart, mob/user, embedded = FALSE) + SIGNAL_HANDLER + +/obj/item/pen/proc/get_dart_var_modifiers(datum/source, list/modifiers) + SIGNAL_HANDLER + modifiers["damage"] = max(5, throwforce) + modifiers["speed"] = max(0, throw_speed - 3) + modifiers["embedding"] = embedding + modifiers["armour_penetration"] = armour_penetration + modifiers["wound_bonus"] = wound_bonus + modifiers["bare_wound_bonus"] = bare_wound_bonus + modifiers["demolition_mod"] = demolition_mod + +/obj/item/pen/proc/on_removed_from_dart(datum/source, obj/projectile/dart, mob/user) + SIGNAL_HANDLER /obj/item/pen/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...")) @@ -69,7 +95,7 @@ if("#FF0000") colour = "#00FF00" chosen_color = "green" - throw_speed = initial(throw_speed) + throw_speed-- if("#00FF00") colour = "#0000FF" chosen_color = "blue" @@ -84,6 +110,8 @@ icon_state = "pen-fountain" font = FOUNTAIN_PEN_FONT requires_gravity = FALSE // fancy spess pens + dart_insert_casing_icon_state = "overlay_fountainpen" + dart_insert_projectile_icon_state = "overlay_fountainpen_proj" /obj/item/pen/charcoal name = "charcoal stylus" @@ -113,13 +141,23 @@ custom_materials = list(/datum/material/gold = SMALL_MATERIAL_AMOUNT*7.5) sharpness = SHARP_EDGED resistance_flags = FIRE_PROOF - unique_reskin = list("Oak" = "pen-fountain-o", - "Gold" = "pen-fountain-g", - "Rosewood" = "pen-fountain-r", - "Black and Silver" = "pen-fountain-b", - "Command Blue" = "pen-fountain-cb" - ) + unique_reskin = list( + "Oak" = "pen-fountain-o", + "Gold" = "pen-fountain-g", + "Rosewood" = "pen-fountain-r", + "Black and Silver" = "pen-fountain-b", + "Command Blue" = "pen-fountain-cb" + ) embedding = list("embed_chance" = 75) + dart_insert_casing_icon_state = "overlay_fountainpen_gold" + dart_insert_projectile_icon_state = "overlay_fountainpen_gold_proj" + var/list/overlay_reskin = list( + "Oak" = "overlay_fountainpen_gold", + "Gold" = "overlay_fountainpen_gold", + "Rosewood" = "overlay_fountainpen_gold", + "Black and Silver" = "overlay_fountainpen", + "Command Blue" = "overlay_fountainpen_gold" + ) /obj/item/pen/fountain/captain/Initialize(mapload) . = ..() @@ -128,12 +166,19 @@ effectiveness = 115, \ ) //the pen is mightier than the sword + RegisterSignal(src, COMSIG_DART_INSERT_PARENT_RESKINNED, PROC_REF(reskin_dart_insert)) /obj/item/pen/fountain/captain/reskin_obj(mob/M) ..() if(current_skin) desc = "It's an expensive [current_skin] fountain pen. The nib is quite sharp." +/obj/item/pen/fountain/captain/proc/reskin_dart_insert(datum/component/dart_insert/insert_comp) + if(!istype(insert_comp)) //You really shouldn't be sending this signal from anything other than a dart_insert component + return + insert_comp.casing_overlay_icon_state = overlay_reskin[current_skin] + insert_comp.projectile_overlay_icon_state = "[overlay_reskin[current_skin]]_proj" + /obj/item/pen/attack_self(mob/living/carbon/user) . = ..() if(.) @@ -247,6 +292,23 @@ reagents.add_reagent(/datum/reagent/toxin/mutetoxin, 15) reagents.add_reagent(/datum/reagent/toxin/staminatoxin, 10) +/obj/item/pen/sleepy/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user) + . = ..() + var/obj/projectile/proj = dart.loaded_projectile + RegisterSignal(proj, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_dart_hit)) + +/obj/item/pen/sleepy/on_removed_from_dart(datum/source, obj/item/ammo_casing/dart, obj/projectile/proj, mob/user) + . = ..() + if(istype(proj)) + UnregisterSignal(proj, COMSIG_PROJECTILE_SELF_ON_HIT) + +/obj/item/pen/sleepy/proc/on_dart_hit(datum/source, atom/movable/firer, atom/target, angle, hit_limb, blocked) + SIGNAL_HANDLER + var/mob/living/carbon/carbon_target = target + if(!istype(carbon_target) || blocked == 100) + return + if(carbon_target.can_inject(target_zone = hit_limb)) + reagents.trans_to(carbon_target, reagents.total_volume, transferred_by = firer, methods = INJECT) /* * (Alan) Edaggers */ @@ -262,6 +324,7 @@ light_power = 0.75 light_color = COLOR_SOFT_RED light_on = FALSE + dart_insert_projectile_icon_state = "overlay_edagger" /// The real name of our item when extended. var/hidden_name = "energy dagger" /// The real desc of our item when extended. @@ -287,6 +350,62 @@ RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) RegisterSignal(src, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan)) +/obj/item/pen/edagger/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user) + . = ..() + var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) + if(HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) + transform_comp.do_transform(src, user) + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_FIRE, PROC_REF(on_containing_dart_fired)) + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_ON_SPAWN_DROP, PROC_REF(on_containing_dart_drop)) + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, PROC_REF(on_containing_dart_embedded)) + +/obj/item/pen/edagger/on_removed_from_dart(datum/source, obj/item/ammo_casing/dart, obj/projectile/projectile, mob/user) + . = ..() + if(istype(dart)) + UnregisterSignal(dart, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_ITEM_FAILED_EMBED)) + if(istype(projectile)) + UnregisterSignal(projectile, list(COMSIG_PROJECTILE_FIRE, COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED)) + +/obj/item/pen/edagger/get_dart_var_modifiers(datum/source, list/modifiers) + . = ..() + var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) + modifiers["damage"] = max(5, transform_comp.throwforce_on) + modifiers["speed"] = max(0, transform_comp.throw_speed_on - 3) + var/list/embed_params = modifiers["embedding"] + embed_params["embed_chance"] = 100 + +/obj/item/pen/edagger/proc/on_containing_dart_fired(obj/projectile/source) + SIGNAL_HANDLER + playsound(source, 'sound/weapons/saberon.ogg', 5, TRUE) + var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) + source.hitsound = transform_comp.hitsound_on + source.set_light(light_range, light_power, light_color, l_on = TRUE) + +/obj/item/pen/edagger/proc/on_containing_dart_drop(datum/source, obj/item/ammo_casing/new_casing) + SIGNAL_HANDLER + playsound(new_casing, 'sound/weapons/saberoff.ogg', 5, TRUE) + +/obj/item/pen/edagger/proc/on_containing_dart_embedded(datum/source, obj/item/ammo_casing/new_casing) + SIGNAL_HANDLER + RegisterSignal(new_casing, COMSIG_ITEM_UNEMBEDDED, PROC_REF(on_embedded_removed)) + RegisterSignal(new_casing, COMSIG_ITEM_FAILED_EMBED, PROC_REF(on_containing_dart_failed_embed)) + +/obj/item/pen/edagger/proc/on_containing_dart_failed_embed(obj/item/ammo_casing/source) + SIGNAL_HANDLER + playsound(source, 'sound/weapons/saberoff.ogg', 5, TRUE) + UnregisterSignal(source, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_ITEM_FAILED_EMBED)) + +/obj/item/pen/edagger/proc/on_embedded_removed(obj/item/ammo_casing/source, mob/living/carbon/victim) + SIGNAL_HANDLER + playsound(source, 'sound/weapons/saberoff.ogg', 5, TRUE) + UnregisterSignal(source, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_ITEM_FAILED_EMBED)) + victim.visible_message( + message = span_warning("The blade of the [hidden_name] retracts as the [source.name] is removed from [victim]!"), + self_message = span_warning("The blade of the [hidden_name] retracts as the [source.name] is removed from you!"), + blind_message = span_warning("You hear an energy blade retract!"), + vision_distance = 1 + ) + /obj/item/pen/edagger/suicide_act(mob/living/user) if(HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) user.visible_message(span_suicide("[user] forcefully rams the pen into their mouth!")) @@ -348,6 +467,25 @@ toolspeed = 10 //You will never willingly choose to use one of these over a shovel. font = FOUNTAIN_PEN_FONT colour = "#0000FF" + dart_insert_casing_icon_state = "overlay_survivalpen" + dart_insert_projectile_icon_state = "overlay_survivalpen_proj" + +/obj/item/pen/survival/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user) + . = ..() + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_dart_hit)) + +/obj/item/pen/survival/on_removed_from_dart(datum/source, obj/item/ammo_casing/dart, obj/projectile/proj, mob/user) + . = ..() + if(istype(proj)) + UnregisterSignal(proj, COMSIG_PROJECTILE_SELF_ON_HIT) + +/obj/item/pen/survival/proc/on_dart_hit(obj/projectile/source, atom/movable/firer, atom/target) + var/turf/target_turf = get_turf(target) + if(!target_turf) + target_turf = get_turf(src) + if(ismineralturf(target_turf)) + var/turf/closed/mineral/mineral_turf = target_turf + mineral_turf.gets_drilled(firer, TRUE) /obj/item/pen/destroyer name = "Fine Tipped Pen" @@ -362,6 +500,7 @@ desc = "A pen with an extendable screwdriver tip. This one has a yellow cap." icon_state = "pendriver" toolspeed = 1.2 // gotta have some downside + dart_insert_projectile_icon_state = "overlay_pendriver" /obj/item/pen/screwdriver/get_all_tool_behaviours() return list(TOOL_SCREWDRIVER) diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index dee2c087c68..009c52b227e 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -66,6 +66,7 @@ if(reagents && loaded_projectile.reagents) reagents.trans_to(loaded_projectile, reagents.total_volume, transferred_by = user) //For chemical darts/bullets qdel(reagents) + SEND_SIGNAL(src, COMSIG_CASING_READY_PROJECTILE, target, user, quiet, zone_override, fired_from) /obj/item/ammo_casing/proc/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread, atom/fired_from) var/turf/curloc = get_turf(fired_from) diff --git a/code/modules/projectiles/ammunition/ballistic/foam.dm b/code/modules/projectiles/ammunition/ballistic/foam.dm index 21ceeb6918b..2895d74555b 100644 --- a/code/modules/projectiles/ammunition/ballistic/foam.dm +++ b/code/modules/projectiles/ammunition/ballistic/foam.dm @@ -9,6 +9,7 @@ custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.1125) harmful = FALSE var/modified = FALSE + var/static/list/insertable_items_hint = list(/obj/item/pen) /obj/item/ammo_casing/foam_dart/Initialize(mapload) . = ..() @@ -18,47 +19,37 @@ . = ..() if(modified) icon_state = "[base_icon_state]_empty" - loaded_projectile?.icon_state = "[base_icon_state]_empty" + loaded_projectile?.icon_state = "[loaded_projectile.base_icon_state]_empty_proj" return icon_state = "[base_icon_state]" - loaded_projectile?.icon_state = "[loaded_projectile.base_icon_state]" + loaded_projectile?.icon_state = "[loaded_projectile.base_icon_state]_proj" /obj/item/ammo_casing/foam_dart/update_desc() . = ..() desc = "It's Donk or Don't! [modified ? "... Although, this one doesn't look too safe." : "Ages 8 and up."]" -/obj/item/ammo_casing/foam_dart/attackby(obj/item/A, mob/user, params) - var/obj/projectile/bullet/foam_dart/FD = loaded_projectile - if (A.tool_behaviour == TOOL_SCREWDRIVER && !modified) +/obj/item/ammo_casing/foam_dart/examine_more(mob/user) + . = ..() + if(!HAS_TRAIT(src, TRAIT_DART_HAS_INSERT)) + var/list/type_initial_names = list() + for(var/type in insertable_items_hint) + var/obj/item/type_item = type + type_initial_names += "\a [initial(type_item.name)]" + . += span_notice("[modified ? "You can" : "If you removed the safety cap with a screwdriver, you could"] insert a small item\ + [length(type_initial_names) ? ", such as [english_list(type_initial_names, and_text = "or ", final_comma_text = ", ")]" : ""].") + + +/obj/item/ammo_casing/foam_dart/attackby(obj/item/attacking_item, mob/user, params) + var/obj/projectile/bullet/foam_dart/dart = loaded_projectile + if (attacking_item.tool_behaviour == TOOL_SCREWDRIVER && !modified) modified = TRUE - FD.modified = TRUE - FD.damage_type = BRUTE + dart.modified = TRUE + dart.damage_type = BRUTE to_chat(user, span_notice("You pop the safety cap off [src].")) update_appearance() - else if (istype(A, /obj/item/pen)) - if(modified) - if(!FD.pen) - harmful = TRUE - if(!user.transferItemToLoc(A, FD)) - return - FD.pen = A - FD.damage = 5 - to_chat(user, span_notice("You insert [A] into [src].")) - else - to_chat(user, span_warning("There's already something in [src].")) - else - to_chat(user, span_warning("The safety cap prevents you from inserting [A] into [src].")) else return ..() -/obj/item/ammo_casing/foam_dart/attack_self(mob/living/user) - var/obj/projectile/bullet/foam_dart/FD = loaded_projectile - if(FD.pen) - FD.damage = initial(FD.damage) - user.put_in_hands(FD.pen) - to_chat(user, span_notice("You remove [FD.pen] from [src].")) - FD.pen = null - /obj/item/ammo_casing/foam_dart/riot name = "riot foam dart" desc = "Whose smart idea was it to use toys as crowd control? Ages 18 and up." diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm index a3bb54a07e0..713790049b5 100644 --- a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm +++ b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm @@ -32,6 +32,7 @@ damage = 50 speed = 1 range = 25 + shrapnel_type = null embedding = list( embed_chance = 90, fall_chance = 2, @@ -42,7 +43,6 @@ jostle_pain_mult = 3, rip_time = 1 SECONDS ) - shrapnel_type = /obj/item/ammo_casing/arrow /// holy arrows /obj/item/ammo_casing/arrow/holy @@ -59,7 +59,6 @@ desc = "Here it comes, cultist scum!" icon_state = "holy_arrow_projectile" damage = 20 //still a lot but this is roundstart gear so far less - shrapnel_type =/obj/item/ammo_casing/arrow/holy embedding = list( embed_chance = 50, fall_chance = 2, diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 18c0b557f88..a7beb1a7102 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -282,8 +282,8 @@ var/mob/living/L = target hit_limb_zone = L.check_hit_limb_zone_name(def_zone) if(fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone) - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone) + SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone, blocked) + SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone, blocked) if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason return BULLET_ACT_BLOCK diff --git a/code/modules/projectiles/projectile/bullets/foam_dart.dm b/code/modules/projectiles/projectile/bullets/foam_dart.dm index 6d4cffd4524..3f086166e6a 100644 --- a/code/modules/projectiles/projectile/bullets/foam_dart.dm +++ b/code/modules/projectiles/projectile/bullets/foam_dart.dm @@ -5,27 +5,24 @@ damage_type = OXY icon = 'icons/obj/weapons/guns/toy.dmi' icon_state = "foamdart_proj" - base_icon_state = "foamdart_proj" + base_icon_state = "foamdart" range = 10 + shrapnel_type = null embedding = null var/modified = FALSE var/obj/item/pen/pen = null /obj/projectile/bullet/foam_dart/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_PROJECTILE_ON_SPAWN_DROP, PROC_REF(handle_drop)) + RegisterSignals(src, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(handle_drop)) /obj/projectile/bullet/foam_dart/proc/handle_drop(datum/source, obj/item/ammo_casing/foam_dart/newcasing) SIGNAL_HANDLER newcasing.modified = modified + newcasing.update_appearance() var/obj/projectile/bullet/foam_dart/newdart = newcasing.loaded_projectile newdart.modified = modified newdart.damage_type = damage_type - if(pen) - newdart.pen = pen - pen.forceMove(newdart) - pen = null - newdart.damage = 5 newdart.update_appearance() /obj/projectile/bullet/foam_dart/Destroy() @@ -35,5 +32,5 @@ /obj/projectile/bullet/foam_dart/riot name = "riot foam dart" icon_state = "foamdart_riot_proj" - base_icon_state = "foamdart_riot_proj" + base_icon_state = "foamdart_riot" stamina = 25 diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm index de7e59facc3..d76b2de9d6a 100644 --- a/code/modules/projectiles/projectile/bullets/rifle.dm +++ b/code/modules/projectiles/projectile/bullets/rifle.dm @@ -46,7 +46,7 @@ bare_wound_bonus = 80 embedding = list(embed_chance=100, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) wound_falloff_tile = -5 - shrapnel_type = /obj/item/ammo_casing/harpoon + shrapnel_type = null // Rebar (Rebar Crossbow) /obj/projectile/bullet/rebar @@ -75,4 +75,3 @@ embedding = list(embed_chance=80, fall_chance=1, jostle_chance=3, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=2, rip_time=14) embed_falloff_tile = -3 shrapnel_type = /obj/item/stack/rods - diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index a4d31849cda..bc5b14614c6 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -136,7 +136,6 @@ //SKYRAT EDIT CHANGE END /obj/machinery/chem_dispenser/Initialize(mapload) - . = ..() if(dispensable_reagents != null && !dispensable_reagents.len) dispensable_reagents = default_dispensable_reagents if(dispensable_reagents) @@ -162,6 +161,8 @@ if(emagged_reagents) emagged_reagents = sort_list(emagged_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + . = ..() // So that we call RefreshParts() after adjusting the lists + if(is_operational) begin_processing() update_appearance() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index c24e9f8ceca..a9dab01c918 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -901,7 +901,7 @@ SHOULD_CALL_PARENT(TRUE) if(IS_ORGANIC_LIMB(src)) - if(owner && HAS_TRAIT(owner, TRAIT_HUSK)) + if(!(bodypart_flags & BODYPART_UNHUSKABLE) && owner && HAS_TRAIT(owner, TRAIT_HUSK)) dmg_overlay_type = "" //no damage overlay shown when husked is_husked = TRUE else if(owner && HAS_TRAIT(owner, TRAIT_INVISIBLE_MAN)) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index f10393dd653..10195c6d98e 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -42,6 +42,7 @@ damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) disabling_threshold_percentage = 1 + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/arm/right/robot name = "cyborg right arm" @@ -75,6 +76,7 @@ biological_state = (BIO_ROBOTIC|BIO_JOINTED) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/robot name = "cyborg left leg" @@ -108,6 +110,7 @@ biological_state = (BIO_ROBOTIC|BIO_JOINTED) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/robot/emp_act(severity) . = ..() @@ -154,6 +157,7 @@ biological_state = (BIO_ROBOTIC|BIO_JOINTED) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/right/robot/emp_act(severity) . = ..() @@ -197,14 +201,15 @@ biological_state = (BIO_ROBOTIC) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) - - var/wired = FALSE - var/obj/item/stock_parts/cell/cell = null + bodypart_flags = BODYPART_UNHUSKABLE robotic_emp_paralyze_damage_percent_threshold = 0.6 wing_types = list(/obj/item/organ/external/wings/functional/robotic) + var/wired = FALSE + var/obj/item/stock_parts/cell/cell = null + /obj/item/bodypart/chest/robot/emp_act(severity) . = ..() if(!. || isnull(owner)) @@ -376,6 +381,7 @@ damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) head_flags = HEAD_EYESPRITES + bodypart_flags = BODYPART_UNHUSKABLE var/obj/item/assembly/flash/handheld/flash1 = null var/obj/item/assembly/flash/handheld/flash2 = null diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index ad3c9ce213c..f4be2fd340f 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -331,6 +331,7 @@ should_draw_greyscale = FALSE dmg_overlay_type = null head_flags = NONE + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/chest/skeleton biological_state = BIO_BONE @@ -338,6 +339,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE wing_types = list(/obj/item/organ/external/wings/functional/skeleton) /obj/item/bodypart/arm/left/skeleton @@ -345,24 +347,28 @@ limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/arm/right/skeleton biological_state = (BIO_BONE|BIO_JOINTED) limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/skeleton biological_state = (BIO_BONE|BIO_JOINTED) limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/right/skeleton biological_state = (BIO_BONE|BIO_JOINTED) limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE ///MUSHROOM /obj/item/bodypart/head/mushroom diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm index 8070072521f..8ba27c2cdf9 100644 --- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -10,6 +10,7 @@ brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak head_flags = HEAD_EYESPRITES + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/chest/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -22,6 +23,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE wing_types = NONE /obj/item/bodypart/arm/left/plasmaman @@ -34,6 +36,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/arm/right/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -45,6 +48,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -56,6 +60,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/right/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -67,3 +72,4 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE diff --git a/code/modules/unit_tests/monkey_business.dm b/code/modules/unit_tests/monkey_business.dm index 20bfffe6a48..80044a0486d 100644 --- a/code/modules/unit_tests/monkey_business.dm +++ b/code/modules/unit_tests/monkey_business.dm @@ -14,7 +14,8 @@ /datum/unit_test/monkey_business/Run() for(var/monkey_id in 1 to length(GLOB.the_station_areas)) - var/mob/living/carbon/human/monkey = allocate(/mob/living/carbon/human/consistent, get_first_open_turf_in_area(GLOB.the_station_areas[monkey_id])) + var/area/monkey_zone = GLOB.areas_by_type[GLOB.the_station_areas[monkey_id]] + var/mob/living/carbon/human/monkey = allocate(/mob/living/carbon/human/consistent, get_first_open_turf_in_area(monkey_zone)) monkey.set_species(/datum/species/monkey) monkey.set_name("Monkey [monkey_id]") if(monkey_id % monkey_angry_nth == 0) // BLOOD FOR THE BLOOD GODS diff --git a/html/changelogs/AutoChangeLog-pr-784.yml b/html/changelogs/AutoChangeLog-pr-784.yml new file mode 100644 index 00000000000..2d911e132c8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-784.yml @@ -0,0 +1,4 @@ +author: "RatFromTheJungle" +delete-after: True +changes: + - bugfix: "fixes punches doing like triple stamina damage, by removing a 2.6x multiplier." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-786.yml b/html/changelogs/AutoChangeLog-pr-786.yml new file mode 100644 index 00000000000..9cb91ae6647 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-786.yml @@ -0,0 +1,4 @@ +author: "Nerev4r" +delete-after: True +changes: + - bugfix: "Chameleon mutation is toggleable again." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-787.yml b/html/changelogs/AutoChangeLog-pr-787.yml new file mode 100644 index 00000000000..da74cef81fe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-787.yml @@ -0,0 +1,4 @@ +author: "TwistedSilicon" +delete-after: True +changes: + - bugfix: "Window damage overlays have been fixed." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-788.yml b/html/changelogs/AutoChangeLog-pr-788.yml new file mode 100644 index 00000000000..e9429200cfc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-788.yml @@ -0,0 +1,5 @@ +author: "jjpark-kb" +delete-after: True +changes: + - rscadd: "you can craft the gutlunch trough" + - qol: "you can fill the gutlunch trough with a mining bag" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-790.yml b/html/changelogs/AutoChangeLog-pr-790.yml new file mode 100644 index 00000000000..db441e24d90 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-790.yml @@ -0,0 +1,4 @@ +author: "Smol42" +delete-after: True +changes: + - rscadd: "Added four acrador snouts." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-793.yml b/html/changelogs/AutoChangeLog-pr-793.yml new file mode 100644 index 00000000000..f375987f1c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-793.yml @@ -0,0 +1,4 @@ +author: "Xander3359" +delete-after: True +changes: + - admin: "Remove \"Make AI\" from VV dropdown" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-794.yml b/html/changelogs/AutoChangeLog-pr-794.yml new file mode 100644 index 00000000000..5575fc89378 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-794.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "RCD can build directional windows on top of existing grills & without them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-795.yml b/html/changelogs/AutoChangeLog-pr-795.yml new file mode 100644 index 00000000000..01610a2bd18 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-795.yml @@ -0,0 +1,4 @@ +author: "jjpark-kb" +delete-after: True +changes: + - bugfix: "gutlunches now produce miner salve instead of milk, as well as the other reagents if fed the correct ore" \ No newline at end of file diff --git a/icons/obj/weapons/guns/toy.dmi b/icons/obj/weapons/guns/toy.dmi index 83a85e7e447..3f7e509b699 100644 Binary files a/icons/obj/weapons/guns/toy.dmi and b/icons/obj/weapons/guns/toy.dmi differ diff --git a/modular_skyrat/master_files/code/datums/mutations/chameleon.dm b/modular_skyrat/master_files/code/datums/mutations/chameleon.dm new file mode 100644 index 00000000000..7bd88ed3eb2 --- /dev/null +++ b/modular_skyrat/master_files/code/datums/mutations/chameleon.dm @@ -0,0 +1,28 @@ +// toggleable chameleon skin +/datum/mutation/human/chameleon + power_path = /datum/action/cooldown/spell/chameleon_skin_activate + +/datum/action/cooldown/spell/chameleon_skin_activate + name = "Activate Chameleon Skin" + desc = "The chromatophores in your skin adjust to your surroundings, as long as you stay still." + spell_requirements = NONE + button_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "ninja_cloak" + +/datum/action/cooldown/spell/chameleon_skin_activate/cast(list/targets, mob/user = usr) + . = ..() + + if(HAS_TRAIT(user,TRAIT_CHAMELEON_SKIN)) + chameleon_skin_deactivate(user) + return + + ADD_TRAIT(user, TRAIT_CHAMELEON_SKIN, GENETIC_MUTATION) + to_chat(user, "The pigmentation of your skin shifts and starts to take on the colors of your surroundings.") + +/datum/action/cooldown/spell/chameleon_skin_activate/proc/chameleon_skin_deactivate(mob/user = usr) + if(!HAS_TRAIT_FROM(user,TRAIT_CHAMELEON_SKIN, GENETIC_MUTATION)) + return + + REMOVE_TRAIT(user, TRAIT_CHAMELEON_SKIN, GENETIC_MUTATION) + user.alpha = 255 + to_chat(user, text("Your skin shifts as it shimmers back into its original colors.")) diff --git a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm index d68f78c5d46..3a59d18fc52 100644 --- a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -78,6 +78,7 @@ GLOBAL_LIST_INIT(skyrat_wood_recipes, list( new/datum/stack_recipe("produce bin", /obj/machinery/smartfridge/producebin, 10, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), new/datum/stack_recipe("storage barrel", /obj/structure/closet/crate/wooden/storage_barrel, 4, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, category = CAT_STRUCTURE), new/datum/stack_recipe("worm barrel", /obj/structure/wormfarm, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), + new/datum/stack_recipe("gutlunch trough", /obj/structure/ore_container/gutlunch_trough, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), new/datum/stack_recipe("sturdy wooden fence", /obj/structure/railing/wooden_fencing, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), new/datum/stack_recipe("sturdy wooden fence gate", /obj/structure/railing/wooden_fencing/gate, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), )) diff --git a/modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi b/modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi index 86f4c783e20..fa2fc8b89aa 100644 Binary files a/modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi and b/modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi differ diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm b/modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm new file mode 100644 index 00000000000..fec1b4c1715 --- /dev/null +++ b/modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm @@ -0,0 +1,6 @@ +/obj/structure/ore_container/gutlunch_trough/attackby(obj/item/attacking_item, mob/living/carbon/human/user, list/modifiers) + if(!istype(attacking_item, /obj/item/storage/bag/ore)) + return ..() + + for(var/obj/item/stack/ore/stored_ore in attacking_item.contents) + attacking_item.atom_storage?.attempt_remove(stored_ore, src) diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm index 8ab45ecf430..ce8dc17424b 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm @@ -433,3 +433,27 @@ color_src = USE_MATRIXED_COLORS name = "Acrador (Short)" icon_state = "acrador_short" + +/datum/sprite_accessory/snouts/acrador_1 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 1 (Normal)" + icon_state = "acrador_1" + +/datum/sprite_accessory/snouts/acrador_2 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 2 (Normal)" + icon_state = "acrador_2" + +/datum/sprite_accessory/snouts/acrador_3 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 3 (Normal)" + icon_state = "acrador_3" + +/datum/sprite_accessory/snouts/acrador_4 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 4 (Normal)" + icon_state = "acrador_4" diff --git a/tgstation.dme b/tgstation.dme index 4ea0689bc46..35b9780d62d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1117,6 +1117,7 @@ #include "code\datums\components\customizable_reagent_holder.dm" #include "code\datums\components\damage_aura.dm" #include "code\datums\components\damage_chain.dm" +#include "code\datums\components\dart_insert.dm" #include "code\datums\components\deadchat_control.dm" #include "code\datums\components\death_linked.dm" #include "code\datums\components\dejavu.dm" @@ -6113,6 +6114,7 @@ #include "modular_skyrat\master_files\code\datums\mood_events\generic_negative_events.dm" #include "modular_skyrat\master_files\code\datums\mood_events\needs_events.dm" #include "modular_skyrat\master_files\code\datums\mutations\_mutations.dm" +#include "modular_skyrat\master_files\code\datums\mutations\chameleon.dm" #include "modular_skyrat\master_files\code\datums\mutations\hulk.dm" #include "modular_skyrat\master_files\code\datums\quirks\_quirk.dm" #include "modular_skyrat\master_files\code\datums\quirks\negative.dm" @@ -6490,6 +6492,7 @@ #include "modular_skyrat\modules\ashwalkers\code\buildings\ash_farming.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\ash_tendril.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\fuelwell.dm" +#include "modular_skyrat\modules\ashwalkers\code\buildings\gutluncher_foodtrough.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\railroad.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\tendril_cursing.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\wormfarm.dm" diff --git a/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx b/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx index 46f5a07182f..332d11d63fb 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx @@ -2,6 +2,9 @@ import { useBackend, useLocalState } from '../backend'; import { LabeledList, Stack, Button, Section, ProgressBar, Box, Tabs, Divider } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Objectives = { count: number; @@ -117,6 +120,11 @@ export const AntagInfoAssaultops = (props, context) => { {tab === 1 && } {tab === 2 && } + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx b/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx index e8471a6a5ac..7000b324aa9 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx @@ -1,6 +1,9 @@ import { useBackend } from '../backend'; import { Box, Collapsible, Divider, LabeledList, Section, Stack } from '../components'; import { Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END import { Window } from '../layouts'; @@ -25,6 +28,7 @@ export const AntagInfoBlob = (props, context) => { + diff --git a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx index f3eda78c661..339c115e30c 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx @@ -4,6 +4,9 @@ import { useBackend, useSharedState } from '../backend'; import { Button, Dimmer, Dropdown, Section, Stack, NoticeBox } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const hivestyle = { fontWeight: 'bold', @@ -54,9 +57,10 @@ type Info = { can_change_objective: BooleanLike; }; +// SKYRAT EDIT change height from 750 to 900 export const AntagInfoChangeling = (props, context) => { return ( - + { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx index 8912a666bc5..96b94c70339 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx @@ -1,16 +1,20 @@ import { useBackend } from '../backend'; import { Icon, Section, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Info = { antag_name: string; }; +// SKYRAT EDIT change height from 250 to 350 export const AntagInfoClock = (props, context) => { const { data } = useBackend(context); const { antag_name } = data; return ( - +
@@ -19,6 +23,11 @@ export const AntagInfoClock = (props, context) => { {' You are the ' + antag_name + '! '} + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx b/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx index 33b7623c44f..7aa7b80eea0 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx @@ -2,23 +2,32 @@ import { useBackend } from '../backend'; import { Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Info = { antag_name: string; objectives: Objective[]; }; +// SKYRAT EDIT increase height from 250 to 500 export const AntagInfoGeneric = (props, context) => { const { data } = useBackend(context); const { antag_name, objectives } = data; return ( - +
You are the {antag_name}! + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx b/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx index ff14419473c..367cc311403 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx @@ -3,6 +3,9 @@ import { Section, Stack, Box, Tabs, Button, BlockQuote } from '../components'; import { Window } from '../layouts'; import { BooleanLike } from 'common/react'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const hereticRed = { color: '#e03c3c', @@ -63,6 +66,12 @@ const IntroductionSection = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} + diff --git a/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx b/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx index 0344f11d2ee..76e7944cfd7 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx @@ -5,6 +5,9 @@ import { BlockQuote, Button, Section, Stack, Tabs } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const allystyle = { fontWeight: 'bold', @@ -55,6 +58,7 @@ const IntroductionSection = (props, context) => { /> } /> +
diff --git a/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx b/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx index fb98e1aa35b..58c379ab522 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx @@ -1,5 +1,8 @@ import { BlockQuote, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const goodstyle = { color: 'lightgreen', @@ -48,6 +51,11 @@ export const AntagInfoMorph = (props, context) => { {' '} + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */}
diff --git a/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx b/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx index 327e114e2fd..6d4b105c498 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx @@ -1,5 +1,8 @@ import { BlockQuote, LabeledList, Section, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const tipstyle = { color: 'white', @@ -68,6 +71,11 @@ export const AntagInfoNightmare = (props, context) => {
+ {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */}
diff --git a/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx b/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx index a537888af75..0615e46e05d 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx @@ -3,6 +3,9 @@ import { useBackend } from '../backend'; import { Icon, Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const ninja_emphasis = { color: 'red', @@ -48,6 +51,11 @@ export const AntagInfoNinja = (props, context) => { what you can do! + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} { + const { data } = useBackend(context); + const { antag_name } = data; + switch (antag_name) { + case 'Abductor Agent' || 'Abductor Scientist' || 'Abductor Solo': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Drifting Contractor': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Cortical Borer': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Venus Human Trap': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Obsessed': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Revenant': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Space Dragon': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Space Pirate': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Blob': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Changeling': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'ClockCult': + return ( + + Special Rules: + {Dont be an asshole.} + + ); + case 'AssaultOps': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Heretic': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Malf AI': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Morph': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Nightmare': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Ninja': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Wizard': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + default: + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + } +}; diff --git a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx index cc62986c085..083e3b2372c 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx @@ -4,6 +4,9 @@ import { BlockQuote, Button, Dimmer, Section, Stack } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const allystyle = { fontWeight: 'bold', @@ -48,6 +51,14 @@ const IntroductionSection = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + {/* SKYRAT EDIT ADDITION START */} + + + + + {/* SKYRAT EDIT ADDITION END */} ); @@ -218,11 +229,12 @@ const CodewordsSection = (props, context) => { ); }; +// SKYRAT EDIT: change height from 580 to 650 export const AntagInfoTraitor = (props, context) => { const { data } = useBackend(context); const { theme } = data; return ( - + diff --git a/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx b/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx index e5de257851a..94d528513d0 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx @@ -3,6 +3,9 @@ import { useBackend } from '../backend'; import { Box, Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const teleportstyle = { color: 'yellow', @@ -48,12 +51,13 @@ type Info = { can_change_objective: BooleanLike; }; +// SKYRAT CHANGE height from 630 to 700 export const AntagInfoWizard = (props, context) => { const { data, act } = useBackend(context); const { ritual, objectives, can_change_objective } = data; return ( - + @@ -78,6 +82,11 @@ export const AntagInfoWizard = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/Autolathe.tsx b/tgui/packages/tgui/interfaces/Autolathe.tsx index 1436d045256..e83554e7164 100644 --- a/tgui/packages/tgui/interfaces/Autolathe.tsx +++ b/tgui/packages/tgui/interfaces/Autolathe.tsx @@ -118,18 +118,20 @@ type PrintButtonProps = { quantity: number; availableMaterials: MaterialMap; SHEET_MATERIAL_AMOUNT: number; + maxmult: number; }; const PrintButton = (props: PrintButtonProps, context) => { const { act } = useBackend(context); - const { design, quantity, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; - - const canPrint = !Object.entries(design.cost).some( - ([material, amount]) => - !availableMaterials[material] || - amount * quantity > (availableMaterials[material] ?? 0) - ); + const { + design, + quantity, + availableMaterials, + SHEET_MATERIAL_AMOUNT, + maxmult, + } = props; + const canPrint = maxmult >= quantity; return ( { !canPrint && 'FabricatorRecipe__Button--disabled', ])} color={'transparent'} - onClick={() => act('make', { id: design.id, multiplier: quantity })}> + onClick={() => + canPrint && act('make', { id: design.id, multiplier: quantity }) + }> ×{quantity} @@ -163,11 +167,8 @@ const AutolatheRecipe = (props: AutolatheRecipeProps, context) => { const { act } = useBackend(context); const { design, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; - const canPrint = !Object.entries(design.cost).some( - ([material, amount]) => - !availableMaterials[material] || - amount > (availableMaterials[material] ?? 0) - ); + const maxmult = design.maxmult; + const canPrint = maxmult > 0; return (
@@ -195,7 +196,9 @@ const AutolatheRecipe = (props: AutolatheRecipeProps, context) => { 'FabricatorRecipe__Title', !canPrint && 'FabricatorRecipe__Title--disabled', ])} - onClick={() => act('make', { id: design.id, multiplier: 1 })}> + onClick={() => + canPrint && act('make', { id: design.id, multiplier: 1 }) + }>
{ quantity={5} SHEET_MATERIAL_AMOUNT={SHEET_MATERIAL_AMOUNT} availableMaterials={availableMaterials} + maxmult={maxmult} /> { quantity={10} SHEET_MATERIAL_AMOUNT={SHEET_MATERIAL_AMOUNT} availableMaterials={availableMaterials} + maxmult={maxmult} />
{ !canPrint && 'FabricatorRecipe__Button--disabled', ])}> act('make', { id: design.id, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx index 4afde6a8bb1..ed5fb9aafa7 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx @@ -9,5 +9,8 @@ export const pixel_size: Feature = { 1.5: 'Pixel Perfect 1.5x', 2: 'Pixel Perfect 2x', 3: 'Pixel Perfect 3x', + 4: 'Pixel Perfect 4x', + 4.5: 'Pixel Perfect 4.5x', + 5: 'Pixel Perfect 5x', }), };