diff --git a/_maps/shuttles/emergency_cruise.dmm b/_maps/shuttles/emergency_cruise.dmm index 43553972dc5842..aa4364858e12c6 100644 --- a/_maps/shuttles/emergency_cruise.dmm +++ b/_maps/shuttles/emergency_cruise.dmm @@ -925,9 +925,7 @@ /turf/open/floor/iron, /area/shuttle/escape) "tT" = ( -/obj/structure/railing{ - dir = 2 - }, +/obj/structure/railing, /turf/open/floor/carpet/red, /area/shuttle/escape) "tZ" = ( @@ -1224,9 +1222,7 @@ /turf/open/floor/iron, /area/shuttle/escape) "Av" = ( -/obj/structure/railing{ - dir = 2 - }, +/obj/structure/railing, /obj/machinery/light/directional/north, /turf/open/floor/iron/stairs{ dir = 8 @@ -1398,7 +1394,9 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/effect/fun_balloon/sentience/emergency_shuttle, +/obj/effect/fun_balloon/sentience/emergency_shuttle{ + group_name = "bar staff on the NTTS Independence" + }, /turf/open/floor/wood/parquet, /area/shuttle/escape) "DF" = ( @@ -1754,9 +1752,7 @@ /obj/effect/turf_decal/siding/thinplating{ dir = 6 }, -/obj/structure/railing{ - dir = 2 - }, +/obj/structure/railing, /turf/open/floor/iron, /area/shuttle/escape) "LD" = ( @@ -2818,7 +2814,7 @@ WX hB AF Mv -DA +Tz il YY tG @@ -2864,7 +2860,7 @@ at AL AF AF -Tz +DA il IO Ew diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index b836c811667e4a..601f441c66dd45 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -23,9 +23,11 @@ #define COMSIG_MOVABLE_DRIFT_BLOCK_INPUT "movable_drift_block_input" #define DRIFT_ALLOW_INPUT (1<<0) ///from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum) -#define COMSIG_MOVABLE_IMPACT "movable_impact" +#define COMSIG_MOVABLE_PRE_IMPACT "movable_pre_impact" #define COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH (1<<0) //if true, flip if the impact will push what it hits #define COMPONENT_MOVABLE_IMPACT_NEVERMIND (1<<1) //return true if you destroyed whatever it was you're impacting and there won't be anything for hitby() to run on +///from base of atom/movable/throw_impact() after confirming a hit: (/atom/hit_atom, /datum/thrownthing/throwingdatum) +#define COMSIG_MOVABLE_IMPACT "movable_impact" ///from base of mob/living/hitby(): (mob/living/target, hit_zone, blocked, datum/thrownthing/throwingdatum) #define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" ///from /atom/movable/proc/buckle_mob(): (mob/living/M, force, check_loc, buckle_mob_flags) diff --git a/code/__DEFINES/~skyrat_defines/traits/declarations.dm b/code/__DEFINES/~skyrat_defines/traits/declarations.dm index e7eb77d9224f39..c005247fb552df 100644 --- a/code/__DEFINES/~skyrat_defines/traits/declarations.dm +++ b/code/__DEFINES/~skyrat_defines/traits/declarations.dm @@ -16,6 +16,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_OXYIMMUNE "oxyimmune" // Immune to oxygen damage, ideally give this to all non-breathing species or bad stuff will happen #define TRAIT_AFFECTION_AVERSION "affection_aversion" // No more dogborg licking. "Dogborg bad" is no longer a personality #define TRAIT_PERSONALSPACE "personalspace" // Block/counter-attack ass-slaps +#define TRAIT_QUICKREFLEXES "quickreflexes" // Counters hugs and headpats #define TRAIT_MOOD_NOEXAMINE "mood_noexamine" // Can't assess your own mood #define TRAIT_DNR "do_not_revive" // Can't be revived without supernatural means or admin intervention #define TRAIT_HARD_SOLES "hard_soles" // No step on glass diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index c46b5986d08716..7388770cab42a9 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -611,6 +611,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_OVERSIZED" = TRAIT_OVERSIZED, "TRAIT_OXYIMMUNE" = TRAIT_OXYIMMUNE, "TRAIT_PERSONALSPACE" = TRAIT_PERSONALSPACE, + "TRAIT_QUICKREFLEXES" = TRAIT_QUICKREFLEXES, "TRAIT_PET_OWNER" = TRAIT_PET_OWNER, "TRAIT_R_UNIQUEWRECK" = TRAIT_R_UNIQUEWRECK, "TRAIT_R_UNIQUETIP" = TRAIT_R_UNIQUETIP, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index f73d9ac3d9e1bd..221d6ef820d1db 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -316,6 +316,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_OVERSIZED" = TRAIT_OVERSIZED, "TRAIT_OXYIMMUNE" = TRAIT_OXYIMMUNE, "TRAIT_PERSONALSPACE" = TRAIT_PERSONALSPACE, + "TRAIT_QUICKREFLEXES" = TRAIT_QUICKREFLEXES, "TRAIT_PET_OWNER" = TRAIT_PET_OWNER, "TRAIT_R_UNIQUEWRECK" = TRAIT_R_UNIQUEWRECK, "TRAIT_R_UNIQUETIP" = TRAIT_R_UNIQUETIP, diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 88a24f50516a65..06a4aac8358ae0 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -70,6 +70,9 @@ multiple modular subtrees with behaviors /datum/ai_controller/Destroy(force, ...) set_ai_status(AI_STATUS_OFF) UnpossessPawn(FALSE) + set_movement_target(type, null) + if(ai_movement.moving_controllers[src]) + ai_movement.stop_moving_towards(src) return ..() ///Sets the current movement target, with an optional param to override the movement behavior @@ -118,6 +121,7 @@ multiple modular subtrees with behaviors reset_ai_status() RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed)) RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) + RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted)) /// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere /datum/ai_controller/proc/reset_ai_status() @@ -152,7 +156,7 @@ multiple modular subtrees with behaviors if(isnull(pawn)) return // instantiated without an applicable pawn, fine - UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE)) + UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) if(ai_movement.moving_controllers[src]) ai_movement.stop_moving_towards(src) pawn.ai_controller = null @@ -230,6 +234,8 @@ multiple modular subtrees with behaviors ///Determines whether the AI can currently make a new plan /datum/ai_controller/proc/able_to_plan() . = TRUE + if(QDELETED(pawn)) + return FALSE for(var/datum/ai_behavior/current_behavior as anything in current_behaviors) if(!(current_behavior.behavior_flags & AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION)) //We have a behavior that blocks planning . = FALSE @@ -296,7 +302,7 @@ multiple modular subtrees with behaviors if(length(arguments)) behavior_args[behavior_type] = arguments else - behavior_args[behavior_type] = null + behavior_args -= behavior_type /datum/ai_controller/proc/ProcessBehavior(seconds_per_tick, datum/ai_behavior/behavior) var/list/arguments = list(seconds_per_tick, src) @@ -334,6 +340,14 @@ multiple modular subtrees with behaviors set_ai_status(AI_STATUS_ON) //Can't do anything while player is connected RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) +// Turn the controller off the controller if the pawn has been qdeleted +/datum/ai_controller/proc/on_pawn_qdeleted() + SIGNAL_HANDLER + set_ai_status(AI_STATUS_OFF) + set_movement_target(type, null) + if(ai_movement.moving_controllers[src]) + ai_movement.stop_moving_towards(src) + /// Use this proc to define how your controller defines what access the pawn has for the sake of pathfinding. Return the access list you want to use /datum/ai_controller/proc/get_access() return diff --git a/code/datums/ai/babies/babies_behaviors.dm b/code/datums/ai/babies/babies_behaviors.dm index 5941bb818f448d..8cc03d72f6b762 100644 --- a/code/datums/ai/babies/babies_behaviors.dm +++ b/code/datums/ai/babies/babies_behaviors.dm @@ -75,4 +75,6 @@ if(!succeeded) return var/mob/living/living_pawn = controller.pawn + if(QDELETED(living_pawn)) // pawn can be null at this point + return living_pawn.set_combat_mode(initial(living_pawn.combat_mode)) diff --git a/code/datums/ai/bane/bane_behaviors.dm b/code/datums/ai/bane/bane_behaviors.dm index d36c110f0c32c0..c47c455f7f9cc6 100644 --- a/code/datums/ai/bane/bane_behaviors.dm +++ b/code/datums/ai/bane/bane_behaviors.dm @@ -3,5 +3,7 @@ if(succeeded) var/list/bane_quotes = strings("bane.json", "bane") var/mob/living/bane = controller.pawn + if(QDELETED(bane)) // pawn can be null at this point + return ..() bane.say(pick(bane_quotes)) return ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm index bb901066025750..c8c18072a4aaa0 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm @@ -25,6 +25,8 @@ . = ..() var/obj/structure/flora/target_tree = controller.blackboard[target_key] var/mob/living/basic/living_pawn = controller.pawn + if(QDELETED(living_pawn)) // pawn can be null at this point + return SEND_SIGNAL(living_pawn, COMSIG_LIVING_CLIMB_TREE, target_tree) finish_action(controller, TRUE, target_key) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm index d0fb7e3e8c7074..655b335d3b63cf 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm @@ -4,11 +4,11 @@ . = ..() var/mob/living/living_pawn = controller.pawn - var/atom/movable/buckled_too = living_pawn.buckled + var/atom/movable/buckled_to = living_pawn.buckled - if(isnull(buckled_too)) + if(isnull(buckled_to)) finish_action(controller, FALSE) return - buckled_too.unbuckle_mob(living_pawn) + buckled_to.unbuckle_mob(living_pawn) finish_action(controller, TRUE) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm b/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm index 8d2dd2443defc5..240272d1ef48a1 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm @@ -2,7 +2,7 @@ /datum/ai_planning_subtree/opportunistic_ventcrawler /datum/ai_planning_subtree/opportunistic_ventcrawler/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - if(QDELETED(controller.pawn) || HAS_TRAIT(controller.pawn, TRAIT_MOVE_VENTCRAWLING)) + if(HAS_TRAIT(controller.pawn, TRAIT_MOVE_VENTCRAWLING)) return SUBTREE_RETURN_FINISH_PLANNING // hold on let me cook var/obj/machinery/atmospherics/components/unary/vent_pump/target = controller.blackboard[BB_ENTRY_VENT_TARGET] diff --git a/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm index 584fb984839f24..c7153b0c12f7a4 100644 --- a/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm +++ b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm @@ -16,7 +16,7 @@ finish_action(controller, FALSE, ability_key, target_key) return var/mob/pawn = controller.pawn - if (ability.InterceptClickOn(pawn, null, target)) + if(QDELETED(pawn) || ability.InterceptClickOn(pawn, null, target)) finish_action(controller, TRUE, ability_key, target_key) /datum/ai_behavior/pet_use_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key) diff --git a/code/datums/ai/basic_mobs/pet_commands/play_dead.dm b/code/datums/ai/basic_mobs/pet_commands/play_dead.dm index 0520898c4a53a6..c4b99cf6f42b15 100644 --- a/code/datums/ai/basic_mobs/pet_commands/play_dead.dm +++ b/code/datums/ai/basic_mobs/pet_commands/play_dead.dm @@ -18,7 +18,7 @@ /datum/ai_behavior/play_dead/finish_action(datum/ai_controller/controller, succeeded) . = ..() var/mob/living/basic/basic_pawn = controller.pawn - if(!istype(basic_pawn) || basic_pawn.stat) // imagine actually dying while playing dead. hell, imagine being the kid waiting for your pup to get back up :( + if(QDELETED(basic_pawn) || basic_pawn.stat) // imagine actually dying while playing dead. hell, imagine being the kid waiting for your pup to get back up :( return basic_pawn.visible_message(span_notice("[basic_pawn] miraculously springs back to life!")) REMOVE_TRAIT(basic_pawn, TRAIT_FAKEDEATH, BASIC_MOB_DEATH_TRAIT) diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm index 962c8d141cd8aa..9a7ec19cd5eb78 100644 --- a/code/datums/ai/generic/generic_behaviors.dm +++ b/code/datums/ai/generic/generic_behaviors.dm @@ -67,6 +67,8 @@ /datum/ai_behavior/break_spine/finish_action(datum/ai_controller/controller, succeeded, target_key) if(succeeded) var/mob/living/bane = controller.pawn + if(QDELETED(bane)) // pawn can be null at this point + return ..() bane.stop_pulling() controller.clear_blackboard_key(target_key) return ..() @@ -283,8 +285,6 @@ . = ..() controller.clear_blackboard_key(BB_FOLLOW_TARGET) - - /datum/ai_behavior/perform_emote /datum/ai_behavior/perform_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote, speech_sound) diff --git a/code/datums/ai/generic/generic_subtrees.dm b/code/datums/ai/generic/generic_subtrees.dm index c33091a64d434d..12007a261240f5 100644 --- a/code/datums/ai/generic/generic_subtrees.dm +++ b/code/datums/ai/generic/generic_subtrees.dm @@ -32,8 +32,6 @@ */ /datum/ai_planning_subtree/generic_resist/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - if(QDELETED(living_pawn)) - return if(SHOULD_RESIST(living_pawn) && SPT_PROB(RESIST_SUBTREE_PROB, seconds_per_tick)) controller.queue_behavior(/datum/ai_behavior/resist) //BRO IM ON FUCKING FIRE BRO diff --git a/code/datums/ai/hunting_behavior/hunting_behaviors.dm b/code/datums/ai/hunting_behavior/hunting_behaviors.dm index f3ffa8c130b995..3e747640be3e27 100644 --- a/code/datums/ai/hunting_behavior/hunting_behaviors.dm +++ b/code/datums/ai/hunting_behavior/hunting_behaviors.dm @@ -30,7 +30,7 @@ return var/mob/living/living_pawn = controller.pawn // We can't hunt if we're indisposed - if(QDELETED(living_pawn) || HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED) || living_pawn.stat != CONSCIOUS) + if(HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED) || living_pawn.stat != CONSCIOUS) return var/atom/hunted = controller.blackboard[target_key] diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm index 13ae68170053c2..b041ec763a8f84 100644 --- a/code/datums/ai/monkey/monkey_behaviors.dm +++ b/code/datums/ai/monkey/monkey_behaviors.dm @@ -166,8 +166,10 @@ /datum/ai_behavior/monkey_attack_mob/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() var/mob/living/living_pawn = controller.pawn - SSmove_manager.stop_looping(living_pawn) controller.clear_blackboard_key(target_key) + if(QDELETED(living_pawn)) // pawn can be null at this point + return + SSmove_manager.stop_looping(living_pawn) /// attack using a held weapon otherwise bite the enemy, then if we are angry there is a chance we might calm down a little /datum/ai_behavior/monkey_attack_mob/proc/monkey_attack(datum/ai_controller/controller, mob/living/target, seconds_per_tick, disarm) diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index 4e2f0a90b1e2ba..951147007f9b82 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -97,8 +97,6 @@ have ways of interacting with a specific mob and control it. /datum/ai_controller/monkey/proc/set_trip_mode(mode = TRUE) var/mob/living/carbon/regressed_monkey = pawn - if(QDELETED(regressed_monkey)) - return var/brain = regressed_monkey.get_organ_slot(ORGAN_SLOT_BRAIN) if(istype(brain, /obj/item/organ/internal/brain/primate)) // In case we are a monkey AI in a human brain by who was previously controlled by a client but it now not by some marvel var/obj/item/organ/internal/brain/primate/monkeybrain = brain diff --git a/code/datums/ai/monkey/monkey_subtrees.dm b/code/datums/ai/monkey/monkey_subtrees.dm index 75d2a3eb3a58e1..572eeb6b56e922 100644 --- a/code/datums/ai/monkey/monkey_subtrees.dm +++ b/code/datums/ai/monkey/monkey_subtrees.dm @@ -26,9 +26,6 @@ ///monkey combat subtree. /datum/ai_planning_subtree/monkey_combat/SelectBehaviors(datum/ai_controller/monkey/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - if(QDELETED(living_pawn)) - return - var/list/enemies = controller.blackboard[BB_MONKEY_ENEMIES] if((HAS_TRAIT(controller.pawn, TRAIT_PACIFISM)) || (!length(enemies) && !controller.blackboard[BB_MONKEY_AGGRESSIVE])) //Pacifist, or we have no enemies and we're not pissed diff --git a/code/datums/ai/robot_customer/robot_customer_behaviors.dm b/code/datums/ai/robot_customer/robot_customer_behaviors.dm index 95260b8e68de2c..35fd26d76f6fe0 100644 --- a/code/datums/ai/robot_customer/robot_customer_behaviors.dm +++ b/code/datums/ai/robot_customer/robot_customer_behaviors.dm @@ -103,7 +103,7 @@ var/mob/living/greytider = controller.blackboard[BB_CUSTOMER_CURRENT_TARGET] //usually if we stop waiting, it's because we're done with the venue. but here we're either beating some dude up //or are being qdeleted and don't want runtime errors, so don't switch to leaving - if(greytider || QDELETED(src)) + if(greytider || QDELETED(src) || QDELETED(customer_pawn)) return controller.set_blackboard_key(BB_CUSTOMER_LEAVING, TRUE) customer_pawn.update_icon() //They might have a special leaving accesoiry (french flag) diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index 1b19b4744cb75c..6d1122fa716efe 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -17,7 +17,6 @@ var/obsession_hug_count = 0 /datum/brain_trauma/special/obsessed/on_gain() - //setup, linking, etc// if(!obsession)//admins didn't set one obsession = find_obsession() @@ -34,6 +33,7 @@ //antag stuff// antagonist.forge_objectives(obsession.mind) antagonist.greet() + log_game("[key_name(antagonist)] has developed an obsession with [key_name(obsession)].") RegisterSignal(owner, COMSIG_CARBON_HELPED, PROC_REF(on_hug)) /datum/brain_trauma/special/obsessed/on_life(seconds_per_tick, times_fired) @@ -69,6 +69,7 @@ owner.mind.remove_antag_datum(/datum/antagonist/obsessed) owner.clear_mood_event("creeping") if(obsession) + log_game("[key_name(owner)] is no longer obsessed with [key_name(obsession)].") UnregisterSignal(obsession, COMSIG_MOB_EYECONTACT) /datum/brain_trauma/special/obsessed/handle_speech(datum/source, list/speech_args) diff --git a/code/datums/components/crafting/robot.dm b/code/datums/components/crafting/robot.dm index 9c05bdf7fb3a14..e0c6b4ecd3a688 100644 --- a/code/datums/components/crafting/robot.dm +++ b/code/datums/components/crafting/robot.dm @@ -3,7 +3,7 @@ result = /mob/living/simple_animal/bot/secbot/ed209 reqs = list( /obj/item/robot_suit = 1, - /obj/item/clothing/head/helmet = 1, + /obj/item/clothing/head/helmet/sec = 1, /obj/item/clothing/suit/armor/vest = 1, /obj/item/bodypart/leg/left/robot = 1, /obj/item/bodypart/leg/right/robot = 1, diff --git a/code/datums/components/on_hit_effect.dm b/code/datums/components/on_hit_effect.dm index 38610395248b32..50f31269f16344 100644 --- a/code/datums/components/on_hit_effect.dm +++ b/code/datums/components/on_hit_effect.dm @@ -11,12 +11,15 @@ var/datum/callback/on_hit_callback ///callback optionally used for more checks var/datum/callback/extra_check_callback + ///optionally should we also apply the effect if thrown at something? + var/thrown_effect -/datum/component/on_hit_effect/Initialize(on_hit_callback, extra_check_callback) +/datum/component/on_hit_effect/Initialize(on_hit_callback, extra_check_callback, thrown_effect = FALSE) src.on_hit_callback = on_hit_callback src.extra_check_callback = extra_check_callback if(!(ismachinery(parent) || isstructure(parent) || isgun(parent) || isprojectilespell(parent) || isitem(parent) || isanimal_or_basicmob(parent) || isprojectile(parent))) return ELEMENT_INCOMPATIBLE + src.thrown_effect = thrown_effect /datum/component/on_hit_effect/Destroy(force, silent) on_hit_callback = null @@ -33,12 +36,16 @@ else if(isprojectile(parent)) RegisterSignal(parent, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_projectile_self_hit)) + if(thrown_effect) + RegisterSignal(parent, COMSIG_MOVABLE_IMPACT, PROC_REF(on_thrown_hit)) + /datum/component/on_hit_effect/UnregisterFromParent() UnregisterSignal(parent, list( COMSIG_PROJECTILE_ON_HIT, COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_POST_ATTACKINGTARGET, COMSIG_PROJECTILE_SELF_ON_HIT, + COMSIG_MOVABLE_IMPACT, )) /datum/component/on_hit_effect/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters) @@ -79,3 +86,9 @@ if(!extra_check_callback.Invoke(firer, target)) return on_hit_callback.Invoke(source, firer, target, body_zone) + +/datum/component/on_hit_effect/proc/on_thrown_hit(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + if(extra_check_callback && !extra_check_callback.Invoke(source, hit_atom)) + return + on_hit_callback.Invoke(source, source, hit_atom, null) diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index e4027e4565c355..c05277c136f7c3 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -54,11 +54,11 @@ /datum/component/tackler/RegisterWithParent() RegisterSignal(parent, COMSIG_MOB_CLICKON, PROC_REF(checkTackle)) - RegisterSignal(parent, COMSIG_MOVABLE_IMPACT, PROC_REF(sack)) + RegisterSignal(parent, COMSIG_MOVABLE_PRE_IMPACT, PROC_REF(sack)) RegisterSignal(parent, COMSIG_MOVABLE_POST_THROW, PROC_REF(registerTackle)) /datum/component/tackler/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_MOB_CLICKON, COMSIG_MOVABLE_IMPACT, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_POST_THROW)) + UnregisterSignal(parent, list(COMSIG_MOB_CLICKON, COMSIG_MOVABLE_PRE_IMPACT, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_POST_THROW)) ///Store the thrownthing datum for later use /datum/component/tackler/proc/registerTackle(mob/living/carbon/user, datum/thrownthing/tackle) diff --git a/code/datums/elements/elevation.dm b/code/datums/elements/elevation.dm index 8a21edbd2e1992..645ee2a6081ea1 100644 --- a/code/datums/elements/elevation.dm +++ b/code/datums/elements/elevation.dm @@ -72,7 +72,8 @@ post_change_callbacks += CALLBACK(src, PROC_REF(post_change_turf), trait_sources) /datum/element/elevation/proc/post_change_turf(list/trait_sources, turf/changed) - ADD_TRAIT(changed, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), trait_sources) + for(var/source in trait_sources) + ADD_TRAIT(changed, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), source) reset_elevation(changed) #define ELEVATE_TIME 0.2 SECONDS diff --git a/code/datums/elements/venomous.dm b/code/datums/elements/venomous.dm index b310e01bafc342..ba4e088750cd19 100644 --- a/code/datums/elements/venomous.dm +++ b/code/datums/elements/venomous.dm @@ -8,14 +8,21 @@ argument_hash_start_idx = 2 ///Path of the reagent added var/poison_type + ///Details of how we inject our venom + var/injection_flags ///How much of the reagent added. if it's a list, it'll pick a range with the range being list(lower_value, upper_value) var/list/amount_added -/datum/element/venomous/Attach(datum/target, poison_type, amount_added) +/datum/element/venomous/Attach(datum/target, poison_type, amount_added, injection_flags = NONE, thrown_effect = FALSE) . = ..() src.poison_type = poison_type src.amount_added = amount_added - target.AddComponent(/datum/component/on_hit_effect, CALLBACK(src, PROC_REF(do_venom))) + src.injection_flags = injection_flags + target.AddComponent(\ + /datum/component/on_hit_effect,\ + on_hit_callback = CALLBACK(src, PROC_REF(do_venom)),\ + thrown_effect = thrown_effect,\ + ) /datum/element/venomous/Detach(datum/target) qdel(target.GetComponent(/datum/component/on_hit_effect)) @@ -26,6 +33,8 @@ return if(target.stat == DEAD) return + if(isliving(element_owner) && !target.try_inject(element_owner, hit_zone, injection_flags)) + return var/final_amount_added if(islist(amount_added)) final_amount_added = rand(amount_added[1], amount_added[2]) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 317e155ef5ee71..e5f199b47ac4ba 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -4,7 +4,8 @@ /datum/mood_event/broken_vow //Used for when mimes break their vow of silence description = "I have brought shame upon my name, and betrayed my fellow mimes by breaking our sacred vow..." - mood_change = -8 + mood_change = -4 + timeout = 3 MINUTES /datum/mood_event/on_fire description = "I'M ON FIRE!!!" diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 8a9512bae1c3c6..b8847cd652195f 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -57,8 +57,11 @@ /datum/mood_event/exercise description = "Working out releases those endorphins!" - mood_change = 2 - timeout = 5 MINUTES + mood_change = 1 + +/datum/mood_event/exercise/add_effects(fitness_level) + mood_change = fitness_level // the more fit you are, the more you like to work out + return ..() /datum/mood_event/pet_animal description = "Animals are adorable! I can't stop petting them!" diff --git a/code/datums/quirks/negative_quirks/all_nighter.dm b/code/datums/quirks/negative_quirks/all_nighter.dm index 981c701c0555ff..798add0539f240 100644 --- a/code/datums/quirks/negative_quirks/all_nighter.dm +++ b/code/datums/quirks/negative_quirks/all_nighter.dm @@ -31,7 +31,9 @@ /datum/reagent/drug/pumpup, /datum/reagent/drug/blastoff, /datum/reagent/consumable/coffee, - /datum/reagent/consumable/tea + /datum/reagent/consumable/tea, + /datum/reagent/consumable/volt_energy, + /datum/reagent/consumable/monkey_energy ) ///essentially our "sleep bank". sleeping charges it up and its drained while awake var/five_more_minutes = 0 diff --git a/code/datums/skills/fitness.dm b/code/datums/skills/fitness.dm index c19a374893e836..5e6e3a14c23cdd 100644 --- a/code/datums/skills/fitness.dm +++ b/code/datums/skills/fitness.dm @@ -3,20 +3,23 @@ title = "Fitness" desc = "Twinkle twinkle little star, hit the gym and lift the bar." /// The skill value modifier effects the max duration that is possible for /datum/status_effect/exercised - modifiers = list(SKILL_VALUE_MODIFIER = list(2 MINUTES, 3 MINUTES, 4 MINUTES, 5 MINUTES, 6 MINUTES, 7 MINUTES, 10 MINUTES)) + modifiers = list(SKILL_VALUE_MODIFIER = list(1 MINUTES, 1.5 MINUTES, 2 MINUTES, 2.5 MINUTES, 3 MINUTES, 3.5 MINUTES, 5 MINUTES)) + /// How much bigger your mob becomes per level (these effects don't stack together) + var/static/size_boost = list(0, 1/16, 1/8, 3/16, 2/8, 3/8, 4/8) // skill_item_path - your mob sprite gets bigger to showoff so we don't get a special item /* SKYRAT EDIT REMOVAL START - NO SIZE INCREASE /datum/skill/fitness/level_gained(datum/mind/mind, new_level, old_level, silent) . = ..() + var/old_gym_size = RESIZE_DEFAULT_SIZE + size_boost[old_level] + var/new_gym_size = RESIZE_DEFAULT_SIZE + size_boost[new_level] - var/size_boost = (new_level == SKILL_LEVEL_LEGENDARY) ? 0.25 : 0.05 - var/gym_size = RESIZE_DEFAULT_SIZE + size_boost - mind.current.update_transform(gym_size) + mind.current.update_transform(new_gym_size / old_gym_size) /datum/skill/fitness/level_lost(datum/mind/mind, new_level, old_level, silent) . = ..() - var/size_boost = (new_level == SKILL_LEVEL_LEGENDARY) ? 0.25 : 0.05 - var/gym_size = RESIZE_DEFAULT_SIZE + size_boost - mind.current.update_transform(RESIZE_DEFAULT_SIZE / gym_size) + var/old_gym_size = RESIZE_DEFAULT_SIZE + size_boost[old_level] + var/new_gym_size = RESIZE_DEFAULT_SIZE + size_boost[new_level] + + mind.current.update_transform(new_gym_size / old_gym_size) SKYRAT EDIT REMOVAL END */ diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 19b474da0bf00e..39d5c3a3754f75 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -162,31 +162,33 @@ /datum/status_effect/exercised id = "Exercised" - duration = 30 SECONDS + duration = 15 SECONDS status_type = STATUS_EFFECT_REFRESH // New effects will add to total duration alert_type = null processing_speed = STATUS_EFFECT_NORMAL_PROCESS alert_type = /atom/movable/screen/alert/status_effect/exercised /// Having any of these reagents in your system extends the duration var/static/list/supplementary_reagents_bonus = list( - /datum/reagent/consumable/ethanol/protein_blend = 30 SECONDS, // protein shakes are very robust - /datum/reagent/inverse/oxandrolone = 25 SECONDS, - /datum/reagent/consumable/eggwhite = 20 SECONDS, - /datum/reagent/consumable/eggyolk = 15 SECONDS, - /datum/reagent/consumable/nutriment/protein = 15 SECONDS, - /datum/reagent/consumable/nutriment/vitamin = 10 SECONDS, - /datum/reagent/consumable/rice = 10 SECONDS, - /datum/reagent/consumable/milk = 10 SECONDS, - /datum/reagent/consumable/soymilk = 5 SECONDS, // darn vegans! - /datum/reagent/consumable/nutraslop = 5 SECONDS, // prison food to bulk up with + /datum/reagent/consumable/ethanol/protein_blend = 10 SECONDS, // protein shakes are very robust + /datum/reagent/inverse/oxandrolone = 8 SECONDS, + /datum/reagent/consumable/nutriment/protein = 5 SECONDS, + /datum/reagent/consumable/nutriment/vitamin = 4 SECONDS, + /datum/reagent/consumable/milk = 4 SECONDS, + /datum/reagent/consumable/rice = 3 SECONDS, + // keep in mind you can eat a raw egg to acquire both these reagents at the same time + /datum/reagent/consumable/eggwhite = 3 SECONDS, + /datum/reagent/consumable/eggyolk = 2 SECONDS, + // weak workout food + /datum/reagent/consumable/nutraslop = 2 SECONDS, // prison food to bulk up with + /datum/reagent/consumable/soymilk = 1 SECONDS, // darn vegans! // time for the bad stuff - /datum/reagent/consumable/sugar = -5 SECONDS, - /datum/reagent/consumable/monkey_energy = -5 SECONDS, - /datum/reagent/consumable/nutriment/fat = -5 SECONDS, + /datum/reagent/consumable/sugar = -1 SECONDS, + /datum/reagent/consumable/monkey_energy = -1 SECONDS, // the marketing was a lie + /datum/reagent/consumable/nutriment/fat = -1 SECONDS, ) /datum/status_effect/exercised/proc/workout_duration(mob/living/new_owner, bonus_time) - if(!bonus_time || !new_owner.mind) + if(!bonus_time || !new_owner.mind || !iscarbon(new_owner)) return 0 SECONDS var/modifier = 1 @@ -207,7 +209,7 @@ if(new_owner.reagents.has_reagent(workout_reagent)) food_boost += supplementary_reagents_bonus[workout_reagent] - var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/fitness) - 1) * 5 SECONDS + var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/fitness) - 1) * 2 SECONDS bonus_time = (bonus_time + food_boost + skill_level_boost) * modifier var/exhaustion_limit = new_owner.mind.get_skill_modifier(/datum/skill/fitness, SKILL_VALUE_MODIFIER) + world.time @@ -219,15 +221,21 @@ return bonus_time -/datum/status_effect/exercised/tick(seconds_between_ticks) - owner.reagents.metabolize(owner, seconds_between_ticks * SSMOBS_DT, 0) // doubles the metabolization rate - /datum/status_effect/exercised/on_creation(mob/living/new_owner, bonus_time) duration += workout_duration(new_owner, bonus_time) return ..() /datum/status_effect/exercised/refresh(mob/living/new_owner, bonus_time) duration += workout_duration(new_owner, bonus_time) + new_owner.clear_mood_event("exercise") // we need to reset the old mood event in case our fitness skill changes + new_owner.add_mood_event("exercise", /datum/mood_event/exercise, new_owner.mind.get_skill_level(/datum/skill/fitness)) + +/datum/status_effect/exercised/on_apply() + owner.add_mood_event("exercise", /datum/mood_event/exercise, owner.mind.get_skill_level(/datum/skill/fitness)) + return ..() + +/datum/status_effect/exercised/on_remove() + owner.clear_mood_event("exercise") /atom/movable/screen/alert/status_effect/exercised name = "Exercise" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0a5591a8ba8573..27cd0ff3ccef3d 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1248,7 +1248,7 @@ /atom/movable/proc/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) set waitfor = FALSE var/hitpush = TRUE - var/impact_signal = SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) + var/impact_signal = SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_IMPACT, hit_atom, throwingdatum) if(impact_signal & COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH) hitpush = FALSE // hacky, tie this to something else or a proper workaround later @@ -1256,6 +1256,7 @@ return // in case a signal interceptor broke or deleted the thing before we could process our hit if(SEND_SIGNAL(hit_atom, COMSIG_ATOM_PREHITBY, src, throwingdatum) & COMSIG_HIT_PREVENTED) return + SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) return hit_atom.hitby(src, throwingdatum=throwingdatum, hitpush=hitpush) /atom/movable/hitby(atom/movable/hitting_atom, skipcatch, hitpush = TRUE, blocked, datum/thrownthing/throwingdatum) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index ff5054032551ed..3c64e8ec07c352 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -24,8 +24,6 @@ COOLDOWN_DECLARE(activation_cooldown) - ///Trick to get the glowing overlay visible from a distance - luminosity = 1 ///X offset for the overlay lights, so that they line up with the thin border firelocks var/light_xoffset = 0 ///Y offset for the overlay lights, so that they line up with the thin border firelocks diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 7145e8b86a1b19..b3b1615adede43 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -27,8 +27,6 @@ light_range = 1.6 light_color = LIGHT_COLOR_ELECTRIC_CYAN - //Trick to get the glowing overlay visible from a distance - luminosity = 1 //We want to use area sensitivity, let us always_area_sensitive = TRUE ///Buildstate for contruction steps @@ -147,9 +145,9 @@ /obj/machinery/firealarm/update_appearance(updates) . = ..() if((my_area?.fire || LAZYLEN(my_area?.active_firelocks)) && !(obj_flags & EMAGGED) && !(machine_stat & (BROKEN|NOPOWER))) - set_light(l_power = 3) + set_light(l_range = 2.5, l_power = 1.5) else - set_light(l_power = 1) + set_light(l_range = 1.6, l_power = 1) /obj/machinery/firealarm/update_icon_state() if(panel_open) diff --git a/code/game/machinery/mining_weather_monitor.dm b/code/game/machinery/mining_weather_monitor.dm index d05d8820751a60..65cc4b9347c1ab 100644 --- a/code/game/machinery/mining_weather_monitor.dm +++ b/code/game/machinery/mining_weather_monitor.dm @@ -4,7 +4,6 @@ desc = "A machine monitoring atmospheric data from mining environments. Provides warnings about incoming weather fronts." icon = 'icons/obj/miningradio.dmi' icon_state = "wallmount" - luminosity = 1 light_power = 1 light_range = 1.6 diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 8d7131a0aa8a5d..1a20bf90e184ee 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -197,13 +197,6 @@ if(batong.cell) batong.cell.charge = 0 -/obj/machinery/recharger/update_appearance(updates) - . = ..() - if((machine_stat & (NOPOWER|BROKEN)) || panel_open || !anchored) - luminosity = 0 - return - luminosity = 1 - /obj/machinery/recharger/update_overlays() . = ..() if(machine_stat & (NOPOWER|BROKEN) || !anchored) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 39f56619253559..4a8ad3f4caddb6 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -796,10 +796,12 @@ /obj/item/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) if(QDELETED(hit_atom)) return - if(SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) & COMPONENT_MOVABLE_IMPACT_NEVERMIND) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_IMPACT, hit_atom, throwingdatum) & COMPONENT_MOVABLE_IMPACT_NEVERMIND) return if(SEND_SIGNAL(hit_atom, COMSIG_ATOM_PREHITBY, src, throwingdatum) & COMSIG_HIT_PREVENTED) return + + SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) if(get_temperature() && isliving(hit_atom)) var/mob/living/L = hit_atom L.ignite_mob() diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 0c0f8435f723d0..a9046145168ed8 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -266,12 +266,14 @@ continue if(target_felinid.body_position == STANDING_UP) target_felinid.setDir(get_dir(target_felinid, targloc)) // kitty always looks at the light - if(prob(effectchance * diode.rating)) + //SKYRAT EDIT REMOVAL BEGIN (removes forced felinid movement from laserpointers, also fixes the longstanding windoor negation glitch) + /* if(prob(effectchance * diode.rating)) target_felinid.visible_message(span_warning("[target_felinid] makes a grab for the light!"), span_userdanger("LIGHT!")) target_felinid.Move(targloc) log_combat(user, target_felinid, "moved with a laser pointer", src) - else - target_felinid.visible_message(span_notice("[target_felinid] looks briefly distracted by the light."), span_warning("You're briefly tempted by the shiny light...")) + else + SKYRAT EDIT REMOVAL END */ + target_felinid.visible_message(span_notice("[target_felinid] looks briefly distracted by the light."), span_warning("You're briefly tempted by the shiny light...")) //SKYRAT EDIT CHANGE : indent this block if re-enabling above else target_felinid.visible_message(span_notice("[target_felinid] stares at the light."), span_warning("You stare at the light...")) //The pointer is shining, change its sprite to show @@ -290,9 +292,9 @@ laser.pixel_y = target.pixel_y + rand(-5,5) if(outmsg) - to_chat(user, outmsg) + user.visible_message(span_danger("[user] points [src] at [target]!"), outmsg) //SKYRAT EDIT CHANGE - ORIGINAL: to_chat(user, outmsg) else - to_chat(user, span_info("You point [src] at [target].")) + user.visible_message(span_notice("[user] points [src] at [target]."), span_notice("You point [src] at [target].")) //SKYRAT EDIT CHANGE - ORIGINAL: to_chat(user, span_info("You point [src] at [target].")) //we have successfully shone our pointer, reduce our battery depending on whether we have an extra lens or not energy -= crystal_lens ? 2 : 1 diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 04db148ea5bab3..eef6059d98403a 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -126,8 +126,8 @@ return FALSE return TRUE -/obj/structure/ai_core/latejoin_inactive/attackby(obj/item/P, mob/user, params) - if(P.tool_behaviour == TOOL_MULTITOOL) +/obj/structure/ai_core/latejoin_inactive/attackby(obj/item/tool, mob/user, params) + if(tool.tool_behaviour == TOOL_MULTITOOL) active = !active to_chat(user, span_notice("You [active? "activate" : "deactivate"] \the [src]'s transmitters.")) return @@ -156,18 +156,18 @@ balloon_alert(user, "connected neural network") return ITEM_INTERACT_SUCCESS -/obj/structure/ai_core/attackby(obj/item/P, mob/living/user, params) +/obj/structure/ai_core/attackby(obj/item/tool, mob/living/user, params) if(!anchored) - if(P.tool_behaviour == TOOL_WELDER) + if(tool.tool_behaviour == TOOL_WELDER) if(state != EMPTY_CORE) balloon_alert(user, "core must be empty to deconstruct it!") return - if(!P.tool_start_check(user, amount=1)) + if(!tool.tool_start_check(user, amount=1)) return balloon_alert(user, "deconstructing frame...") - if(P.use_tool(src, user, 20, volume=50) && state == EMPTY_CORE) + if(tool.use_tool(src, user, 20, volume=50) && state == EMPTY_CORE) balloon_alert(user, "deconstructed frame") deconstruct(TRUE) return @@ -180,37 +180,37 @@ else switch(state) if(EMPTY_CORE) - if(istype(P, /obj/item/circuitboard/aicore)) - if(!user.transferItemToLoc(P, src)) + if(istype(tool, /obj/item/circuitboard/aicore)) + if(!user.transferItemToLoc(tool, src)) return playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "circuit board inserted") update_appearance() state = CIRCUIT_CORE - circuit = P + circuit = tool return if(CIRCUIT_CORE) - if(P.tool_behaviour == TOOL_SCREWDRIVER) - P.play_tool_sound(src) + if(tool.tool_behaviour == TOOL_SCREWDRIVER) + tool.play_tool_sound(src) balloon_alert(user, "board screwed into place") state = SCREWED_CORE update_appearance() return - if(P.tool_behaviour == TOOL_CROWBAR) - P.play_tool_sound(src) + if(tool.tool_behaviour == TOOL_CROWBAR) + tool.play_tool_sound(src) balloon_alert(user, "circuit board removed") state = EMPTY_CORE circuit.forceMove(loc) return if(SCREWED_CORE) - if(P.tool_behaviour == TOOL_SCREWDRIVER && circuit) - P.play_tool_sound(src) + if(tool.tool_behaviour == TOOL_SCREWDRIVER && circuit) + tool.play_tool_sound(src) balloon_alert(user, "circuit board unfastened") state = CIRCUIT_CORE update_appearance() return - if(istype(P, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = P + if(istype(tool, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = tool if(C.get_amount() >= 5) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "adding cables to frame...") @@ -222,22 +222,22 @@ balloon_alert(user, "need five lengths of cable!") return if(CABLED_CORE) - if(P.tool_behaviour == TOOL_WIRECUTTER) + if(tool.tool_behaviour == TOOL_WIRECUTTER) if(core_mmi) balloon_alert(user, "remove the [AI_CORE_BRAIN(core_mmi)] first!") else - P.play_tool_sound(src) + tool.play_tool_sound(src) balloon_alert(user, "cables removed") state = SCREWED_CORE update_appearance() new /obj/item/stack/cable_coil(drop_location(), 5) return - if(istype(P, /obj/item/stack/sheet/rglass)) + if(istype(tool, /obj/item/stack/sheet/rglass)) if(!core_mmi) balloon_alert(user, "add a brain first!") return - var/obj/item/stack/sheet/rglass/G = P + var/obj/item/stack/sheet/rglass/G = tool if(G.get_amount() >= 2) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "adding glass panel...") @@ -249,7 +249,7 @@ balloon_alert(user, "need two sheets of reinforced glass!") return - if(istype(P, /obj/item/ai_module)) + if(istype(tool, /obj/item/ai_module)) if(!core_mmi) balloon_alert(user, "no brain installed!") return @@ -259,12 +259,12 @@ if(core_mmi.laws.id != DEFAULT_AI_LAWID) balloon_alert(user, "[AI_CORE_BRAIN(core_mmi)] already has set laws!") return - var/obj/item/ai_module/module = P + var/obj/item/ai_module/module = tool module.install(laws, user) return - if(istype(P, /obj/item/mmi) && !core_mmi) - var/obj/item/mmi/M = P + if(istype(tool, /obj/item/mmi) && !core_mmi) + var/obj/item/mmi/M = tool if(!M.brain_check(user)) var/install = tgui_alert(user, "This [AI_CORE_BRAIN(M)] is inactive, would you like to make an inactive AI?", "Installing AI [AI_CORE_BRAIN(M)]", list("Yes", "No")) if(install != "Yes") @@ -292,40 +292,42 @@ update_appearance() return - if(P.tool_behaviour == TOOL_CROWBAR && core_mmi) - P.play_tool_sound(src) + if(tool.tool_behaviour == TOOL_CROWBAR && core_mmi) + tool.play_tool_sound(src) balloon_alert(user, "removed [AI_CORE_BRAIN(core_mmi)]") core_mmi.forceMove(loc) return if(GLASS_CORE) - if(P.tool_behaviour == TOOL_CROWBAR) - P.play_tool_sound(src) + if(tool.tool_behaviour == TOOL_CROWBAR) + tool.play_tool_sound(src) balloon_alert(user, "removed glass panel") state = CABLED_CORE update_appearance() new /obj/item/stack/sheet/rglass(loc, 2) return - if(P.tool_behaviour == TOOL_SCREWDRIVER) + if(tool.tool_behaviour == TOOL_SCREWDRIVER) if(suicide_check()) to_chat(user, span_warning("The brain installed is completely useless.")) return - P.play_tool_sound(src) - balloon_alert(user, "connected monitor[core_mmi?.brainmob?.mind ? " and neural network" : ""]") + tool.play_tool_sound(src) + + var/atom/alert_source = src if(core_mmi.brainmob?.mind) - ai_structure_to_mob() + alert_source = ai_structure_to_mob() || alert_source else state = AI_READY_CORE update_appearance() + alert_source.balloon_alert(user, "connected monitor[core_mmi?.brainmob?.mind ? " and neural network" : ""]") return if(AI_READY_CORE) - if(istype(P, /obj/item/aicard)) + if(istype(tool, /obj/item/aicard)) return //handled by /obj/structure/ai_core/transfer_ai() - if(P.tool_behaviour == TOOL_WIRECUTTER) - P.play_tool_sound(src) + if(tool.tool_behaviour == TOOL_WIRECUTTER) + tool.play_tool_sound(src) balloon_alert(user, "disconnected monitor") state = GLASS_CORE update_appearance() @@ -354,11 +356,10 @@ if(core_mmi.force_replace_ai_name) ai_mob.fully_replace_character_name(ai_mob.name, core_mmi.replacement_ai_name()) - if(core_mmi.braintype == "Android") - ai_mob.posibrain_inside = TRUE + ai_mob.posibrain_inside = core_mmi.braintype == "Android" deadchat_broadcast(" has been brought online at [get_area_name(ai_mob, format_text = TRUE)].", span_name("[ai_mob]"), follow_target = ai_mob, message_type = DEADCHAT_ANNOUNCEMENT) qdel(src) - return TRUE + return ai_mob /obj/structure/ai_core/update_icon_state() switch(state) @@ -431,10 +432,7 @@ That prevents a few funky behaviors. to_chat(user, "[span_boldnotice("Transfer successful")]: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed.") card.AI = null AI.battery = circuit.battery - if(core_mmi && core_mmi.braintype == "Android") - AI.posibrain_inside = TRUE - else - AI.posibrain_inside = FALSE + AI.posibrain_inside = isnull(core_mmi) || core_mmi.braintype == "Android" qdel(src) else //If for some reason you use an empty card on an empty AI terminal. to_chat(user, span_alert("There is no AI loaded on this terminal.")) diff --git a/code/game/objects/structures/gym/punching_bag.dm b/code/game/objects/structures/gym/punching_bag.dm index 9219153d02619b..9c67bd89cfc09b 100644 --- a/code/game/objects/structures/gym/punching_bag.dm +++ b/code/game/objects/structures/gym/punching_bag.dm @@ -51,8 +51,9 @@ if(istype(boxing_gloves)) stamina_exhaustion = 2 + if(!iscarbon(user)) + return user.adjustStaminaLoss(stamina_exhaustion) - user.add_mood_event("exercise", /datum/mood_event/exercise) user.mind?.adjust_experience(/datum/skill/fitness, 0.1) user.apply_status_effect(/datum/status_effect/exercised) diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index 761db678b38334..a7426e2f465d19 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -1,6 +1,6 @@ #define WORKOUT_XP 5 -#define EXERCISE_STATUS_DURATION 20 SECONDS -#define SAFE_DRUNK_LEVEL 39 +#define EXERCISE_STATUS_DURATION 15 SECONDS +#define SAFE_DRUNK_LEVEL 39 /obj/structure/weightmachine name = "chest press machine" @@ -22,6 +22,9 @@ ///message when drunk user fails to use the machine var/drunk_message = "You try for a new record and pull through! Through a muscle that is." + // the total reps you can do before you hit stamcrit based on fitness level + var/static/list/total_workout_reps = list(3, 4, 4, 5, 6, 6, 7) + ///List of messages picked when using the machine. var/static/list/more_weight = list( "pushing it to the limit!", @@ -127,12 +130,12 @@ else user.balloon_alert(user, pick(finished_message)) - user.adjust_nutrition(-3) // feel the burn - user.add_mood_event("exercise", /datum/mood_event/exercise) + user.adjust_nutrition(-5) // feel the burn - // remember the real xp gain is from sleeping after working out - user.mind.adjust_experience(/datum/skill/fitness, WORKOUT_XP) - user.apply_status_effect(/datum/status_effect/exercised, EXERCISE_STATUS_DURATION) + if(iscarbon(user)) + // remember the real xp gain is from sleeping after working out + user.mind.adjust_experience(/datum/skill/fitness, WORKOUT_XP) + user.apply_status_effect(/datum/status_effect/exercised, EXERCISE_STATUS_DURATION) end_workout() @@ -141,6 +144,9 @@ STOP_PROCESSING(SSobj, src) icon_state = initial(icon_state) +/// roughly 8 seconds for 1 workout rep +#define WORKOUT_LENGTH 8 + /obj/structure/weightmachine/process(seconds_per_tick) if(!has_buckled_mobs()) end_workout() @@ -150,15 +156,22 @@ flick_overlay_view(workout, 0.8 SECONDS) flick("[base_icon_state]-u", src) var/mob/living/user = buckled_mobs[1] - animate(user, pixel_y = pixel_shift_y, time = 4) + animate(user, pixel_y = pixel_shift_y, time = WORKOUT_LENGTH * 0.5) playsound(user, 'sound/machines/creak.ogg', 60, TRUE) - animate(pixel_y = user.base_pixel_y, time = 4) - - var/stamina_exhaustion = 5 - (user.mind.get_skill_level(/datum/skill/fitness) * 0.5) + animate(pixel_y = user.base_pixel_y, time = WORKOUT_LENGTH * 0.5) + + if(!iscarbon(user) || isnull(user.mind)) + return TRUE + // the amount of workouts you can do before you hit stamcrit + var/workout_reps = total_workout_reps[user.mind.get_skill_level(/datum/skill/fitness)] + // total stamina drain of 1 workout calculated based on the workout length + var/stamina_exhaustion = FLOOR(user.maxHealth / workout_reps / WORKOUT_LENGTH, 0.1) user.adjustStaminaLoss(stamina_exhaustion * seconds_per_tick) return TRUE +#undef WORKOUT_LENGTH + /** * Weight lifter subtype */ diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm index 69b52953283f20..bc6cb750b219a1 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm @@ -65,7 +65,7 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) nightshift_allowed = FALSE bulb_colour = "#d6b6a6ff" brightness = 3 - fire_brightness = 2 + fire_brightness = 3.5 bulb_power = 0.5 /obj/machinery/light/very_dim/directional/north diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index ae8b786fbeff25..296ac44503d7ae 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -222,6 +222,33 @@ desc = "A red jacket with silver rank pips and body armor strapped on top." icon_state = "warden_jacket" +/obj/item/clothing/suit/armor/vest/secjacket + name = "security jacket" + desc = "A red jacket in red Security colors. It has hi-vis stripes all over it." + icon_state = "secjacket" + inhand_icon_state = "armor" + armor_type = /datum/armor/armor_secjacket + body_parts_covered = CHEST|GROIN|ARMS + cold_protection = CHEST|GROIN|ARMS|HANDS + heat_protection = CHEST|GROIN|ARMS|HANDS + resistance_flags = FLAMMABLE + dog_fashion = null + +/obj/item/clothing/suit/armor/vest/secjacket/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(!isinhands) + . += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha) + +/datum/armor/armor_secjacket //Gotta compensate those extra covered limbs + melee = 25 + bullet = 25 + laser = 25 + energy = 35 + bomb = 20 + fire = 30 + acid = 30 + wound = 5 + /obj/item/clothing/suit/armor/vest/leather name = "security overcoat" desc = "Lightly armored leather overcoat meant as casual wear for high-ranking officers. Bears the crest of Nanotrasen Security." diff --git a/code/modules/food_and_drinks/machinery/coffeemaker.dm b/code/modules/food_and_drinks/machinery/coffeemaker.dm index 424b7e401ccc4d..5f6ef410413e59 100644 --- a/code/modules/food_and_drinks/machinery/coffeemaker.dm +++ b/code/modules/food_and_drinks/machinery/coffeemaker.dm @@ -484,6 +484,7 @@ contents_tag = "coffee cartridge" open_status = FANCY_CONTAINER_ALWAYS_OPEN spawn_type = /obj/item/coffee_cartridge + spawn_count = 1 /obj/item/storage/fancy/coffee_cart_rack/Initialize(mapload) . = ..() diff --git a/code/modules/mining/equipment/miningradio.dm b/code/modules/mining/equipment/miningradio.dm index 559740599dbe40..c6fa3a34fc36ae 100644 --- a/code/modules/mining/equipment/miningradio.dm +++ b/code/modules/mining/equipment/miningradio.dm @@ -5,7 +5,6 @@ icon_state = "miningradio" desc = "A weather radio designed for use in inhospitable environments. Gives audible warnings when storms approach. Has access to cargo channel." freqlock = RADIO_FREQENCY_LOCKED - luminosity = 1 light_power = 1 light_range = 1.6 diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm index 39c4875b15fffd..bb8d77eb64b8d9 100644 --- a/code/modules/mob/living/basic/bots/bot_ai.dm +++ b/code/modules/mob/living/basic/bots/bot_ai.dm @@ -97,7 +97,7 @@ /datum/ai_planning_subtree/find_patrol_beacon/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/basic/bot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || !(bot_pawn.bot_mode_flags & BOT_MODE_AUTOPATROL) || bot_pawn.mode == BOT_SUMMON) + if(!(bot_pawn.bot_mode_flags & BOT_MODE_AUTOPATROL) || bot_pawn.mode == BOT_SUMMON) return if(controller.blackboard_key_exists(BB_BEACON_TARGET)) @@ -179,6 +179,8 @@ /datum/ai_behavior/travel_towards/bot_summon/finish_action(datum/ai_controller/controller, succeeded, target_key) var/mob/living/basic/bot/bot_pawn = controller.pawn + if(QDELETED(bot_pawn)) // pawn can be null at this point + return ..() bot_pawn.calling_ai_ref = null bot_pawn.update_bot_mode(new_mode = BOT_IDLE) return ..() @@ -188,7 +190,7 @@ /datum/ai_planning_subtree/salute_authority/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/basic/bot/bot_pawn = controller.pawn //we are criminals, dont salute the dirty pigs - if(QDELETED(bot_pawn) || bot_pawn.bot_access_flags & BOT_COVER_EMAGGED) + if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED) return if(controller.blackboard_key_exists(BB_SALUTE_TARGET)) controller.queue_behavior(/datum/ai_behavior/salute_authority, BB_SALUTE_TARGET, BB_SALUTE_MESSAGES) diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm index 5ca7cdae3a6f92..9d1367ee07595d 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm @@ -41,7 +41,7 @@ /datum/ai_planning_subtree/pet_planning/cleanbot/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick) var/mob/living/basic/bot/bot_pawn = controller.pawn //we are DONE listening to orders - if(QDELETED(bot_pawn) || bot_pawn.bot_access_flags & BOT_COVER_EMAGGED) + if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED) return return ..() @@ -51,7 +51,7 @@ /datum/ai_planning_subtree/cleaning_subtree/SelectBehaviors(datum/ai_controller/basic_controller/bot/cleanbot/controller, seconds_per_tick) var/mob/living/basic/bot/cleanbot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || LAZYLEN(bot_pawn.do_afters)) + if(LAZYLEN(bot_pawn.do_afters)) return SUBTREE_RETURN_FINISH_PLANNING if(controller.reachable_key(BB_CLEAN_TARGET, BOT_CLEAN_PATH_LIMIT)) @@ -84,7 +84,7 @@ /datum/ai_planning_subtree/acid_spray/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick) var/mob/living/basic/bot/cleanbot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || !(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)) + if(!(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)) return if(controller.reachable_key(BB_ACID_SPRAY_TARGET, BOT_CLEAN_PATH_LIMIT)) controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_ACID_SPRAY_TARGET) @@ -140,6 +140,9 @@ if(!length(speech_list)) return var/mob/living/living_pawn = controller.pawn + if(QDELETED(living_pawn)) // pawn can be null at this point + controller.clear_blackboard_key(target_key) + return living_pawn.say(pick(controller.blackboard[BB_CLEANBOT_EMAGGED_PHRASES]), forced = "ai controller") controller.clear_blackboard_key(target_key) @@ -149,7 +152,7 @@ /datum/ai_planning_subtree/use_mob_ability/foam_area/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick) var/mob/living/basic/bot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || !(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)) + if(!(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)) return return ..() @@ -158,7 +161,7 @@ /datum/ai_planning_subtree/befriend_janitors/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick) var/mob/living/basic/bot/bot_pawn = controller.pawn //we are now evil. dont befriend the janitors - if((bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)) + if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED) return if(controller.blackboard_key_exists(BB_FRIENDLY_JANITOR)) controller.queue_behavior(/datum/ai_behavior/befriend_target, BB_FRIENDLY_JANITOR, BB_FRIENDLY_MESSAGE) diff --git a/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm b/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm index 4c31567f9e00e4..54315deda72e48 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm @@ -23,7 +23,7 @@ /datum/ai_movement/jps/bot/medbot/allowed_to_move(datum/move_loop/source) var/datum/ai_controller/controller = source.extra_info var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || bot_pawn.medical_mode_flags & MEDBOT_STATIONARY_MODE) + if(bot_pawn.medical_mode_flags & MEDBOT_STATIONARY_MODE) return FALSE return ..() @@ -32,7 +32,7 @@ /datum/ai_planning_subtree/treat_wounded_target/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick) var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || bot_pawn.medical_mode_flags & MEDBOT_TIPPED_MODE) + if(bot_pawn.medical_mode_flags & MEDBOT_TIPPED_MODE) controller.clear_blackboard_key(BB_PATIENT_TARGET) return var/reach_distance = (bot_pawn.medical_mode_flags & MEDBOT_STATIONARY_MODE) ? 1 : BOT_PATIENT_PATH_LIMIT @@ -69,7 +69,7 @@ /datum/ai_behavior/find_suitable_patient/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() - if(!succeeded || get_dist(controller.pawn, controller.blackboard[target_key]) <= 1) + if(!succeeded || QDELETED(controller.pawn) ||get_dist(controller.pawn, controller.blackboard[target_key]) <= 1) return var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY] announcement?.announce(pick(controller.blackboard[BB_WAIT_SPEECH])) @@ -98,8 +98,7 @@ if(patient.stat >= HARD_CRIT && prob(5)) var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY] announcement?.announce(pick(controller.blackboard[BB_NEAR_DEATH_SPEECH])) - if(!QDELETED(bot_pawn)) - bot_pawn.melee_attack(patient) + bot_pawn.melee_attack(patient) finish_action(controller, TRUE, target_key) // only clear the target if they get healed @@ -127,7 +126,7 @@ /datum/ai_planning_subtree/handle_medbot_speech/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn //we cant speak! - if(QDELETED(bot_pawn) || !(bot_pawn.medical_mode_flags & MEDBOT_SPEAK_MODE)) + if(!(bot_pawn.medical_mode_flags & MEDBOT_SPEAK_MODE)) return var/currently_tipped = bot_pawn.medical_mode_flags & MEDBOT_TIPPED_MODE @@ -174,7 +173,7 @@ /datum/ai_planning_subtree/find_and_hunt_target/patients_in_crit/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick) var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn - if(QDELETED(bot_pawn) || !(bot_pawn.medical_mode_flags & MEDBOT_DECLARE_CRIT)) + if(!(bot_pawn.medical_mode_flags & MEDBOT_DECLARE_CRIT)) return return ..() diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index 6c677e284dccbb..1a713ec04f8846 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -112,7 +112,12 @@ var/static/list/injection_range if(!injection_range) injection_range = string_numbers_list(list(1, 5)) - AddElement(/datum/element/venomous, /datum/reagent/consumable/laughter, injection_range) + AddElement(\ + /datum/element/venomous,\ + /datum/reagent/consumable/laughter,\ + injection_range,\ + injection_flags = INJECT_CHECK_PENETRATE_THICK | INJECT_CHECK_IGNORE_SPECIES,\ + ) /mob/living/basic/clown/fleshclown name = "Fleshclown" @@ -288,7 +293,12 @@ var/static/list/injection_range if(!injection_range) injection_range = string_numbers_list(list(1, 5)) - AddElement(/datum/element/venomous, /datum/reagent/peaceborg/confuse, injection_range) + AddElement(\ + /datum/element/venomous,\ + /datum/reagent/peaceborg/confuse,\ + injection_range,\ + injection_flags = INJECT_CHECK_PENETRATE_THICK | INJECT_CHECK_IGNORE_SPECIES,\ + ) // I don't really know what a clown is using to inject people but let's assume it doesn't need to penetrate at all /mob/living/basic/clown/clownhulk/destroyer name = "The Destroyer" diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm index dfaff9f4efc414..66c0d12996299b 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm @@ -192,11 +192,11 @@ if(!injection_range) injection_range = string_numbers_list(list(1, 5)) if(beegent) //clear the old since this one is going to have some new value - RemoveElement(/datum/element/venomous, beegent.type, injection_range) + RemoveElement(/datum/element/venomous, beegent.type, injection_range, thrown_effect = TRUE) beegent = toxin name = "[initial(name)] ([toxin.name])" real_name = name - AddElement(/datum/element/venomous, beegent.type, injection_range) + AddElement(/datum/element/venomous, beegent.type, injection_range, thrown_effect = TRUE) generate_bee_visuals() /mob/living/basic/bee/queen diff --git a/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm b/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm index f499859e19e911..b3af3c59a12b24 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm @@ -24,7 +24,7 @@ /mob/living/basic/cow/moonicorn/Initialize(mapload) . = ..() - AddElement(/datum/element/venomous, /datum/reagent/pax, 5) + AddElement(/datum/element/venomous, /datum/reagent/pax, 5, injection_flags = INJECT_CHECK_PENETRATE_THICK | INJECT_CHECK_IGNORE_SPECIES) AddElement(/datum/element/movement_turf_changer, /turf/open/floor/grass/fairy) /mob/living/basic/cow/moonicorn/udder_component() diff --git a/code/modules/mob/living/basic/heretic/fire_shark.dm b/code/modules/mob/living/basic/heretic/fire_shark.dm index e1eba1008458a4..c4106050bc26e1 100644 --- a/code/modules/mob/living/basic/heretic/fire_shark.dm +++ b/code/modules/mob/living/basic/heretic/fire_shark.dm @@ -26,7 +26,7 @@ . = ..() AddElement(/datum/element/death_gases, /datum/gas/plasma, 40) AddElement(/datum/element/simple_flying) - AddElement(/datum/element/venomous, /datum/reagent/phlogiston, 2) + AddElement(/datum/element/venomous, /datum/reagent/phlogiston, 2, injection_flags = INJECT_CHECK_PENETRATE_THICK) AddComponent(/datum/component/swarming) AddComponent(/datum/component/regenerator, outline_colour = COLOR_DARK_RED) ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm index fe209387e008b0..0012aff294d40b 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm @@ -25,11 +25,11 @@ /datum/ai_behavior/move_to_cardinal/brimdemon/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() - if (!succeeded) + if(!succeeded) return var/mob/living/target = controller.blackboard[target_key] var/datum/action/cooldown/ability = controller.blackboard[BB_TARGETED_ACTION] - if(!ability?.IsAvailable()) + if(QDELETED(target) || QDELETED(controller.pawn) || !ability?.IsAvailable()) return ability.InterceptClickOn(caller = controller.pawn, target = target) diff --git a/code/modules/mob/living/basic/pets/cat/cat_ai.dm b/code/modules/mob/living/basic/pets/cat/cat_ai.dm index c3660d87f05969..6cd01eb54539f9 100644 --- a/code/modules/mob/living/basic/pets/cat/cat_ai.dm +++ b/code/modules/mob/living/basic/pets/cat/cat_ai.dm @@ -27,8 +27,6 @@ /datum/ai_planning_subtree/reside_in_home/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - if(QDELETED(living_pawn)) - return if(controller.blackboard_key_exists(BB_CAT_HOME)) controller.queue_behavior(/datum/ai_behavior/enter_cat_home, BB_CAT_HOME) @@ -75,7 +73,6 @@ . = ..() controller.clear_blackboard_key(target_key) - /datum/ai_planning_subtree/flee_target/from_flee_key/cat_struggle flee_behaviour = /datum/ai_behavior/run_away_from_target/cat_struggle @@ -88,7 +85,7 @@ /datum/ai_planning_subtree/territorial_struggle/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - if(QDELETED(living_pawn) || living_pawn.gender != MALE || !SPT_PROB(hostility_chance, seconds_per_tick)) + if(living_pawn.gender != MALE || !SPT_PROB(hostility_chance, seconds_per_tick)) return if(controller.blackboard_key_exists(BB_TRESSPASSER_TARGET)) controller.queue_behavior(/datum/ai_behavior/territorial_struggle, BB_TRESSPASSER_TARGET, BB_HOSTILE_MEOWS) @@ -167,8 +164,6 @@ /datum/ai_planning_subtree/find_and_hunt_target/hunt_mice/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - if(QDELETED(living_pawn)) - return var/list/items_we_carry = typecache_filter_list(living_pawn, controller.blackboard[BB_HUNTABLE_PREY]) if(length(items_we_carry)) return @@ -214,7 +209,7 @@ var/mob/living/living_pawn = controller.pawn var/atom/target = controller.blackboard[target_key] controller.clear_blackboard_key(target_key) - if(isnull(target)) + if(isnull(target) || QDELETED(living_pawn)) return var/manual_emote = "attempts to hunt [target]..." var/end_result = success ? "and succeeds!" : "but fails!" diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm index 9b7ecd4af1ddb1..8a0fe5e157d93f 100644 --- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm @@ -30,6 +30,8 @@ /datum/ai_behavior/travel_towards/and_drop/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() var/mob/living/living_mob = controller.pawn + if(QDELETED(living_mob)) // pawn can be null at this point + return var/obj/drop_item = locate(/obj/item) in (living_mob.contents - typecache_filter_list(living_mob.contents, controller.blackboard[BB_IGNORE_ITEMS])) drop_item?.forceMove(get_turf(living_mob)) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm index 847d123f767a57..ccc3ef92f6ea22 100644 --- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm @@ -8,9 +8,6 @@ /datum/ai_planning_subtree/perch_on_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - if(QDELETED(living_pawn)) - return - var/atom/buckled_to = living_pawn.buckled //do we have a current target or is chance to unbuckle has passed? then unbuckle! diff --git a/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm b/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm index c16831f74a25e3..80e1768c90ebab 100644 --- a/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm @@ -47,7 +47,7 @@ ADD_TRAIT(src, TRAIT_WEB_SURFER, INNATE_TRAIT) AddElement(/datum/element/cliff_walking) AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) - AddElement(/datum/element/venomous, /datum/reagent/toxin/hunterspider, 5) + AddElement(/datum/element/venomous, /datum/reagent/toxin/hunterspider, 5, injection_flags = INJECT_CHECK_PENETRATE_THICK) AddElement(/datum/element/web_walker, /datum/movespeed_modifier/fast_web) AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move) AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!") diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm index e7fbfa5c2ecf17..f05ea779763ca8 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm @@ -22,7 +22,7 @@ antag_type = /datum/antagonist/slaughter - /// Datum that stores the action for us to crawl around. + /// Which blood crawl do we give to the demon var/crawl_type = /datum/action/cooldown/spell/jaunt/bloodcrawl/slaughter_demon /// How long it takes for the alt-click slam attack to come off cooldown var/slam_cooldown_time = 45 SECONDS @@ -37,7 +37,7 @@ /mob/living/basic/demon/slaughter/Initialize(mapload) . = ..() - GRANT_ACTION(/datum/action/cooldown/spell/jaunt/bloodcrawl/slaughter_demon) + GRANT_ACTION(crawl_type) RegisterSignal(src, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attack)) RegisterSignals(src, list(COMSIG_MOB_ENTER_JAUNT, COMSIG_MOB_AFTER_EXIT_JAUNT), PROC_REF(on_crawl)) diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm index 16e4bae095f15f..71fd357fd98588 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm @@ -19,6 +19,7 @@ melee_damage_upper = 25 gold_core_spawnable = HOSTILE_SPAWN ai_controller = /datum/ai_controller/basic_controller/giant_spider + bite_injection_flags = INJECT_CHECK_PENETRATE_THICK /// Actions to grant on Initialize var/list/innate_actions = null diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider.dm b/code/modules/mob/living/basic/space_fauna/spider/spider.dm index 6cd6275c10d1c0..b9938631ec5d57 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider.dm @@ -36,6 +36,8 @@ var/poison_type = /datum/reagent/toxin/hunterspider /// How much of a reagent the mob injects on attack var/poison_per_bite = 0 + /// How tough is our bite? + var/bite_injection_flags = NONE /// Multiplier to apply to web laying speed. Fractional numbers make it faster, because it's a multiplier. var/web_speed = 1 /// Type of webbing ability to learn. @@ -57,7 +59,7 @@ AddComponent(/datum/component/health_scaling_effects, min_health_slowdown = 1.5) if(poison_per_bite) - AddElement(/datum/element/venomous, poison_type, poison_per_bite) + AddElement(/datum/element/venomous, poison_type, poison_per_bite, injection_flags = bite_injection_flags) var/datum/action/cooldown/mob_cooldown/lay_web/webbing = new web_type(src) webbing.webbing_time *= web_speed diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 9092deee8e4407..d07ca87c75f0b3 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -801,7 +801,6 @@ if(hud_used?.spacesuit) hud_used.spacesuit.icon_state = "spacesuit_[cell_state]" - /mob/living/carbon/set_health(new_value) . = ..() if(. > hardcrit_threshold) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 0eb3945af8cdf7..ace31751c5dd62 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -486,18 +486,25 @@ //SKYRAT EDIT ADDITION BEGIN - EMOTES -- SENSITIVE SNOUT TRAIT ADDITION else if(helper.zone_selected == BODY_ZONE_PRECISE_MOUTH) nosound = TRUE - playsound(src, 'modular_skyrat/modules/emotes/sound/emotes/Nose_boop.ogg', 50, 0) - if(HAS_TRAIT(src, TRAIT_SENSITIVESNOUT) && get_location_accessible(src, BODY_ZONE_PRECISE_MOUTH)) - to_chat(src, span_warning("[helper] boops you on your sensitive nose, sending you to the ground!")) - src.Knockdown(20) - src.apply_damage(30, STAMINA) - helper.visible_message(span_notice("[helper] boops [src]'s nose."), span_notice("You boop [src] on the nose.")) + if(HAS_TRAIT(src, TRAIT_QUICKREFLEXES) && (src.stat != UNCONSCIOUS) && src.incapacitated(IGNORE_RESTRAINTS)) + visible_message(span_warning("[helper] tries to boop [src] on the nose, but [p_they()] move[p_s()] out of the way.")) + return + else + playsound(src, 'modular_skyrat/modules/emotes/sound/emotes/Nose_boop.ogg', 50, 0) + if(HAS_TRAIT(src, TRAIT_SENSITIVESNOUT) && get_location_accessible(src, BODY_ZONE_PRECISE_MOUTH)) + to_chat(src, span_warning("[helper] boops you on your sensitive nose, sending you to the ground!")) + src.Knockdown(20) + src.apply_damage(30, STAMINA) + helper.visible_message(span_notice("[helper] boops [src]'s nose."), span_notice("You boop [src] on the nose.")) //SKYRAT EDIT ADDITION END else if(check_zone(helper.zone_selected) == BODY_ZONE_HEAD && get_bodypart(BODY_ZONE_HEAD)) //Headpats! - //SKYRAT EDIT ADDITION BEGIN - OVERSIZED HEADPATS + //SKYRAT EDIT ADDITION BEGIN - OVERSIZED & DISALLOWED HEADPATS if(HAS_TRAIT(src, TRAIT_OVERSIZED) && !HAS_TRAIT(helper, TRAIT_OVERSIZED)) visible_message(span_warning("[helper] tries to pat [src] on the head, but can't reach!")) return + else if(HAS_TRAIT(src, TRAIT_QUICKREFLEXES) && (src.stat != UNCONSCIOUS) && !src.incapacitated(IGNORE_RESTRAINTS)) + visible_message(span_warning("[helper] tries to pat [src] on the head, but [p_they()] move[p_s()] out of the way.")) + return //SKYRAT EDIT ADDITION END helper.visible_message(span_notice("[helper] gives [src] a pat on the head to make [p_them()] feel better!"), \ null, span_hear("You hear a soft patter."), DEFAULT_MESSAGE_RANGE, list(helper, src)) @@ -541,6 +548,11 @@ to_chat(helper, span_notice("You wrap [src] into a tight bear hug!")) to_chat(src, span_notice("[helper] squeezes you super tightly in a firm bear hug!")) else + // SKYRAT EDIT ADDITION START + if (HAS_TRAIT(src, TRAIT_QUICKREFLEXES) && (src.stat != UNCONSCIOUS) && !src.incapacitated(IGNORE_RESTRAINTS)) + visible_message(span_warning("[helper] tries to hug [src], but [p_they()] move[p_s()] out of the way.")) + return + // SKYRAT EDIT ADDITION END helper.visible_message(span_notice("[helper] hugs [src] to make [p_them()] feel better!"), \ null, span_hear("You hear the rustling of clothes."), DEFAULT_MESSAGE_RANGE, list(helper, src)) to_chat(helper, span_notice("You hug [src] to make [p_them()] feel better!")) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 8d2ef6ce97c399..ac65691efd33ec 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -936,12 +936,19 @@ return var/carrydelay = 5 SECONDS //if you have latex you are faster at grabbing - var/skills_space = "" //cobby told me to do this + var/skills_space + var/fitness_level = mind.get_skill_level(/datum/skill/fitness) - 1 if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY)) - carrydelay = 3 SECONDS - skills_space = " very quickly" + carrydelay -= 2 SECONDS else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY)) - carrydelay = 4 SECONDS + carrydelay -= 1 SECONDS + + // can remove up to 2 seconds at legendary + carrydelay -= fitness_level * (1/3) SECONDS + + if(carrydelay <= 3 SECONDS) + skills_space = " very quickly" + else if(carrydelay <= 4 SECONDS) skills_space = " quickly" //SKYRAT EDIT ADDITION else if(HAS_TRAIT(target, TRAIT_OVERSIZED) && !HAS_TRAIT(src, TRAIT_OVERSIZED)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 5665fd0608bb68..f0122491a04277 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -106,7 +106,7 @@ var/atom/movable/screen/ai/modpc/interfaceButton ///whether its mmi is a posibrain or regular mmi when going ai mob to ai core structure - var/posibrain_inside = FALSE + var/posibrain_inside = TRUE ///whether its cover is opened, so you can wirecut it for deconstruction var/opened = FALSE ///whether AI is anchored or not, used for checks @@ -443,10 +443,9 @@ disconnect_shell() ShutOffDoomsdayDevice() var/obj/structure/ai_core/deactivated/ai_core = new(get_turf(src), /* skip_mmi_creation = */ TRUE) - if(!make_mmi_drop_and_transfer(ai_core.core_mmi, the_core = ai_core)) - return FALSE - qdel(src) - return TRUE + if(make_mmi_drop_and_transfer(ai_core.core_mmi, the_core = ai_core)) + qdel(src) + return ai_core /mob/living/silicon/ai/proc/make_mmi_drop_and_transfer(obj/item/mmi/the_mmi, the_core) var/mmi_type diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index 431d86f096c05d..da8411f7cb317a 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -147,8 +147,7 @@ user.electrocute_act(120, src) opened = FALSE return ITEM_INTERACT_SUCCESS - balloon_alert(user, "disconnected neural network") to_chat(src, span_danger("You feel incredibly confused and disorientated.")) - if(!ai_mob_to_structure()) - return ITEM_INTERACT_SUCCESS + var/atom/ai_structure = ai_mob_to_structure() + ai_structure.balloon_alert(user, "disconnected neural network") return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 4b870fdf474258..249cef26d5bc64 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -70,7 +70,11 @@ visible_message(span_danger("[user] punches [src], but doesn't leave a dent!"), \ span_warning("[user] punches you, but doesn't leave a dent!"), null, COMBAT_MESSAGE_RANGE, user) to_chat(user, span_danger("You punch [src], but don't leave a dent!")) - else + else // SKYRAT EDIT ADDITION START + if(HAS_TRAIT(src, TRAIT_QUICKREFLEXES) && (src.stat != UNCONSCIOUS) && !src.incapacitated(IGNORE_RESTRAINTS)) + visible_message(span_warning("[user] tries to pet [src], but it moves out of the way.")) + return + // SKYRAT EDIT ADDITION END visible_message(span_notice("[user] pets [src]."), \ span_notice("[user] pets you."), null, null, user) to_chat(user, span_notice("You pet [src].")) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 907eb0dfca918a..7ef55e8357c211 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -135,7 +135,7 @@ build_step++ if(ASSEMBLY_FIFTH_STEP) - if(istype(W, /obj/item/clothing/head/helmet)) + if(istype(W, /obj/item/clothing/head/helmet/sec)) if(!user.temporarilyRemoveItemFromInventory(W)) return to_chat(user, span_notice("You add [W] to [src].")) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index dc080a225358c9..7726d30dc18c9f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1385,10 +1385,6 @@ to_chat(src, span_warning("You can't write with the [writing_instrument]!")) return FALSE - if(HAS_MIND_TRAIT(src, TRAIT_MIMING) && !istype(writing_instrument, /obj/item/toy/crayon/mime)) - to_chat(src, span_warning("Your vow of silence is preventing you from talking with text.")) - return FALSE - if(!is_literate()) to_chat(src, span_warning("You try to write, but don't know how to spell anything!")) return FALSE diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 5ed1e44b709879..f175dda0317611 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -218,7 +218,7 @@ /obj/item/mod/module/weapon_recall/proc/set_weapon(obj/item/weapon) linked_weapon = weapon - RegisterSignal(linked_weapon, COMSIG_MOVABLE_IMPACT, PROC_REF(catch_weapon)) + RegisterSignal(linked_weapon, COMSIG_MOVABLE_PRE_IMPACT, PROC_REF(catch_weapon)) RegisterSignal(linked_weapon, COMSIG_QDELETING, PROC_REF(deleted_weapon)) /obj/item/mod/module/weapon_recall/proc/recall_weapon(caught = FALSE) diff --git a/code/modules/pai/hud.dm b/code/modules/pai/hud.dm index 523d57d17b31c1..1a71b5235b610c 100644 --- a/code/modules/pai/hud.dm +++ b/code/modules/pai/hud.dm @@ -94,6 +94,7 @@ if(LAZYACCESS(modifiers, RIGHT_CLICK)) pAI.host_scan(PAI_SCAN_MASTER) return TRUE + /atom/movable/screen/pai/crew_manifest name = "Crew Manifest" icon_state = "manifest" diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm index da7684794bba17..832718f0b177ab 100644 --- a/code/modules/pai/pai.dm +++ b/code/modules/pai/pai.dm @@ -71,8 +71,6 @@ // Onboard Items /// Atmospheric analyzer var/obj/item/analyzer/atmos_analyzer - /// Health analyzer - var/obj/item/healthanalyzer/host_scan /// GPS var/obj/item/gps/pai/internal_gps /// Music Synthesizer @@ -153,7 +151,6 @@ /mob/living/silicon/pai/Destroy() QDEL_NULL(atmos_analyzer) QDEL_NULL(hacking_cable) - QDEL_NULL(host_scan) QDEL_NULL(instrument) QDEL_NULL(internal_gps) QDEL_NULL(newscaster) @@ -185,8 +182,6 @@ atmos_analyzer = null else if(gone == aicamera) aicamera = null - else if(gone == host_scan) - host_scan = null else if(gone == internal_gps) internal_gps = null else if(gone == instrument) diff --git a/code/modules/pai/software.dm b/code/modules/pai/software.dm index 103056a5535b3a..9876df5a2646ae 100644 --- a/code/modules/pai/software.dm +++ b/code/modules/pai/software.dm @@ -38,7 +38,7 @@ return TRUE // Software related ui actions if(available_software[action] && !installed_software.Find(action)) - balloon_alert(usr, "software unavailable") + balloon_alert(ui.user, "software unavailable!") return FALSE switch(action) if("Atmospheric Sensor") @@ -116,8 +116,6 @@ atmos_analyzer = new(src) if("Digital Messenger") create_modularInterface() - if("Host Scan") - host_scan = new(src) if("Internal GPS") internal_gps = new(src) if("Music Synthesizer") @@ -193,28 +191,27 @@ * @returns {boolean} - TRUE if the scan was successful, FALSE otherwise. */ /mob/living/silicon/pai/proc/host_scan(mode) - if(isnull(mode)) - return FALSE - if(mode == PAI_SCAN_TARGET) - var/mob/living/target = get_holder() - if(!target || !isliving(target)) - balloon_alert(src, "not being carried") - return FALSE - host_scan.attack(target, src) - return TRUE - if(mode == PAI_SCAN_MASTER) - if(!master_ref) - balloon_alert(src, "no master detected") - return FALSE - var/mob/living/resolved_master = find_master() - if(!resolved_master) - balloon_alert(src, "cannot locate master") - return FALSE - if(!is_valid_z_level(get_turf(src), get_turf(resolved_master))) - balloon_alert(src, "master out of range") - return FALSE - host_scan.attack(resolved_master, src) - return TRUE + switch(mode) + if(PAI_SCAN_TARGET) + var/mob/living/target = get_holder() + if(!isliving(target)) + balloon_alert(src, "not being carried!") + return FALSE + healthscan(src, target) + return TRUE + + if(PAI_SCAN_MASTER) + var/mob/living/resolved_master = find_master() + if(isnull(resolved_master)) + balloon_alert(src, "no master detected!") + return FALSE + if(!is_valid_z_level(get_turf(src), get_turf(resolved_master))) + balloon_alert(src, "master out of range!") + return FALSE + healthscan(src, resolved_master) + return TRUE + + stack_trace("Invalid mode passed to host scan: [mode || "null"]") return FALSE /** diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 22a013b463e8c9..8559ae9fb5ad1b 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -73,7 +73,9 @@ ///The minimum value for the light's power in low power mode var/bulb_low_power_pow_min = 0.5 ///The Light range to use when working in fire alarm status - var/fire_brightness = 4 + var/fire_brightness = 9 + ///The Light power to use when working in fire alarm status + var/fire_power = 0.5 ///The Light colour to use when working in fire alarm status var/fire_colour = COLOR_FIRE_LIGHT_RED @@ -230,6 +232,7 @@ var/area/local_area = get_room_area() if (local_area?.fire) color_set = fire_colour + power_set = fire_power brightness_set = fire_brightness else if (nightshift_enabled) brightness_set = nightshift_brightness @@ -748,7 +751,7 @@ light_type = /obj/item/light/bulb fitting = "bulb" nightshift_brightness = 3 - fire_brightness = 2 + fire_brightness = 4.5 /obj/machinery/light/floor/get_light_offset() return list(0, 0) diff --git a/code/modules/power/lighting/light_mapping_helpers.dm b/code/modules/power/lighting/light_mapping_helpers.dm index a2171c8897c89b..db11c77fbefb3b 100644 --- a/code/modules/power/lighting/light_mapping_helpers.dm +++ b/code/modules/power/lighting/light_mapping_helpers.dm @@ -39,7 +39,7 @@ /obj/machinery/light/red/dim brightness = 4 bulb_power = 0.7 - fire_brightness = 2 + fire_brightness = 4.5 /obj/machinery/light/blacklight bulb_colour = "#A700FF" @@ -58,7 +58,7 @@ fitting = "bulb" brightness = 4 nightshift_brightness = 4 - fire_brightness = 3 + fire_brightness = 4.5 bulb_colour = "#FFD6AA" fire_colour = "#bd3f46" desc = "A small lighting fixture." @@ -85,13 +85,13 @@ /obj/machinery/light/small/red/dim brightness = 2 bulb_power = 0.8 - fire_brightness = 2 + fire_brightness = 2.5 /obj/machinery/light/small/blacklight bulb_colour = "#A700FF" nightshift_allowed = FALSE brightness = 4 - fire_brightness = 3 + fire_brightness = 4.5 fire_colour = "#d400ff" // -------- Directional presets diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index 2ebb6a884c039f..793b4a2b2bf4c9 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -98,6 +98,8 @@ ph = 8.2 taste_description = "bitter with a hint of alcohol" reagent_state = SOLID + inverse_chem_val = 0.3 + inverse_chem = /datum/reagent/inverse/libitoil chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/medicine/c2/libital/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) @@ -161,13 +163,16 @@ /*Suffix: -uri*/ /datum/reagent/medicine/c2/lenturi name = "Lenturi" - description = "Used to treat burns. Makes you move slower while it is in your system. Applies stomach damage when it leaves your system." + description = "Used to treat burns. Applies stomach damage when it leaves your system." reagent_state = LIQUID color = "#6171FF" ph = 4.7 var/resetting_probability = 0 //What are these for?? Can I remove them? var/spammer = 0 chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + inverse_chem_val = 0.4 + inverse_chem = /datum/reagent/inverse/lentslurri + /datum/reagent/medicine/c2/lenturi/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() @@ -186,6 +191,8 @@ var/resetting_probability = 0 //same with this? Old legacy vars that should be removed? var/message_cd = 0 chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + inverse_chem_val = 0.35 + inverse_chem = /datum/reagent/inverse/aiuri /datum/reagent/medicine/c2/aiuri/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents.dm index 9db1d223f8e4ac..59baceab5579ff 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents.dm @@ -60,13 +60,14 @@ // Unique -/datum/reagent/impurity/eigenswap +/datum/reagent/inverse/eigenswap name = "Eigenswap" description = "This reagent is known to swap the handedness of a patient." ph = 3.3 chemical_flags = REAGENT_DONOTSPLIT + tox_damage = 0 -/datum/reagent/impurity/eigenswap/on_mob_life(mob/living/carbon/affected_mob) +/datum/reagent/inverse/eigenswap/on_mob_life(mob/living/carbon/affected_mob) . = ..() if(!prob(creation_purity * 100)) return diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm index 8fd6559c39a863..fa871013ad9496 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm @@ -131,17 +131,21 @@ Basically, we fill the time between now and 2s from now with hands based off the tox_damage = 0 //libital -//Impure +//Inverse: //Simply reduces your alcohol tolerance, kinda simular to prohol -/datum/reagent/impurity/libitoil +/datum/reagent/inverse/libitoil name = "Libitoil" description = "Temporarilly interferes a patient's ability to process alcohol." chemical_flags = REAGENT_DONOTSPLIT ph = 13.5 - liver_damage = 0.1 addiction_types = list(/datum/addiction/medicine = 4) + tox_damage = 0 -/datum/reagent/impurity/libitoil/on_mob_add(mob/living/affected_mob, amount) +/datum/reagent/inverse/libitoil/on_mob_life(mob/living/carbon/affected_mob, delta_time, times_fired) + . = ..() + affected_mob.adjustOrganLoss(ORGAN_SLOT_LIVER, 0.1 * REM * delta_time) + +/datum/reagent/inverse/libitoil/on_mob_add(mob/living/affected_mob, amount) . = ..() var/mob/living/carbon/consumer = affected_mob if(!consumer) @@ -151,21 +155,21 @@ Basically, we fill the time between now and 2s from now with hands based off the var/obj/item/organ/internal/liver/this_liver = consumer.get_organ_slot(ORGAN_SLOT_LIVER) this_liver.alcohol_tolerance *= 2 -/datum/reagent/impurity/libitoil/proc/on_gained_organ(mob/prev_owner, obj/item/organ/organ) +/datum/reagent/inverse/libitoil/proc/on_gained_organ(mob/prev_owner, obj/item/organ/organ) SIGNAL_HANDLER if(!istype(organ, /obj/item/organ/internal/liver)) return var/obj/item/organ/internal/liver/this_liver = organ this_liver.alcohol_tolerance *= 2 -/datum/reagent/impurity/libitoil/proc/on_removed_organ(mob/prev_owner, obj/item/organ/organ) +/datum/reagent/inverse/libitoil/proc/on_removed_organ(mob/prev_owner, obj/item/organ/organ) SIGNAL_HANDLER if(!istype(organ, /obj/item/organ/internal/liver)) return var/obj/item/organ/internal/liver/this_liver = organ this_liver.alcohol_tolerance /= 2 -/datum/reagent/impurity/libitoil/on_mob_delete(mob/living/affected_mob) +/datum/reagent/inverse/libitoil/on_mob_delete(mob/living/affected_mob) . = ..() var/mob/living/carbon/consumer = affected_mob UnregisterSignal(consumer, COMSIG_CARBON_LOSE_ORGAN) @@ -205,18 +209,18 @@ Basically, we fill the time between now and 2s from now with hands based off the affected_mob.adjust_nutrition(-5 * REAGENTS_METABOLISM * seconds_per_tick) //Lenturi -//impure -/datum/reagent/impurity/lentslurri //Okay maybe I should outsource names for these +//inverse +/datum/reagent/inverse/lentslurri //Okay maybe I should outsource names for these name = "Lentslurri"//This is a really bad name please replace - description = "A highly addicitive muscle relaxant that is made when Lenturi reactions go wrong." + description = "A highly addicitive muscle relaxant that is made when Lenturi reactions go wrong, this will cause the patient to move slowly." addiction_types = list(/datum/addiction/medicine = 8) - liver_damage = 0 + tox_damage = 0 -/datum/reagent/impurity/lentslurri/on_mob_metabolize(mob/living/carbon/affected_mob) +/datum/reagent/inverse/lentslurri/on_mob_metabolize(mob/living/carbon/affected_mob) . = ..() affected_mob.add_movespeed_modifier(/datum/movespeed_modifier/reagent/lenturi) -/datum/reagent/impurity/lentslurri/on_mob_end_metabolize(mob/living/carbon/affected_mob) +/datum/reagent/inverse/lentslurri/on_mob_end_metabolize(mob/living/carbon/affected_mob) . = ..() affected_mob.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/lenturi) @@ -250,24 +254,21 @@ Basically, we fill the time between now and 2s from now with hands based off the resetting_probability += (5*((current_cycle-1)/10) * seconds_per_tick) // 10 iterations = >51% to itch //Aiuri -//impure -/datum/reagent/impurity/aiuri +//inverse +/datum/reagent/inverse/aiuri name = "Aivime" description = "This reagent is known to interfere with the eyesight of a patient." ph = 3.1 addiction_types = list(/datum/addiction/medicine = 1.5) - liver_damage = 0.1 - /// blurriness at the start of taking the med - var/amount_of_blur_applied = 0 SECONDS - -/datum/reagent/impurity/aiuri/on_mob_add(mob/living/affected_mob, amount) - . = ..() - amount_of_blur_applied = creation_purity * (volume / metabolization_rate) * 2 SECONDS - affected_mob.adjust_eye_blur(amount_of_blur_applied) + ///The amount of blur applied per second. Given the average on_life interval is 2 seconds, that'd be 2.5s. + var/amount_of_blur_applied = 1.25 SECONDS + tox_damage = 0 -/datum/reagent/impurity/aiuri/on_mob_delete(mob/living/affected_mob, amount) +/datum/reagent/inverse/aiuri/on_mob_life(mob/living/carbon/owner, delta_time, times_fired) + owner.adjustOrganLoss(ORGAN_SLOT_EYES, 0.1 * REM * delta_time) + owner.adjust_eye_blur(amount_of_blur_applied * delta_time) . = ..() - affected_mob.adjust_eye_blur(-amount_of_blur_applied) + return TRUE //Hercuri //inverse diff --git a/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm b/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm index 73dcf8aa60b482..1cb0e6204c2e7e 100644 --- a/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm +++ b/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm @@ -19,8 +19,8 @@ ph = 3.7 purity = 0.5 creation_purity = 0.5 - inverse_chem = /datum/reagent/impurity/eigenswap - inverse_chem_val = 0 + inverse_chem = /datum/reagent/inverse/eigenswap + inverse_chem_val = 0.1 chemical_flags = REAGENT_DEAD_PROCESS //So if you die with it in your body, you still get teleported back to the location as a corpse data = list("location_created" = null, "ingested" = FALSE)//So we retain the target location and creator between reagent instances ///The creation point assigned during the reaction diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index ddfa9e0688b7e2..123d81501fa97a 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -402,13 +402,6 @@ pressure_charging = TRUE update_appearance() -/obj/machinery/disposal/bin/update_appearance(updates) - . = ..() - if((machine_stat & (BROKEN|NOPOWER)) || panel_open) - luminosity = 0 - return - luminosity = 1 - /obj/machinery/disposal/bin/update_overlays() . = ..() if(machine_stat & BROKEN) diff --git a/code/modules/shuttle/shuttle_events/turbulence.dm b/code/modules/shuttle/shuttle_events/turbulence.dm new file mode 100644 index 00000000000000..bbc136397c2a02 --- /dev/null +++ b/code/modules/shuttle/shuttle_events/turbulence.dm @@ -0,0 +1,48 @@ +/// Repeat the "buckle in or fall over" event a couple times +/datum/shuttle_event/turbulence + name = "Turbulence" + event_probability = 5 + activation_fraction = 0.1 + /// Minimum time to wait between periods of turbulence + var/minimum_interval = 20 SECONDS + /// Maximum time to wait between periods of turbulence + var/maximum_interval = 50 SECONDS + /// Time until we should shake again + COOLDOWN_DECLARE(turbulence_cooldown) + /// How long do we give people to get buckled? + var/warning_interval = 2 SECONDS + +/datum/shuttle_event/turbulence/activate() + . = ..() + minor_announce("Please note, we are entering an area of subspace turbulence. For your own safety, \ + please fasten your belts and remain seated until the vehicle comes to a complete stop.", + title = "Emergency Shuttle", alert = TRUE) + COOLDOWN_START(src, turbulence_cooldown, rand(5 SECONDS, 20 SECONDS)) // Reduced interval after the announcement + +/datum/shuttle_event/turbulence/event_process() + . = ..() + if (!.) + return + if (!COOLDOWN_FINISHED(src, turbulence_cooldown)) + return + COOLDOWN_START(src, turbulence_cooldown, rand(minimum_interval, maximum_interval)) + shake() + addtimer(CALLBACK(src, PROC_REF(knock_down)), warning_interval, TIMER_DELETE_ME) + +/// Warn players to get buckled +/datum/shuttle_event/turbulence/proc/shake() + var/list/mobs = mobs_in_area_type(list(/area/shuttle/escape)) + for(var/mob/living/mob as anything in mobs) + var/shake_intensity = mob.buckled ? 0.25 : 1 + if(mob.client) + shake_camera(mob, 3 SECONDS, shake_intensity) + +/// Knock them down +/datum/shuttle_event/turbulence/proc/knock_down() + if (SSshuttle.emergency.mode != SHUTTLE_ESCAPE) + return // They docked + var/list/mobs = mobs_in_area_type(list(/area/shuttle/escape)) // Not very efficient but check again in case someone was outdoors + for(var/mob/living/mob as anything in mobs) + if(mob.buckled) + continue + mob.Paralyze(3 SECONDS, ignore_canstun = TRUE) diff --git a/code/modules/spells/spell_types/self/mime_vow.dm b/code/modules/spells/spell_types/self/mime_vow.dm index 444775e7ff4aa7..bd666786b9624b 100644 --- a/code/modules/spells/spell_types/self/mime_vow.dm +++ b/code/modules/spells/spell_types/self/mime_vow.dm @@ -1,6 +1,6 @@ /datum/action/cooldown/spell/vow_of_silence - name = "Speech" - desc = "Make (or break) a vow of silence." + name = "Break Vow" + desc = "Break your vow of silence. Permanently." background_icon_state = "bg_mime" overlay_icon_state = "bg_mime_border" button_icon = 'icons/mob/actions/actions_mime.dmi' @@ -8,7 +8,6 @@ panel = "Mime" school = SCHOOL_MIME - cooldown_time = 5 MINUTES spell_requirements = NONE spell_max_level = 1 @@ -20,18 +19,18 @@ /datum/action/cooldown/spell/vow_of_silence/Remove(mob/living/remove_from) . = ..() REMOVE_TRAIT(remove_from, TRAIT_MIMING, "[type]") - remove_from.clear_mood_event("vow") + +/datum/action/cooldown/spell/vow_of_silence/before_cast(atom/cast_on) + if(tgui_alert(usr, "Are you sure? There's no going back.", "Break Vow", list("I'm Sure", "Abort")) != "I'm Sure") + return SPELL_CANCEL_CAST + return ..() /datum/action/cooldown/spell/vow_of_silence/cast(mob/living/carbon/human/cast_on) . = ..() - if(HAS_TRAIT_FROM(cast_on, TRAIT_MIMING, "[type]")) - to_chat(cast_on, span_notice("You break your vow of silence.")) - cast_on.log_message("broke [cast_on.p_their()] vow of silence.", LOG_GAME) - cast_on.add_mood_event("vow", /datum/mood_event/broken_vow) - REMOVE_TRAIT(cast_on, TRAIT_MIMING, "[type]") - else - to_chat(cast_on, span_notice("You make a vow of silence.")) - cast_on.log_message("made a vow of silence.", LOG_GAME) - cast_on.clear_mood_event("vow") - ADD_TRAIT(cast_on, TRAIT_MIMING, "[type]") - cast_on.update_mob_action_buttons() + to_chat(cast_on, span_notice("You break your vow of silence.")) + cast_on.log_message("broke [cast_on.p_their()] vow of silence.", LOG_GAME) + cast_on.add_mood_event("vow", /datum/mood_event/broken_vow) + REMOVE_TRAIT(cast_on, TRAIT_MIMING, "[type]") + var/datum/job/mime/mime_job = SSjob.GetJob(JOB_MIME) + mime_job.total_positions += 1 + qdel(src) diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index 3fe5e15028813e..d97df1d043bc08 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -52,9 +52,8 @@ slot = ORGAN_SLOT_HEART_AID var/revive_cost = 0 var/reviving = FALSE - /// revival/defibrillation possibility flag that gathered from owner's .can_defib() proc - var/can_defib_owner COOLDOWN_DECLARE(reviver_cooldown) + COOLDOWN_DECLARE(defib_cooldown) /obj/item/organ/internal/cyberimp/chest/reviver/on_death(seconds_per_tick, times_fired) if(isnull(owner)) // owner can be null, on_death() gets called by /obj/item/organ/internal/process() for decay @@ -81,19 +80,13 @@ revive_cost = 0 reviving = TRUE to_chat(owner, span_notice("You feel a faint buzzing as your reviver implant starts patching your wounds...")) + COOLDOWN_START(src, defib_cooldown, 8 SECONDS) // 5 seconds after heal proc delay /obj/item/organ/internal/cyberimp/chest/reviver/proc/heal() - if(can_defib_owner == DEFIB_POSSIBLE) + if(COOLDOWN_FINISHED(src, defib_cooldown)) revive_dead() - can_defib_owner = null - revive_cost += 10 MINUTES // Additional 10 minutes cooldown after revival. - // this check goes after revive_dead() to delay revival a bit - if(owner.stat == DEAD) - can_defib_owner = owner.can_defib() - if(can_defib_owner == DEFIB_POSSIBLE) - owner.notify_revival("You are being revived by [src]!") - owner.grab_ghost() + /// boolean that stands for if PHYSICAL damage being patched var/body_damage_patched = FALSE var/need_mob_update = FALSE @@ -119,8 +112,14 @@ /obj/item/organ/internal/cyberimp/chest/reviver/proc/revive_dead() + if(!COOLDOWN_FINISHED(src, defib_cooldown) || owner.stat != DEAD || owner.can_defib() != DEFIB_POSSIBLE) + return + owner.notify_revival("You are being revived by [src]!") + revive_cost += 10 MINUTES // Additional 10 minutes cooldown after revival. owner.grab_ghost() + defib_cooldown += 16 SECONDS // delay so it doesn't spam + owner.visible_message(span_warning("[owner]'s body convulses a bit.")) playsound(owner, SFX_BODYFALL, 50, TRUE) playsound(owner, 'sound/machines/defib_zap.ogg', 75, TRUE, -1) diff --git a/code/modules/transport/elevator/elev_indicator.dm b/code/modules/transport/elevator/elev_indicator.dm index cf9fa46e96328d..9751b44e0ff124 100644 --- a/code/modules/transport/elevator/elev_indicator.dm +++ b/code/modules/transport/elevator/elev_indicator.dm @@ -17,7 +17,6 @@ light_range = 1 light_power = 1 light_color = COLOR_DISPLAY_BLUE - luminosity = 1 maptext_x = 18 maptext_y = 20 diff --git a/code/modules/transport/tram/tram_signals.dm b/code/modules/transport/tram/tram_signals.dm index 9983b32fe33121..53fcd97cffe38f 100644 --- a/code/modules/transport/tram/tram_signals.dm +++ b/code/modules/transport/tram/tram_signals.dm @@ -19,7 +19,6 @@ // pointless if it only takes 2 seconds to cross but updates every 2 seconds subsystem_type = /datum/controller/subsystem/processing/transport light_color = LIGHT_COLOR_BABY_BLUE - luminosity = 1 /// green, amber, or red for tram, blue if it's emag, tram missing, etc. var/signal_state = XING_STATE_MALF /// the sensor we use @@ -83,7 +82,6 @@ light_range = 1.5 light_power = 3 light_color = COLOR_VIBRANT_LIME - luminosity = 1 var/sign_dir = INBOUND /obj/machinery/static_signal/northwest diff --git a/code/modules/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm index 5afcd58c0c0ca6..ed9884a9ea3cbd 100644 --- a/code/modules/vehicles/vehicle_actions.dm +++ b/code/modules/vehicles/vehicle_actions.dm @@ -301,9 +301,11 @@ return COOLDOWN_START(src, thank_time_cooldown, 6 SECONDS) var/obj/vehicle/sealed/car/clowncar/clown_car = vehicle_entered_target - var/mob/living/carbon/human/clown = pick(clown_car.return_drivers()) - if(!clown) + var/list/mob/drivers = clown_car.return_drivers() + if(!length(drivers)) + to_chat(owner, span_danger("You prepare to thank the driver, only to realize that they don't exist.")) return + var/mob/clown = pick(drivers) owner.say("Thank you for the fun ride, [clown.name]!") clown_car.increment_thanks_counter() diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index e43314aa3076b3..2e138b12c2c710 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -24,6 +24,7 @@ /obj/item/clothing/under/rank/security/officer/grey = 3, /obj/item/clothing/under/pants/slacks = 3, /obj/item/clothing/under/rank/security/officer/blueshirt = 3, + /obj/item/clothing/suit/armor/vest/secjacket = 3, /obj/item/clothing/suit/hooded/wintercoat/security = 3, /obj/item/clothing/suit/armor/vest = 3, /obj/item/clothing/gloves/color/black = 3, diff --git a/html/changelogs/AutoChangeLog-pr-25388.yml b/html/changelogs/AutoChangeLog-pr-25388.yml deleted file mode 100644 index 3788362a4213e5..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25388.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Paxilmaniac" -delete-after: True -changes: - - rscdel: "Every gun from the gunsgalore module has been deleted, long live the king" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25512.yml b/html/changelogs/AutoChangeLog-pr-25512.yml deleted file mode 100644 index ccf2a5013ef5d6..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25512.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Paxilmaniac" -delete-after: True -changes: - - qol: "The lanca and miecz can be suppressed." - - qol: "Suppressors no longer increase the weight class of a gun they're attached to." - - image: "New sprites for lanca and miecz suppressors done by me." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25604.yml b/html/changelogs/AutoChangeLog-pr-25604.yml deleted file mode 100644 index 88887475aeaae2..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25604.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "yooriss" -delete-after: True -changes: - - bugfix: "Loadout MODlink scryers now come with the NT frequency by default, allowing them to actually be used without requiring complicated setup. Try them out again and holocall all your friends!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25647.yml b/html/changelogs/AutoChangeLog-pr-25647.yml deleted file mode 100644 index acf2b275ca3602..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25647.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Bitrunners can now access the Northstar ORM\n:cl:" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25648.yml b/html/changelogs/AutoChangeLog-pr-25648.yml deleted file mode 100644 index b304a8398becae..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25648.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "character setup screen no longer runtimes with all_nighter quirk" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25649.yml b/html/changelogs/AutoChangeLog-pr-25649.yml deleted file mode 100644 index d4f58112a188b9..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25649.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Thlumyn" -delete-after: True -changes: - - bugfix: "Contractor PDAs do not bluescreen any more." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25651.yml b/html/changelogs/AutoChangeLog-pr-25651.yml deleted file mode 100644 index b8a19573cf3e98..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25651.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - balance: "Exosuit Materials 1 now only requires one mech." - - qol: "Exosuit Materials 1 is much more lenient on the percentage it requires.\n/🆑" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25652.yml b/html/changelogs/AutoChangeLog-pr-25652.yml deleted file mode 100644 index a4b6cb5338c2e8..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25652.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Fixed a rare false positive with morgue tray alarms." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25653.yml b/html/changelogs/AutoChangeLog-pr-25653.yml deleted file mode 100644 index 2586a1598527e8..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25653.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "fixed the oversight with martian food complexity." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-25655.yml b/html/changelogs/AutoChangeLog-pr-25655.yml deleted file mode 100644 index 1827482458b27b..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-25655.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Motorized wheelchairs will no longer spawn in a bugged state where they have no parts and can't be upgraded." - - bugfix: "Motorized wheelchairs will drop their power cell when destroyed or deconstructed." - - qol: "Power cells are now inserted into motorized wheelchairs as part of the crafting recipe, instead of as an extra step afterwards." \ No newline at end of file diff --git a/html/changelogs/archive/2023-12.yml b/html/changelogs/archive/2023-12.yml index 957deb2721495b..90e7bd680ad5b1 100644 --- a/html/changelogs/archive/2023-12.yml +++ b/html/changelogs/archive/2023-12.yml @@ -548,3 +548,103 @@ thegrb93: - bugfix: Fix vox tails being unable to wag - bugfix: fixed lizard spine sprites disappearing when wagging +2023-12-17: + Paxilmaniac: + - rscdel: Every gun from the gunsgalore module has been deleted, long live the king + - qol: The lanca and miecz can be suppressed. + - qol: Suppressors no longer increase the weight class of a gun they're attached + to. + - image: New sprites for lanca and miecz suppressors done by me. + SkyratBot: + - bugfix: 'Bitrunners can now access the Northstar ORM + + :cl:' + - qol: Added a confirmation prompt to breaking your vow of silence. + - balance: Mimes can no longer repair the vow of silence once broken. + - balance: The negative moodlet from breaking your vow of silence is now lighter, + and no longer permanent. + - balance: Mimes are back to being able to write while under a vow of silence. + - bugfix: character setup screen no longer runtimes with all_nighter quirk + - bugfix: Motorized wheelchairs will no longer spawn in a bugged state where they + have no parts and can't be upgraded. + - bugfix: Motorized wheelchairs will drop their power cell when destroyed or deconstructed. + - qol: Power cells are now inserted into motorized wheelchairs as part of the crafting + recipe, instead of as an extra step afterwards. + - bugfix: Fixed a rare false positive with morgue tray alarms. + - bugfix: fixed the oversight with martian food complexity. + - balance: Exosuit Materials 1 now only requires one mech. + - qol: "Exosuit Materials 1 is much more lenient on the percentage it requires.\n\ + /\U0001F191" + Thlumyn: + - bugfix: Contractor PDAs do not bluescreen any more. + yooriss: + - bugfix: Loadout MODlink scryers now come with the NT frequency by default, allowing + them to actually be used without requiring complicated setup. Try them out again + and holocall all your friends! +2023-12-18: + KannaLisvern: + - qol: You can now LOOC while in crit/unconscious. + Melbert: + - bugfix: Fixes Laughter demons deleting the bodies of their friends. + - bugfix: Fixes PAI health scan software + Paxilmaniac: + - qol: deployable thermomachines no longer deploy in the direction you're facing, + meaning the pipe connection will be visually in the right location + SkyratBot: + - rscadd: Adds a new shuttle event, where space shuttles can experience minor turbulance. + Keep your belt on while the appropriate cabin light is lit. + - bugfix: 'Interview UI should now be more obvious how it works: You must press + "enter" or save the answer.' + - bugfix: Fixed runtime regarding thanking non-existent clown car drivers + - bugfix: ED-209s can no longer be crafted with most instances of helmet, you need + security ones just like Beepsky. + - code_imp: All nighters can now drink energy drinks to cope with their lack of + sleep. + - balance: Roundstart AIs are now made of positronic cubes, rather than brains inside + MMIs + - bugfix: Reviver no longer attempts to revive impossible to defib mobs. + - refactor: Cleaned up unnecessary variables and re-arraigned code to have it perform + altogether in one tick. Additionally added a proper cooldown to revivers. + - balance: Fitness level decreases the time it takes to firemany carry someone. + Fitness level determines how much of a positive mood the workout grants. Working + out is now more difficult and requires more nutrition. + - balance: Exercise no longer triggers double metabolism. + - bugfix: Aivime, Lentslurri, Eigenswap and Libitoil can now be cooked again. + - balance: Aivime now can stack blur effects for the soapiest game ever. + - spellcheck: Lenturri description become more actual + - bugfix: coffee cartridge racks start with a coffee cartridge in them + - bugfix: Fire alarms no longer cause pitch blackness, instead creating a dark but + not black red light. + - image: 'New Security clothing: Security High-Vis jacket!' + - bugfix: fixed ghost role descriptions on NTTS Independence + - bugfix: Fix search categories in log viewer + - rscadd: If you throw a bee at someone it will hit them sting-first and inject + that bee's reagent + - balance: Thick clothing can now protect you from the venom of bees, snakes, frogs, + and (small) spiders + Tattle: + - admin: obsession targets are logged + Thlumyn: + - bugfix: opfor panel works again + goobliner: + - rscadd: Adds a new verb in the IC tab, "toggle reflexes", which lets your toggle + being able to be head pat, nose bopped or hugged. Works for both people AND + robots. + jjpark-kb: + - rscadd: added the plant tank-- allows simple farm growing and production of nitrogen + and oxygen + - bugfix: simple farms will now destroy themselves if their parent atom is destroyed + yooriss: + - bugfix: Laser pointers now show appropriate messaging to nearby players when someone + is using them for both benign and hostile actions. + - bugfix: Due to budget cuts and petitioning from protesting silicons, the FTU has + replaced all full-power laser pointers available in crew loadouts and Good Clean + Fun vendors with limited promotional variants that can't have their diodes repaired + or upgraded on the field. Joint litigation by the NT research and service departments + has allowed the RD and lawyers to keep their original ones, however. + - bugfix: Extensive lobbying by the Felinid Rights Association has forced the FTU + to replace all laser pointer diodes with special low 'radiationyan' variants + that no longer trigger felinids to compulsively leap. They're still super distracting + though... + yorii: + - rscadd: added moth milk diff --git a/icons/mob/clothing/suits/armor.dmi b/icons/mob/clothing/suits/armor.dmi index dc5fae0172cc4a..8e5b492251eb90 100644 Binary files a/icons/mob/clothing/suits/armor.dmi and b/icons/mob/clothing/suits/armor.dmi differ diff --git a/icons/obj/clothing/suits/armor.dmi b/icons/obj/clothing/suits/armor.dmi index 4bf43e07e970c4..38fa25daa9dc30 100644 Binary files a/icons/obj/clothing/suits/armor.dmi and b/icons/obj/clothing/suits/armor.dmi differ diff --git a/modular_skyrat/master_files/code/game/objects/items/devices/laserpointer.dm b/modular_skyrat/master_files/code/game/objects/items/devices/laserpointer.dm new file mode 100644 index 00000000000000..d9ec81f7098744 --- /dev/null +++ b/modular_skyrat/master_files/code/game/objects/items/devices/laserpointer.dm @@ -0,0 +1,37 @@ +/obj/item/laser_pointer + //Whether the laser pointer is capable of receiving upgrades + var/upgradable = TRUE + +/obj/item/laser_pointer/limited + //limited laser pointers cannot receive upgrades, mostly used in loadout + upgradable = FALSE + +/obj/item/laser_pointer/limited/red + pointer_icon_state = "red_laser" + +/obj/item/laser_pointer/limited/green + pointer_icon_state = "green_laser" + +/obj/item/laser_pointer/limited/blue + pointer_icon_state = "blue_laser" + +/obj/item/laser_pointer/limited/purple + pointer_icon_state = "purple_laser" + +/obj/item/laser_pointer/screwdriver_act(mob/living/user, obj/item/tool) + if(!upgradable) + balloon_alert(user, "can't remove integrated diode!") + return + return ..() + +/obj/item/laser_pointer/attackby(obj/item/attack_item, mob/user, params) + if(istype(attack_item, /obj/item/stock_parts/micro_laser) || istype(attack_item, /obj/item/stack/ore/bluespace_crystal)) + if(!upgradable) + balloon_alert(user, "can't upgrade integrated parts!") + return + return ..() + +/obj/item/laser_pointer/examine(mob/user) + . = ..() + if(!upgradable) + . += span_notice("The diode and the lens are both cheap, integrated components. This pointer cannot be upgraded.") diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm b/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm index 5de8573f6b6a66..0e735a708a8918 100644 --- a/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm +++ b/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm @@ -17,10 +17,11 @@ //now lets register the signals RegisterSignal(atom_parent, COMSIG_ATOM_ATTACKBY, PROC_REF(check_attack)) RegisterSignal(atom_parent, COMSIG_ATOM_EXAMINE, PROC_REF(check_examine)) + RegisterSignal(atom_parent, COMSIG_QDELETING, PROC_REF(delete_farm)) /datum/component/simple_farm/Destroy(force, silent) //lets not hard del - UnregisterSignal(atom_parent, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_EXAMINE)) + UnregisterSignal(atom_parent, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_EXAMINE, COMSIG_QDELETING)) atom_parent = null return ..() @@ -42,6 +43,9 @@ locate_farm.pixel_x = pixel_shift[1] locate_farm.pixel_y = pixel_shift[2] locate_farm.layer = atom_parent.layer + 0.1 + if(ismovable(atom_parent)) + var/atom/movable/movable_parent = atom_parent + locate_farm.glide_size = movable_parent.glide_size attacking_item.forceMove(locate_farm) locate_farm.planted_seed = attacking_item locate_farm.attached_atom = atom_parent @@ -53,7 +57,18 @@ * check_examine is meant to listen for the COMSIG_ATOM_EXAMINE signal, where it will put additional information in the examine */ /datum/component/simple_farm/proc/check_examine(datum/source, mob/user, list/examine_list) - examine_list += span_notice("You are able to plant seeds here!") + examine_list += span_notice("
You are able to plant seeds here!") + +/** + * delete_farm is meant to be called when the parent of this component has been deleted-- thus deleting the ability to grow the simple farm + * it will delete the farm that can be found on the turf of the parent of this component + */ +/datum/component/simple_farm/proc/delete_farm() + SIGNAL_HANDLER + + var/obj/structure/simple_farm/locate_farm = locate() in get_turf(atom_parent) + if(locate_farm) + qdel(locate_farm) /obj/structure/simple_farm name = "simple farm" diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm b/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm new file mode 100644 index 00000000000000..0bc1b4d722e0d1 --- /dev/null +++ b/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm @@ -0,0 +1,126 @@ +/obj/structure/plant_tank + name = "plant tank" + desc = "A small little glass tank that is used to grow plants; this tank promotes the nitrogen and oxygen cycle." + icon = 'modular_skyrat/modules/ashwalkers/icons/structures.dmi' + icon_state = "plant_tank_e" + anchored = FALSE + density = TRUE + ///the amount of times the tank can produce-- can be increased through feeding the tank + var/operation_number = 0 + +/obj/structure/plant_tank/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + +/obj/structure/plant_tank/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/structure/plant_tank/examine(mob/user) + . = ..() + . += span_notice("
Use food or worm fertilizer to allow nitrogen production and carbon dioxide processing!") + . += span_notice("There are [operation_number] cycles left!") + var/datum/component/simple_farm/find_farm = GetComponent(/datum/component/simple_farm) + if(!find_farm) + . += span_notice("
Use five sand to allow planting!") + +/obj/structure/plant_tank/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/food) || istype(attacking_item, /obj/item/stack/worm_fertilizer)) + var/obj/item/stack/stack_item = attacking_item + if(isstack(stack_item)) + if(!stack_item.use(1)) + return + + else + qdel(attacking_item) + + balloon_alert(user, "[attacking_item] placed inside") + operation_number += 2 + return + + if(istype(attacking_item, /obj/item/storage/bag/plants)) + balloon_alert(user, "placing food inside") + for(var/obj/item/food/selected_food in attacking_item.contents) + qdel(selected_food) + operation_number += 2 + + return + + if(istype(attacking_item, /obj/item/stack/ore/glass)) + var/datum/component/simple_farm/find_farm = GetComponent(/datum/component/simple_farm) + if(find_farm) + balloon_alert(user, "no more [attacking_item] required") + return + + var/obj/item/stack/attacking_stack = attacking_item + if(!attacking_stack.use(5)) + balloon_alert(user, "farms require five sand") + return + + AddComponent(/datum/component/simple_farm, TRUE, TRUE, list(0, 12)) + icon_state = "plant_tank_f" + return + + return ..() + +/obj/structure/plant_tank/process(seconds_per_tick) + if(operation_number <= 0) //we require "fuel" to actually produce stuff + return + + if(!locate(/obj/structure/simple_farm) in get_turf(src)) //we require a plant to process the "fuel" + return + + operation_number-- + + var/turf/open/src_turf = get_turf(src) + if(!isopenturf(src_turf) || isspaceturf(src_turf) || src_turf.planetary_atmos) //must be open turf, can't be space turf, and can't be a turf that regenerates its atmos + return + + var/datum/gas_mixture/src_mixture = src_turf.return_air() + + src_mixture.assert_gases(/datum/gas/carbon_dioxide, /datum/gas/oxygen, /datum/gas/nitrogen) + + var/proportion = src_mixture.gases[/datum/gas/carbon_dioxide][MOLES] + if(proportion) //if there is carbon dioxide in the air, lets turn it into oxygen + proportion = min(src_mixture.gases[/datum/gas/carbon_dioxide][MOLES], MOLES_CELLSTANDARD) + src_mixture.gases[/datum/gas/carbon_dioxide][MOLES] -= proportion + src_mixture.gases[/datum/gas/oxygen][MOLES] += proportion + + src_mixture.gases[/datum/gas/nitrogen][MOLES] += MOLES_CELLSTANDARD //the nitrogen cycle-- plants (and bacteria) participate in the nitrogen cycle + +/obj/structure/plant_tank/wrench_act(mob/living/user, obj/item/tool) + balloon_alert(user, "[anchored ? "un" : ""]bolting") + tool.play_tool_sound(src, 50) + if(!tool.use_tool(src, user, 2 SECONDS)) + return TRUE + + anchored = !anchored + balloon_alert(user, "[anchored ? "" : "un"]bolted") + return TRUE + +/obj/structure/plant_tank/screwdriver_act(mob/living/user, obj/item/tool) + balloon_alert(user, "deconstructing") + tool.play_tool_sound(src, 50) + if(!tool.use_tool(src, user, 2 SECONDS)) + return TRUE + + deconstruct() + return TRUE + +/obj/structure/plant_tank/deconstruct(disassembled) + var/target_turf = get_turf(src) + for(var/loop in 1 to 4) + new /obj/item/stack/sheet/glass(target_turf) + new /obj/item/stack/rods(target_turf) + new /obj/item/forging/complete/plate(target_turf) + return ..() + +/datum/crafting_recipe/plant_tank + name = "Plant Tank" + result = /obj/structure/plant_tank + reqs = list( + /obj/item/forging/complete/plate = 1, + /obj/item/stack/sheet/glass = 4, + /obj/item/stack/rods = 4, + ) + category = CAT_STRUCTURE diff --git a/modular_skyrat/modules/ashwalkers/icons/structures.dmi b/modular_skyrat/modules/ashwalkers/icons/structures.dmi index d4e229d825590f..0682447f8d3022 100644 Binary files a/modular_skyrat/modules/ashwalkers/icons/structures.dmi and b/modular_skyrat/modules/ashwalkers/icons/structures.dmi differ diff --git a/modular_skyrat/modules/colony_fabricator/code/colony_fabricator.dm b/modular_skyrat/modules/colony_fabricator/code/colony_fabricator.dm index afda38b13399cc..6ffa9011b2ddcb 100644 --- a/modular_skyrat/modules/colony_fabricator/code/colony_fabricator.dm +++ b/modular_skyrat/modules/colony_fabricator/code/colony_fabricator.dm @@ -90,13 +90,17 @@ /obj/item/flatpacked_machine/Initialize(mapload) . = ..() desc = initial(type_to_deploy.desc) - AddComponent(/datum/component/deployable, deploy_time, type_to_deploy) + give_deployable_component() give_manufacturer_examine() /// Adds the manufacturer examine element to the flatpack machine, but can be overridden in the future /obj/item/flatpacked_machine/proc/give_manufacturer_examine() AddElement(/datum/element/manufacturer_examine, COMPANY_FRONTIER) +/// Adds the deployable component, in case we want to change this stuff later +/obj/item/flatpacked_machine/proc/give_deployable_component() + AddComponent(/datum/component/deployable, deploy_time, type_to_deploy) + /obj/item/borg/apparatus/sheet_manipulator/Initialize(mapload) . = ..() storable += /obj/item/flatpacked_machine diff --git a/modular_skyrat/modules/colony_fabricator/code/machines/thermomachine.dm b/modular_skyrat/modules/colony_fabricator/code/machines/thermomachine.dm index 741aabd06261c6..4f59cac7251e14 100644 --- a/modular_skyrat/modules/colony_fabricator/code/machines/thermomachine.dm +++ b/modular_skyrat/modules/colony_fabricator/code/machines/thermomachine.dm @@ -48,6 +48,10 @@ /datum/material/glass = SHEET_MATERIAL_AMOUNT, ) +// This prevents some weird visual bugs with the inlet +/obj/item/flatpacked_machine/thermomachine/give_deployable_component() + AddComponent(/datum/component/deployable, deploy_time, type_to_deploy, direction_setting = FALSE) + // Greyscale config for the light on this machine /datum/greyscale_config/thermomachine/deployable diff --git a/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm b/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm index f35b8f3e36fae4..059a93fcc297a1 100644 --- a/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm +++ b/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm @@ -98,7 +98,7 @@ GLOBAL_LIST_EMPTY(cortical_borers) /datum/reagent/medicine/epinephrine, /datum/reagent/medicine/haloperidol, /datum/reagent/toxin/formaldehyde, - /datum/reagent/impurity/libitoil, + /datum/reagent/inverse/libitoil, /datum/reagent/impurity/mannitol, /datum/reagent/medicine/c2/libital, /datum/reagent/medicine/c2/lenturi, diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm b/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm index 77aa1bf5fb2f25..702983b4966f08 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm +++ b/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm @@ -406,16 +406,16 @@ GLOBAL_LIST_INIT(loadout_toys, generate_loadout_items(/datum/loadout_item/toys)) /datum/loadout_item/toys/red_laser name = "Red Laser Pointer" - item_path = /obj/item/laser_pointer/red + item_path = /obj/item/laser_pointer/limited/red /datum/loadout_item/toys/green_laser name = "Green Laser Pointer" - item_path = /obj/item/laser_pointer/green + item_path = /obj/item/laser_pointer/limited/green /datum/loadout_item/toys/blue_laser name = "Blue Laser Pointer" - item_path = /obj/item/laser_pointer/blue + item_path = /obj/item/laser_pointer/limited/blue /datum/loadout_item/toys/purple_laser name = "Purple Laser Pointer" - item_path = /obj/item/laser_pointer/purple + item_path = /obj/item/laser_pointer/limited/purple diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm b/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm index e565d49152238c..11b1044979fb75 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm @@ -12,6 +12,28 @@ else to_chat(src, span_warning("You can't cum right now!")) +/mob/living/verb/reflexes_verb() + set name = "Toggle Reflexes" + set category = "IC" + if(!HAS_TRAIT_FROM(src, TRAIT_QUICKREFLEXES, REF(src))) + ADD_TRAIT(src, TRAIT_QUICKREFLEXES, REF(src)) + to_chat(src, span_notice("[get_reflexes_gain_text()]")) + else + REMOVE_TRAIT(src, TRAIT_QUICKREFLEXES, REF(src)) + to_chat(src, span_notice("[get_reflexes_lose_text()]")) + +/mob/living/proc/get_reflexes_gain_text() + return "You don't feel like being touched right now." + +/mob/living/proc/get_reflexes_lose_text() + return "You'll allow yourself to be touched now." + +/mob/living/silicon/get_reflexes_gain_text() + return "Our systems will disallow platonic contact." + +/mob/living/silicon/get_reflexes_lose_text() + return "Our systems will allow platonic contact." + /mob/living/carbon/human/Initialize(mapload) . = ..() if(CONFIG_GET(flag/disable_erp_preferences)) diff --git a/modular_skyrat/modules/modular_vending/code/games.dm b/modular_skyrat/modules/modular_vending/code/games.dm index e324b6575f4066..bddc6e2e6d6519 100644 --- a/modular_skyrat/modules/modular_vending/code/games.dm +++ b/modular_skyrat/modules/modular_vending/code/games.dm @@ -5,7 +5,7 @@ "icon" = "hat-wizard", "products" = list( /obj/item/storage/briefcase/secure/white/wargame_kit = 3, - /obj/item/laser_pointer = 3, + /obj/item/laser_pointer/limited = 3, ), ), list( diff --git a/modular_skyrat/modules/verbs/code/looc.dm b/modular_skyrat/modules/verbs/code/looc.dm index 3dd47f9741cf9e..77eb5d02d68e25 100644 --- a/modular_skyrat/modules/verbs/code/looc.dm +++ b/modular_skyrat/modules/verbs/code/looc.dm @@ -40,8 +40,8 @@ if(is_banned_from(ckey, BAN_LOOC)) to_chat(src, span_warning("You are LOOC banned!")) return - if(mob.stat) - to_chat(src, span_danger("You cannot use LOOC while unconscious or dead.")) + if(mob.stat == DEAD) + to_chat(src, span_danger("You cannot use LOOC while dead.")) return if(istype(mob, /mob/dead)) to_chat(src, span_danger("You cannot use LOOC while ghosting.")) diff --git a/strings/tips.txt b/strings/tips.txt index 0a554b4c382880..69128714f1fd7a 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -252,6 +252,7 @@ When hacking doors, cutting and mending a "test light wire" will restore power t When in doubt about technical issues, clear your cache (byond launcher > cogwheel > preferences > game prefs), update your BYOND, and relog. When placing floor tiles in space, you don't need to place down lattice if there is a piece of plating nearby. Where the space map levels connect is randomized every round, but are otherwise kept consistent within rounds. Remember that they are not necessarily bidirectional! +Working out improves your fitness which increases your size and faster times to fireman carry. Remember that a quality diet and sleep are essential! You can catch thrown items by toggling on your throw mode with an empty hand active. You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this. You can cheat games by baking dice in microwaves to make them loaded. Cards can be seen with x-ray vision or be marked with either a pen or crayon to gain an edge. diff --git a/tgstation.dme b/tgstation.dme index ca16b7e0abd940..e803d13558853f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5609,6 +5609,7 @@ #include "code\modules\shuttle\shuttle_events\meteors.dm" #include "code\modules\shuttle\shuttle_events\misc.dm" #include "code\modules\shuttle\shuttle_events\player_controlled.dm" +#include "code\modules\shuttle\shuttle_events\turbulence.dm" #include "code\modules\spatial_grid\cell_tracker.dm" #include "code\modules\spells\spell.dm" #include "code\modules\spells\spell_types\madness_curse.dm" @@ -6195,6 +6196,7 @@ #include "modular_skyrat\master_files\code\game\objects\items\wiki_manuals.dm" #include "modular_skyrat\master_files\code\game\objects\items\devices\anomaly_neutralizer.dm" #include "modular_skyrat\master_files\code\game\objects\items\devices\chameleonproj.dm" +#include "modular_skyrat\master_files\code\game\objects\items\devices\laserpointer.dm" #include "modular_skyrat\master_files\code\game\objects\items\devices\mod_link.dm" #include "modular_skyrat\master_files\code\game\objects\items\devices\traitordevices.dm" #include "modular_skyrat\master_files\code\game\objects\items\stacks\sheets\sheet_types.dm" @@ -6536,6 +6538,7 @@ #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\planttank.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/Interview.tsx b/tgui/packages/tgui/interfaces/Interview.tsx index 4c996ac36511eb..78f8266f476f89 100644 --- a/tgui/packages/tgui/interfaces/Interview.tsx +++ b/tgui/packages/tgui/interfaces/Interview.tsx @@ -4,10 +4,11 @@ import { Section, BlockQuote, NoticeBox, + Box, } from '../components'; import { Window } from '../layouts'; import { useBackend } from '../backend'; -import { ReactNode } from 'react'; +import { ReactNode, useState } from 'react'; type Data = { connected: boolean; @@ -22,7 +23,7 @@ type Data = { type Question = { qidx: number; question: string; - response: string; + response: string | null; }; enum STATUS { @@ -56,13 +57,16 @@ export const Interview = (props) => { const { connected, is_admin, - questions = [], // TODO: Remove default + questions = [], queue_pos, read_only, status, welcome_message = '', } = data; + const allAnswered = questions.every((q) => q.response); + const numAnswered = questions.filter((q) => q.response)?.length; + return ( { buttons={ {!!is_admin && status === 'interview_pending' && ( - + + )} } > {!read_only && ( -

- Please answer the following questions, and press submit when you - are satisfied with your answers. -
-
- You will not be able to edit your answers after submitting. -

+ <> + + Please answer the following questions. + + + + You will not be able to edit your answers after submitting. + + )} - {questions.map(({ qidx, question, response }) => ( -
-

{linkifyText(question)}

- {((read_only || is_admin) && ( -
{response || 'No response.'}
- )) || ( -