diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm index ab233e9cf82c..e76768a82b46 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm @@ -50,6 +50,10 @@ /// From /datum/action/xeno_action/proc/use_ability_wrapper(): (mob/owner) #define COMSIG_XENO_ACTION_USED "xeno_action_used" +/// From /datum/action/xeno_action/proc/use_ability_wrapper(): (mob/owner) +#define COMSIG_XENO_PRE_ACTION_USED "xeno_pre_action_used" +/// From /datum/action/xeno_action/proc/use_ability_wrapper(): (mob/owner) +#define COMSIG_XENO_FAILED_ACTION_USED "xeno_failed_action_used" /// From /mob/living/carbon/xenomorph/proc/check_blood_splash() #define COMSIG_XENO_DEAL_ACID_DAMAGE "xeno_deal_acid_damage" /// From /mob/living/carbon/xenomorph/proc/recalculate_speed() diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 5ba79960657b..88f99bbff578 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -83,3 +83,5 @@ #define COMSIG_CAMERA_SET_AREA "camera_manager_set_area" #define COMSIG_CAMERA_CLEAR "camera_manager_clear_target" #define COMSIG_CAMERA_REFRESH "camera_manager_refresh" + +#define COMSIG_PRED_BRACER_DECLOAKED "pred_bracer_decloaked" diff --git a/code/__DEFINES/dcs/signals/atom/signals_movable.dm b/code/__DEFINES/dcs/signals/atom/signals_movable.dm index ba889d0b5212..ad4be2b1dc9f 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_movable.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_movable.dm @@ -11,6 +11,9 @@ #define COMPONENT_CANCEL_MOVE (1<<0) /// From /turf/open/gm/river/Entered(): (turf/open/gm/river/river, covered) #define COMSIG_MOVABLE_ENTERED_RIVER "movable_entered_river" +/// From /atom/movable/proc/doMove: I think it only works with forceMove so watch out +#define COMSIG_MOVABLE_FORCEMOVE_PRE_CROSSED "movable_forcemove_pre_crossed" + #define COMPONENT_IGNORE_CROSS (1<<0) ///from /mob/living/carbon/xenomorph/start_pulling(): (mob/living/carbon/xenomorph/X) #define COMSIG_MOVABLE_XENO_START_PULLING "movable_xeno_start_pulling" diff --git a/code/__DEFINES/dcs/signals/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum.dm index b798d510763e..c35038fcf3e9 100644 --- a/code/__DEFINES/dcs/signals/signals_datum.dm +++ b/code/__DEFINES/dcs/signals/signals_datum.dm @@ -34,6 +34,8 @@ #define COMSIG_ACTION_HIDDEN "action_hidden" /// From base of /datum/action/proc/unhide_from(): (mob/owner) #define COMSIG_ACTION_UNHIDDEN "action_unhidden" +/// From base of /datum/action/proc/action_activate() : () +#define COMSIG_ACTION_ACTIVATED "action_activated" ///from /datum/component/bonus_damage_stack #define COMSIG_BONUS_DAMAGE "bonus_damage" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 964e77402655..e6b9c4c4b9ee 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -161,6 +161,8 @@ #define TRAIT_MERGED_WITH_WEEDS "merged_with_weeds" /// Apply this to identify a mob as temporarily muted #define TRAIT_TEMPORARILY_MUTED "temporarily_muted" +/// Mob wont get hit by stray projectiles +#define TRAIT_NO_STRAY "trait_no_stray" // SPECIES TRAITS /// Knowledge of Yautja technology diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 5bf36f785746..094f8205c80e 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -235,7 +235,7 @@ * * hive - The hive we're filling a slot for to check if the player is banished * * sorted - Whether to sort by larva_queue_time (default TRUE) or leave unsorted */ -/proc/get_alien_candidates(datum/hive_status/hive = null, sorted = TRUE) +/proc/get_alien_candidates(datum/hive_status/hive = null, sorted = TRUE, abomination = FALSE) var/list/candidates = list() for(var/mob/dead/observer/cur_obs as anything in GLOB.observer_list) @@ -275,6 +275,11 @@ if(banished) continue + if(abomination) + if(!(/datum/tutorial/xenomorph/abomination::tutorial_id in cur_obs.client.prefs.completed_tutorials)) + to_chat(cur_obs, SPAN_BOLDNOTICE("You were passed over for playing as an Abomination because you have not completed its tutorial.")) + continue + candidates += cur_obs // Optionally sort by larva_queue_time diff --git a/code/_macros.dm b/code/_macros.dm index abfa83df7d36..9b92dc8730c3 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -95,6 +95,9 @@ #define GENERATE_DEBUG_ID "[rand(0, 9)][rand(0, 9)][rand(0, 9)][rand(0, 9)][pick(alphabet_lowercase)][pick(alphabet_lowercase)][pick(alphabet_lowercase)][pick(alphabet_lowercase)]" #define RECT new /datum/shape/rectangle +#define SQUARE new /datum/shape/rectangle/square +#define ELLIPSE new /datum/shape/ellipse +#define CIRCLE new /datum/shape/ellipse/circle #define QTREE new /datum/quadtree #define SEARCH_QTREE(qtree, shape_range, flags) qtree.query_range(shape_range, null, flags) diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm index 3bb69fe05419..15dc1c39f495 100644 --- a/code/_onclick/xeno.dm +++ b/code/_onclick/xeno.dm @@ -3,7 +3,7 @@ */ /mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE, ignores_resin = FALSE) - if(body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //No attacks while laying down + if(body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED) || cannot_slash) //No attacks while laying down return FALSE var/mob/alt diff --git a/code/controllers/subsystem/sound.dm b/code/controllers/subsystem/sound.dm index 024df7cc45ad..13dd6a0dddf1 100644 --- a/code/controllers/subsystem/sound.dm +++ b/code/controllers/subsystem/sound.dm @@ -19,8 +19,7 @@ SUBSYSTEM_DEF(sound) if(!run_hearers) // Initialize for handling next template run_hearers = run_queue[run_template] // get base hearers if(run_template.range) // ranging - var/datum/shape/rectangle/zone = RECT(run_template.x, run_template.y, run_template.range * 2, run_template.range * 2) - run_hearers |= SSquadtree.players_in_range(zone, run_template.z) + run_hearers |= SSquadtree.players_in_range(SQUARE(run_template.x, run_template.y, run_template.range), run_template.z) if(MC_TICK_CHECK) return while(length(run_hearers)) // Output sound to hearers diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 85e2a57cc6d6..25f522753543 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -414,6 +414,7 @@ SUBSYSTEM_DEF(vote) qdel(src) /datum/action/innate/vote/action_activate() + . = ..() owner.vote() /datum/action/innate/vote/proc/remove_from_client() diff --git a/code/datums/action.dm b/code/datums/action.dm index d1768655a2da..8dbf6c9df5a5 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -43,7 +43,9 @@ return /datum/action/proc/action_activate() - return + SHOULD_CALL_PARENT(TRUE) + + SEND_SIGNAL(src, COMSIG_ACTION_ACTIVATED) /// handler for when a keybind signal is received by the action, calls the action_activate proc asynchronous /datum/action/proc/keybind_activation() @@ -158,6 +160,10 @@ hidden = FALSE L.update_action_buttons() +/proc/get_action(mob/action_mob, action_path) + for(var/datum/action/action in action_mob.actions) + if(istype(action, action_path)) + return action /datum/action/item_action name = "Use item" @@ -182,6 +188,7 @@ return ..() /datum/action/item_action/action_activate() + . = ..() if(target) var/obj/item/I = target I.ui_action_click(owner, holder_item) diff --git a/code/datums/ammo/bullet/lever_action.dm b/code/datums/ammo/bullet/lever_action.dm index 2770231b6811..e1475146b21f 100644 --- a/code/datums/ammo/bullet/lever_action.dm +++ b/code/datums/ammo/bullet/lever_action.dm @@ -52,7 +52,7 @@ /datum/ammo/bullet/lever_action/xm88 name = ".458 SOCOM round" - damage = 80 + damage = 104 penetration = ARMOR_PENETRATION_TIER_2 accuracy = HIT_ACCURACY_TIER_1 shell_speed = AMMO_SPEED_TIER_6 diff --git a/code/datums/components/bad_leg.dm b/code/datums/components/bad_leg.dm index 4a8678c4da76..8793271803dc 100644 --- a/code/datums/components/bad_leg.dm +++ b/code/datums/components/bad_leg.dm @@ -149,6 +149,7 @@ CRASH("No bound wound to link action") /datum/action/human_action/rest_legs/action_activate() + . = ..() var/mob/living/carbon/human/homan = owner if(in_use) to_chat(homan, SPAN_WARNING("You're already doing that!")) diff --git a/code/datums/quadtree.dm b/code/datums/quadtree.dm index 5e5b27d57330..200a51b358a0 100644 --- a/code/datums/quadtree.dm +++ b/code/datums/quadtree.dm @@ -49,43 +49,124 @@ ..() return QDEL_HINT_IWILLGC -/datum/shape //Leaving rectangles as a subtype if anyone decides to add circles later +/// A simple geometric shape for testing collisions and intersections. This one is a single point. +/datum/shape + /// Horizontal position of the shape's center point. var/center_x = 0 + /// Vertical position of the shape's center point. var/center_y = 0 + /// Distance from the shape's leftmost to rightmost extent. + var/bounds_x = 0 + /// Distance from the shape's topmost to bottommost extent. + var/bounds_y = 0 -/datum/shape/proc/intersects() - return -/datum/shape/proc/contains() - return +/datum/shape/New(center_x, center_y) + set_shape(center_x, center_y) +/// Assign shape variables. +/datum/shape/proc/set_shape(center_x, center_y) + src.center_x = center_x + src.center_y = center_y + +/// Returns TRUE if the coordinates x, y are in or on the shape, otherwise FALSE. +/datum/shape/proc/contains_xy(x, y) + return center_x == x && center_y == y + +/// Returns TRUE if the coord datum is in or on the shape, otherwise FALSE. +/datum/shape/proc/contains_coords(datum/coords/coords) + return contains_xy(coords.x_pos, coords.y_pos) + +/// Returns TRUE if the atom is in or on the shape, otherwise FALSE. +/datum/shape/proc/contains_atom(atom/atom) + return contains_xy(atom.x, atom.y) + +/// Returns TRUE if this shape's bounding box intersects the provided shape's bounding box, otherwise FALSE. Generally faster than a full intersection test. +/datum/shape/proc/intersects_aabb(datum/shape/aabb) + return (abs(src.center_x - aabb.center_x) <= (src.bounds_x + aabb.bounds_x) * 0.5) && (abs(src.center_y - aabb.center_y) <= (src.bounds_x + aabb.bounds_x) * 0.5) + +/// Returns TRUE if this shape intersects the provided rectangle shape, otherwise FALSE. +/datum/shape/proc/intersects_rect(datum/shape/rectangle/rect) + return rect.contains_xy(src.center_x, src.center_y) + +/// A simple geometric shape for testing collisions and intersections. This one is an axis-aligned rectangle. /datum/shape/rectangle + /// Distance from the shape's leftmost to rightmost extent. + var/width = 0 + /// Distance from the shape's topmost to bottommost extent. + var/height = 0 + +/datum/shape/rectangle/New(center_x, center_y, width, height) + set_shape(center_x, center_y, width, height) + +/datum/shape/rectangle/set_shape(center_x, center_y, width, height) + ..() + src.bounds_x = width + src.bounds_y = height + src.width = width + src.height = height + +/datum/shape/rectangle/contains_xy(x, y) + return (abs(center_x - x) <= width * 0.5) && (abs(center_y - y) <= height * 0.5) + +/datum/shape/rectangle/intersects_rect(datum/shape/rectangle/rect) + return intersects_aabb(rect) + +/// A simple geometric shape for testing collisions and intersections. This one is an axis-aligned square. +/datum/shape/rectangle/square + /// Distance between the shape's opposing extents. + var/length = 0 + +/datum/shape/rectangle/square/New(center_x, center_y, length) + set_shape(center_x, center_y, length) + +/datum/shape/rectangle/square/set_shape(center_x, center_y, length) + ..(center_x, center_y, length, length) + src.length = length + +/// A simple geometric shape for testing collisions and intersections. This one is an axis-aligned ellipse. +/datum/shape/ellipse + /// Distance from the shape's leftmost to rightmost extent. var/width = 0 + /// Distance from the shape's topmost to bottommost extent. var/height = 0 + VAR_PROTECTED/_axis_x_sq = 0 + VAR_PROTECTED/_axis_y_sq = 0 + +/datum/shape/ellipse/New(center_x, center_y, width, height) + set_shape(center_x, center_y, width, height) -/datum/shape/rectangle/New(x, y, w, h) +/datum/shape/ellipse/set_shape(center_x, center_y, width, height) ..() - center_x = x - center_y = y - width = w - height = h - -/datum/shape/rectangle/intersects(datum/shape/rectangle/range) - return !(range.center_x + range.width/2 < center_x - width / 2|| \ - range.center_x - range.width/2 > center_x + width / 2|| \ - range.center_y + range.height/2 < center_y - height / 2|| \ - range.center_y - range.height/2 > center_y + height / 2) - -/datum/shape/rectangle/contains(datum/coords/coords) - return (coords.x_pos >= center_x - width / 2 \ - && coords.x_pos <= center_x + width / 2 \ - && coords.y_pos >= center_y - height /2 \ - && coords.y_pos <= center_y + height / 2) - -/datum/shape/rectangle/proc/contains_atom(atom/A) - return (A.x >= center_x - width / 2 \ - && A.x <= center_x + width / 2 \ - && A.y >= center_y - height /2 \ - && A.y <= center_y + height / 2) + src.bounds_x = width + src.bounds_y = height + src.width = width + src.height = height + src._axis_x_sq = (width * 0.5)**2 + src._axis_y_sq = (height * 0.5)**2 + +/datum/shape/ellipse/contains_xy(x, y) + return ((center_x - x)**2 / _axis_x_sq + (center_y - y)**2 / _axis_y_sq <= 1) + +/datum/shape/ellipse/intersects_rect(datum/shape/rectangle/rect) + if(..()) + return TRUE + + var/nearest_x = clamp(src.center_x, rect.center_x - rect.width * 0.5, rect.center_x + rect.width * 0.5) + var/nearest_y = clamp(src.center_y, rect.center_y - rect.height * 0.5, rect.center_y + rect.height * 0.5) + + return src.contains_xy(nearest_x, nearest_y) + +/// A simple geometric shape for testing collisions and intersections. This one is a circle. +/datum/shape/ellipse/circle + /// Distance from the shape's center to edge. + var/radius = 0 + +/datum/shape/ellipse/circle/New(center_x, center_y, radius) + set_shape(center_x, center_y, radius) + +/datum/shape/ellipse/circle/set_shape(center_x, center_y, radius) + ..(center_x, center_y, radius * 2, radius * 2) + src.radius = radius /datum/quadtree/proc/subdivide() //Warning: this might give you eye cancer @@ -96,7 +177,7 @@ is_divided = TRUE /datum/quadtree/proc/insert_player(datum/coords/qtplayer/p_coords) - if(!boundary.contains(p_coords)) + if(!boundary.contains_coords(p_coords)) return FALSE if(!player_coords) @@ -118,11 +199,11 @@ player_coords.Add(p_coords) return TRUE -/datum/quadtree/proc/query_range(datum/shape/rectangle/range, list/found_players, flags = 0) +/datum/quadtree/proc/query_range(datum/shape/range, list/found_players, flags = 0) if(!found_players) found_players = list() . = found_players - if(!range?.intersects(boundary)) + if(!range?.intersects_rect(boundary)) return if(is_divided) nw_branch.query_range(range, found_players, flags) @@ -136,7 +217,7 @@ continue if((flags & QTREE_EXCLUDE_OBSERVER) && P.is_observer) continue - if(range.contains(P)) + if(range.contains_coords(P)) if(flags & QTREE_SCAN_MOBS) found_players.Add(P.player.mob) else diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm index 10ec04c6da0e..79493ca87ef0 100644 --- a/code/datums/statistics/entities/round_stats.dm +++ b/code/datums/statistics/entities/round_stats.dm @@ -393,6 +393,7 @@ return TRUE /datum/action/show_round_statistics/action_activate() + . = ..() if(!can_use_action()) return diff --git a/code/datums/tutorial/_tutorial.dm b/code/datums/tutorial/_tutorial.dm index ddeddddd0407..b7403da3c0a9 100644 --- a/code/datums/tutorial/_tutorial.dm +++ b/code/datums/tutorial/_tutorial.dm @@ -4,7 +4,7 @@ GLOBAL_LIST_EMPTY_TYPED(ongoing_tutorials, /datum/tutorial) /datum/tutorial /// What the tutorial is called, is player facing var/name = "Base" - /// Internal ID of the tutorial, kept for save files + /// Internal ID of the tutorial, kept for save files. Format is "tutorialtype_specifictutorial_number". So, the first basic xeno tutorial would be "xeno_basic_1", and the 2nd marine medical tutorial would be "marine_medical_2" var/tutorial_id = "base" /// A short 1-2 sentence description of the tutorial itself var/desc = "" @@ -144,6 +144,8 @@ GLOBAL_LIST_EMPTY_TYPED(ongoing_tutorials, /datum/tutorial) /// Ends the tutorial after a certain amount of time. /datum/tutorial/proc/tutorial_end_in(time = 5 SECONDS, completed = TRUE) + if(completed) + mark_completed() // This is done because if you're calling this proc with completed == TRUE, then the tutorial's a done deal. We shouldn't penalize the player if they exit a few seconds before it actually completes. tutorial_ending = TRUE addtimer(CALLBACK(src, PROC_REF(end_tutorial), completed), time) @@ -221,6 +223,7 @@ GLOBAL_LIST_EMPTY_TYPED(ongoing_tutorials, /datum/tutorial) tutorial = WEAKREF(selected_tutorial) /datum/action/tutorial_end/action_activate() + . = ..() if(!tutorial) return diff --git a/code/datums/tutorial/xenomorph/abomination.dm b/code/datums/tutorial/xenomorph/abomination.dm new file mode 100644 index 000000000000..db9b77cf2e75 --- /dev/null +++ b/code/datums/tutorial/xenomorph/abomination.dm @@ -0,0 +1,247 @@ +/datum/tutorial/xenomorph/abomination + name = "Xenomorph - Predalien" + desc = "A tutorial to teach you how to play the \"Predalien\", also known as Abomination, xenomorph caste. Completing this is required to be able to play an Abomination." + icon_state = "predalien" + tutorial_id = "xeno_abom_1" + tutorial_template = /datum/map_template/tutorial/s7x7 + starting_xenomorph_type = /mob/living/carbon/xenomorph/predalien/tutorial + /// How many marines in the kill_marines stage have been killed + var/ending_marines_killed = 0 + +// START OF SCRITPING + +/datum/tutorial/xenomorph/abomination/start_tutorial(mob/starting_mob) + . = ..() + if(!.) + return + + init_mob() + xeno.lock_evolve = TRUE + + message_to_player("Welcome to the tutorial for the Abomination xenomorph. As an Abomination, you are a frontline powerhouse whose damage scales with your kill count.") + message_to_player("Your kill count scales when you kill humans with your slash attack, up to 10 kills. Ability kills do not count towards this.") + + addtimer(CALLBACK(src, PROC_REF(how_to_be_abom)), 12 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/how_to_be_abom() + message_to_player("Be aware that you are kill-on-sight to all Predators forever, and will very likely need to defend yourself against multiple.") + message_to_player("Be sure to stick close to other xenomorphs or over-extend. While you may be stronger than many, you don't have enough health or armor to go out on your own.") + addtimer(CALLBACK(src, PROC_REF(feral_rush_tutorial)), 10.5 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/feral_rush_tutorial() + var/datum/action/rush = give_action(xeno, /datum/action/xeno_action/onclick/feralrush) + message_to_player("Your first unique ability is Feral Rush, an ability that temporarily increases your speed and your armor. Use Feral Rush to continue.") + update_objective("Use your Feral Rush ability.") + add_highlight(rush.button) + RegisterSignal(rush, COMSIG_XENO_ACTION_USED, PROC_REF(on_rush_used)) + +/datum/tutorial/xenomorph/abomination/proc/on_rush_used(datum/action/source, mob/owner) + SIGNAL_HANDLER + + UnregisterSignal(source, COMSIG_XENO_ACTION_USED) + remove_highlight(source.button) + addtimer(CALLBACK(src, PROC_REF(predalien_roar_tutorial_1)), 5 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/predalien_roar_tutorial_1() + hide_action(xeno, /datum/action/xeno_action/onclick/feralrush) + xeno.cannot_slash = TRUE + message_to_player("Your next ability is Roar, a versatile ability that disables any motion detectors or cloaks in a medium radius around you.") + message_to_player("Additionally, it gives a slash and speed bonus to any friendly xenomorphs in range.") + addtimer(CALLBACK(src, PROC_REF(predalien_roar_tutorial_2)), 8 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/predalien_roar_tutorial_2() + var/datum/action/roar = give_action(xeno, /datum/action/xeno_action/onclick/predalien_roar) + message_to_player("One of Roar's most useful abilities is uncloaking nearby Predators. Use Roar to uncloak the newly spawned Predator.") + update_objective("Use your Roar ability to uncloak the nearby predator.") + add_highlight(roar.button) + var/mob/living/carbon/human/pred = new(loc_from_corner(3, 3)) + add_to_tracking_atoms(pred) + pred.create_hud() + arm_equipment(pred, /datum/equipment_preset/yautja/blooded) + var/obj/item/clothing/gloves/yautja/hunter/bracers = locate() in pred + if(!bracers) + message_to_player("Something has gone wrong. Please make a bug report.") + CRASH("predator spawned without bracers in tutorial") + + bracers.cloaker_internal(pred, TRUE, TRUE, TRUE) + RegisterSignal(bracers, COMSIG_PRED_BRACER_DECLOAKED, PROC_REF(smash_tutorial_1)) + +/datum/tutorial/xenomorph/abomination/proc/smash_tutorial_1(datum/source) + SIGNAL_HANDLER + + var/datum/action/roar = get_action(xeno, /datum/action/xeno_action/onclick/predalien_roar) + remove_highlight(roar.button) + update_objective("") + + UnregisterSignal(source, COMSIG_PRED_BRACER_DECLOAKED) + addtimer(CALLBACK(src, PROC_REF(smash_tutorial_2)), 2.5 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/smash_tutorial_2() + hide_action(xeno, /datum/action/xeno_action/onclick/predalien_roar) + message_to_player("Good. Roar will be one of your primary tools for defending against Predators. Your next ability is Feral Smash.") + xeno.cannot_slash = FALSE + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, pred) + remove_from_tracking_atoms(pred) + qdel(pred) + + addtimer(CALLBACK(src, PROC_REF(smash_tutorial_3)), 5 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/smash_tutorial_3() + var/datum/action/smash = give_action(xeno, /datum/action/xeno_action/activable/feral_smash) + RegisterSignal(smash, COMSIG_XENO_PRE_ACTION_USED, PROC_REF(frenzy_tutorial_1)) + add_highlight(smash.button) + + message_to_player("Feral Smash is a strong lunge with a range of five tiles. It deals decent damage that scales with your kill count.") + message_to_player("Use Feral Smash on the marine to continue.") + update_objective("Use your Feral Smash ability on the marine.") + + xeno.forceMove(loc_from_corner(0, 2)) + xeno.anchored = TRUE + ADD_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL) + + var/mob/living/carbon/human/marine = new(loc_from_corner(4, 2)) + add_to_tracking_atoms(marine) + arm_equipment(marine, /datum/equipment_preset/uscm/private_equipped) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_1(datum/action/source, mob/owner) + SIGNAL_HANDLER + + xeno.anchored = FALSE + REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL) + RegisterSignal(source, COMSIG_XENO_ACTION_USED, PROC_REF(frenzy_tutorial_2)) + RegisterSignal(source, COMSIG_XENO_FAILED_ACTION_USED, PROC_REF(frenzy_tutorial_1_fail)) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_1_fail(datum/action/source, mob/owner) + SIGNAL_HANDLER + + xeno.anchored = TRUE + ADD_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL) + UnregisterSignal(source, list(COMSIG_XENO_FAILED_ACTION_USED, COMSIG_XENO_ACTION_USED)) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_2(datum/action/source, mob/owner) + SIGNAL_HANDLER + + if(get_turf(xeno) == loc_from_corner(0, 2)) // xeno didn't lunge at the mob + xeno.anchored = TRUE + UnregisterSignal(source, COMSIG_XENO_ACTION_USED) + ADD_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL) + return + + update_objective("") + var/datum/action/smash = get_action(xeno, /datum/action/xeno_action/activable/feral_smash) + remove_highlight(smash.button) + UnregisterSignal(source, list(COMSIG_XENO_ACTION_USED, COMSIG_XENO_PRE_ACTION_USED)) + addtimer(CALLBACK(src, PROC_REF(frenzy_tutorial_3)), 2 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_3() + remove_action(xeno, /datum/action/xeno_action/activable/feral_smash) + message_to_player("Good. Your final ability is Feral Frenzy, a strong ability that can alternate between hitting a single target or all within a large radius. However, it locks you in place while it winds up.") + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, marine) + remove_from_tracking_atoms(marine) + qdel(marine) + + addtimer(CALLBACK(src, PROC_REF(frenzy_tutorial_4)), 6 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_4() + var/mob/living/carbon/human/marine = new(loc_from_corner(4, 2)) + add_to_tracking_atoms(marine) + arm_equipment(marine, /datum/equipment_preset/uscm/private_equipped) + + var/datum/action/frenzy = give_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) + add_highlight(frenzy.button) + message_to_player("By default, Feral Frenzy is on single-target mode. Use Feral Frenzy on the newly spawned marine.") + update_objective("Use Feral Frenzy on the marine.") + + RegisterSignal(frenzy, COMSIG_XENO_ACTION_USED, PROC_REF(frenzy_tutorial_5)) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_5(datum/action/xeno_action/source, mob/owner) + SIGNAL_HANDLER + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, marine) + if(get_dist(marine, xeno) > 1) + return + + UnregisterSignal(source, COMSIG_XENO_ACTION_USED) + var/datum/action/frenzy = get_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) + remove_highlight(frenzy.button) + var/datum/action/frenzy_toggle = give_action(xeno, /datum/action/xeno_action/onclick/toggle_gut_targeting) + add_highlight(frenzy_toggle.button) + message_to_player("Good, now toggle Feral Frenzy's AOE mode with the newly available Toggle Gutting Type ability.") + update_objective("Use the Toggle Gutting Type ability to change your frenzy mode.") + + RegisterSignal(frenzy_toggle, COMSIG_XENO_ACTION_USED, PROC_REF(frenzy_tutorial_6)) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_6(datum/action/xeno_action/source, mob/owner) + SIGNAL_HANDLER + + UnregisterSignal(source, COMSIG_XENO_ACTION_USED) + remove_highlight(source.button) + source.plasma_cost = INFINITY // slightly scuffed way of disabling the switch button + source.update_button_icon() + + message_to_player("Feral Frenzy has now been changed into AOE mode. Use Feral Frenzy again anywhere within 2 tiles of the marine.") + update_objective("Use Feral Frenzy within 2 tiles of the marine.") + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, marine) + marine.rejuvenate() + var/datum/action/xeno_action/activable/feralfrenzy/frenzy = get_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) + frenzy.targeting = AOETARGETGUT + frenzy.reduce_cooldown(frenzy.xeno_cooldown) + add_highlight(frenzy.button) + + RegisterSignal(frenzy, COMSIG_XENO_ACTION_USED, PROC_REF(frenzy_tutorial_7)) + +/datum/tutorial/xenomorph/abomination/proc/frenzy_tutorial_7(datum/action/source) + SIGNAL_HANDLER + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, marine) + var/datum/action/xeno_action/activable/feralfrenzy/frenzy = get_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) + if(get_dist(xeno, marine) > frenzy.range) + // Not close enough to actually hit the marine + return + + UnregisterSignal(frenzy, COMSIG_XENO_ACTION_USED) + remove_highlight(frenzy.button) + message_to_player("Good. As you may have noticed, the AOE version of Feral Frenzy takes longer to wind up, in addition to doing less overall damage.") + addtimer(CALLBACK(src, PROC_REF(kill_marines)), 6 SECONDS) + +/datum/tutorial/xenomorph/abomination/proc/kill_marines() + message_to_player("To finish the tutorial, kill the three newly-spawned marines using any of your attacks or abilities.") + + // Spawn/rejuv the dummies + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, marine) // we can reuse this one though + marine.rejuvenate() + marine.forceMove(loc_from_corner(4, 2)) + RegisterSignal(marine, COMSIG_MOB_DEATH, PROC_REF(kill_marines_2)) + + var/mob/living/carbon/human/marine_2 = new(loc_from_corner(2, 2)) + arm_equipment(marine_2, /datum/equipment_preset/uscm/private_equipped) + RegisterSignal(marine_2, COMSIG_MOB_DEATH, PROC_REF(kill_marines_2)) + + var/mob/living/carbon/human/marine_3 = new(loc_from_corner(0, 2)) + arm_equipment(marine_3, /datum/equipment_preset/uscm/private_equipped) + RegisterSignal(marine_3, COMSIG_MOB_DEATH, PROC_REF(kill_marines_2)) + + // Arrange the actions about how they'd be in an actual game + remove_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) + remove_action(xeno, /datum/action/xeno_action/onclick/toggle_gut_targeting) + + give_action(xeno, /datum/action/xeno_action/activable/tail_stab) + give_action(xeno, /datum/action/xeno_action/onclick/feralrush) + give_action(xeno, /datum/action/xeno_action/onclick/predalien_roar) + give_action(xeno, /datum/action/xeno_action/activable/feral_smash) + give_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) + give_action(xeno, /datum/action/xeno_action/onclick/toggle_gut_targeting) + +/datum/tutorial/xenomorph/abomination/proc/kill_marines_2(datum/source) + SIGNAL_HANDLER + + if(ending_marines_killed < 2) + ending_marines_killed++ + return + + message_to_player("Good work. The tutorial will end shortly.") + tutorial_end_in(7 SECONDS, TRUE) + +// END OF SCRIPTING diff --git a/code/datums/xeno_shields/shield_types/vanguard_shield.dm b/code/datums/xeno_shields/shield_types/vanguard_shield.dm index 21d9fb12cfd7..cd9e4534e778 100644 --- a/code/datums/xeno_shields/shield_types/vanguard_shield.dm +++ b/code/datums/xeno_shields/shield_types/vanguard_shield.dm @@ -42,7 +42,7 @@ return linked_xeno.overlay_shields() - var/datum/action/xeno_action/activable/cleave/cAction = get_xeno_action_by_type(linked_xeno, /datum/action/xeno_action/activable/cleave) + var/datum/action/xeno_action/activable/cleave/cAction = get_action(linked_xeno, /datum/action/xeno_action/activable/cleave) if (istype(cAction)) addtimer(CALLBACK(cAction, TYPE_PROC_REF(/datum/action/xeno_action/activable/cleave, remove_buff)), 7, TIMER_UNIQUE) diff --git a/code/game/camera_manager/camera_manager.dm b/code/game/camera_manager/camera_manager.dm index 9f111b0f8ec6..90e80ec7037e 100644 --- a/code/game/camera_manager/camera_manager.dm +++ b/code/game/camera_manager/camera_manager.dm @@ -6,7 +6,7 @@ /datum/component/camera_manager var/map_name var/obj/structure/machinery/camera/current - var/datum/shape/rectangle/current_area + var/datum/shape/current_area var/atom/movable/screen/map_view/cam_screen var/atom/movable/screen/background/cam_background var/list/range_turfs = list() @@ -86,7 +86,7 @@ RegisterSignal(parent, COMSIG_CAMERA_UNREGISTER_UI, PROC_REF(unregister)) RegisterSignal(parent, COMSIG_CAMERA_SET_NVG, PROC_REF(enable_nvg)) RegisterSignal(parent, COMSIG_CAMERA_CLEAR_NVG, PROC_REF(disable_nvg)) - RegisterSignal(parent, COMSIG_CAMERA_SET_AREA, PROC_REF(set_camera_rect)) + RegisterSignal(parent, COMSIG_CAMERA_SET_AREA, PROC_REF(set_camera_area)) RegisterSignal(parent, COMSIG_CAMERA_SET_TARGET, PROC_REF(set_camera)) RegisterSignal(parent, COMSIG_CAMERA_CLEAR, PROC_REF(clear_camera)) RegisterSignal(parent, COMSIG_CAMERA_REFRESH, PROC_REF(refresh_camera)) @@ -133,18 +133,18 @@ RegisterSignal(current, COMSIG_PARENT_QDELETING, PROC_REF(show_camera_static)) update_target_camera() -/datum/component/camera_manager/proc/set_camera_rect(source, x, y, z, w, h) +/datum/component/camera_manager/proc/set_camera_area(source, datum/shape/new_area, z) SIGNAL_HANDLER render_mode = RENDER_MODE_AREA if(current) UnregisterSignal(current, COMSIG_PARENT_QDELETING) current = null - current_area = RECT(x, y, w, h) - target_x = x - target_y = y + current_area = new_area + target_x = current_area.center_x + target_y = current_area.center_y target_z = z - target_width = w - target_height = h + target_width = current_area.bounds_x + target_height = current_area.bounds_y update_area_camera() /datum/component/camera_manager/proc/enable_nvg(source, power, matrixcol) @@ -221,8 +221,8 @@ // Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs. last_camera_turf = new_location - var/x_size = current_area.width - var/y_size = current_area.height + var/x_size = current_area.bounds_x + var/y_size = current_area.bounds_y var/turf/target = locate(current_area.center_x, current_area.center_y, target_z) var/list/visible_things = isXRay ? range("[x_size]x[y_size]", target) : view("[x_size]x[y_size]", target) diff --git a/code/game/machinery/computer/dropship_weapons.dm b/code/game/machinery/computer/dropship_weapons.dm index e07b415ed233..7f8f4f2b3850 100644 --- a/code/game/machinery/computer/dropship_weapons.dm +++ b/code/game/machinery/computer/dropship_weapons.dm @@ -313,9 +313,8 @@ var/obj/structure/machinery/defenses/sentry/defense = sentry.deployed_turret if(defense.has_camera) defense.set_range() - var/datum/shape/rectangle/current_bb = defense.range_bounds camera_area_equipment = sentry - SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, current_bb.center_x, current_bb.center_y, defense.loc.z, current_bb.width, current_bb.height) + SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, defense.range_bounds, defense.loc.z) return TRUE if("clear-camera") diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm index 7fbe39480999..3f8eff44d052 100644 --- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm +++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm @@ -349,6 +349,13 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Purple Armband", 6, /obj/item/clothing/accessory/armband/science, null, VENDOR_ITEM_REGULAR), list("Yellow Armband", 6, /obj/item/clothing/accessory/armband/engine, null, VENDOR_ITEM_REGULAR), list("Green Armband", 6, /obj/item/clothing/accessory/armband/medgreen, null, VENDOR_ITEM_REGULAR), + list("Blue Tie", 6, /obj/item/clothing/accessory/blue, null, VENDOR_ITEM_REGULAR), + list("Green Tie", 6, /obj/item/clothing/accessory/green, null, VENDOR_ITEM_REGULAR), + list("Black Tie", 6, /obj/item/clothing/accessory/black, null, VENDOR_ITEM_REGULAR), + list("Gold Tie", 6, /obj/item/clothing/accessory/gold, null, VENDOR_ITEM_REGULAR), + list("Red Tie", 6, /obj/item/clothing/accessory/red, null, VENDOR_ITEM_REGULAR), + list("Purple Tie", 6, /obj/item/clothing/accessory/purple, null, VENDOR_ITEM_REGULAR), + list("Stethoscope", 6, /obj/item/clothing/accessory/stethoscope, null, VENDOR_ITEM_REGULAR), list("Dress Gloves", 6, /obj/item/clothing/gloves/marine/dress, null, VENDOR_ITEM_REGULAR), )) diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index 10d4e8d098fb..34da5e3d2623 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -597,7 +597,7 @@ total_hits++ - var/datum/action/xeno_action/activable/boiler_trap/trap = get_xeno_action_by_type(linked_xeno, /datum/action/xeno_action/activable/boiler_trap) + var/datum/action/xeno_action/activable/boiler_trap/trap = get_action(linked_xeno, /datum/action/xeno_action/activable/boiler_trap) trap.reduce_cooldown(total_hits*4 SECONDS) diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm index 5da4704e0e78..3248115adfa8 100644 --- a/code/game/objects/items/devices/binoculars.dm +++ b/code/game/objects/items/devices/binoculars.dm @@ -403,6 +403,7 @@ COOLDOWN_START(designator, spotting_cooldown, 0) /datum/action/item_action/specialist/spotter_target/action_activate() + . = ..() if(!ishuman(owner)) return var/mob/living/carbon/human/human = owner diff --git a/code/game/objects/items/devices/helmet_visors.dm b/code/game/objects/items/devices/helmet_visors.dm index 8f921a62f3f5..e2005a841bc3 100644 --- a/code/game/objects/items/devices/helmet_visors.dm +++ b/code/game/objects/items/devices/helmet_visors.dm @@ -146,6 +146,7 @@ return /datum/action/item_action/view_publications/helmet_visor/action_activate() + . = ..() var/obj/item/device/helmet_visor/medical/advanced/medical_visor = locate() in holder_item if(!medical_visor) diff --git a/code/game/objects/items/devices/motion_detector.dm b/code/game/objects/items/devices/motion_detector.dm index 3551e3a02bef..dcbcc0dd8bc7 100644 --- a/code/game/objects/items/devices/motion_detector.dm +++ b/code/game/objects/items/devices/motion_detector.dm @@ -35,7 +35,7 @@ var/iff_signal = FACTION_MARINE actions_types = list(/datum/action/item_action) var/scanning = FALSE // controls if MD is in process of scan - var/datum/shape/rectangle/range_bounds + var/datum/shape/rectangle/square/range_bounds var/long_range_locked = FALSE //only long-range MD var/ping_overlay @@ -48,7 +48,7 @@ /obj/item/device/motiondetector/Initialize() . = ..() - range_bounds = new //Just creating a rectangle datum + range_bounds = new //Just creating a square datum update_icon() /obj/item/device/motiondetector/Destroy() @@ -215,12 +215,7 @@ if(!istype(cur_turf)) return - if(!range_bounds) - range_bounds = new/datum/shape/rectangle - range_bounds.center_x = cur_turf.x - range_bounds.center_y = cur_turf.y - range_bounds.width = detector_range * 2 - range_bounds.height = detector_range * 2 + range_bounds.set_shape(cur_turf.x, cur_turf.y, detector_range * 2) var/list/ping_candidates = SSquadtree.players_in_range(range_bounds, cur_turf.z, QTREE_EXCLUDE_OBSERVER | QTREE_SCAN_MOBS) diff --git a/code/game/objects/items/devices/walkman.dm b/code/game/objects/items/devices/walkman.dm index 42c03d757dbd..bef8e8f5ff79 100644 --- a/code/game/objects/items/devices/walkman.dm +++ b/code/game/objects/items/devices/walkman.dm @@ -269,6 +269,7 @@ button.name = name /datum/action/item_action/walkman/play_pause/action_activate() + . = ..() if(target) var/obj/item/device/walkman/WM = target WM.attack_self(owner) @@ -282,6 +283,7 @@ button.name = name /datum/action/item_action/walkman/next_song/action_activate() + . = ..() if(target) var/obj/item/device/walkman/WM = target WM.next_song(owner) @@ -295,6 +297,7 @@ button.name = name /datum/action/item_action/walkman/restart_song/action_activate() + . = ..() if(target) var/obj/item/device/walkman/WM = target WM.restart_song(owner) diff --git a/code/game/objects/items/hoverpack.dm b/code/game/objects/items/hoverpack.dm index 02a2d4be779a..65406eb15dc6 100644 --- a/code/game/objects/items/hoverpack.dm +++ b/code/game/objects/items/hoverpack.dm @@ -208,6 +208,7 @@ return TRUE /datum/action/item_action/hover/action_activate() + . = ..() var/mob/living/carbon/human/H = owner if(H.selected_ability == src) to_chat(H, "You will no longer use [name] with \ diff --git a/code/game/objects/items/reagent_containers/reagent_container.dm b/code/game/objects/items/reagent_containers/reagent_container.dm index 5207df4ca7bb..37029ff247d6 100644 --- a/code/game/objects/items/reagent_containers/reagent_container.dm +++ b/code/game/objects/items/reagent_containers/reagent_container.dm @@ -109,5 +109,6 @@ button.overlays += IMG /datum/action/item_action/reagent_container/set_transfer_amount/action_activate() + . = ..() var/obj/item/reagent_container/cont = holder_item cont.set_APTFT() diff --git a/code/game/objects/items/stacks/flags.dm b/code/game/objects/items/stacks/flags.dm index 484d2779f5f8..e032e2c80157 100644 --- a/code/game/objects/items/stacks/flags.dm +++ b/code/game/objects/items/stacks/flags.dm @@ -76,3 +76,206 @@ newflag.icon_state = "[newflag.base_state]_open" newflag.visible_message("[user] plants [newflag] firmly in the ground.") src.use(1) + + +/// PLANTABLE FLAG + +/obj/structure/flag/plantable + name = "flag" + desc = "A flag of something. This one looks like you could dismantle it." + icon = 'icons/obj/structures/plantable_flag.dmi' + pixel_x = 9 // All flags need to be offset to the right by 9 to be centered. + layer = ABOVE_XENO_LAYER + health = 150 + unacidable = TRUE + + /// The typepath for the flag item that gets spawned when the flag is taken down. + var/flag_type = /obj/item/flag/plantable + /// Used to limit the spam of the warcry_extra_sound + COOLDOWN_DECLARE(warcry_cooldown_struc) + +/obj/structure/flag/plantable/attack_hand(mob/user) + ..() + disassemble(user, flag_type) + +/// Proc for dismantling the flag into an item that can be picked up. +/obj/structure/flag/plantable/proc/disassemble(mob/user, flag_type) + if(user.action_busy) + return + + user.visible_message(SPAN_NOTICE("[user] starts taking [src] down..."), SPAN_NOTICE("You start taking [src] down...")) + + playsound(loc, 'sound/effects/flag_raising.ogg', 30) + if(!do_after(user, 6 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC)) + return + + playsound(loc, 'sound/effects/flag_raised.ogg', 30) + user.visible_message(SPAN_NOTICE("[user] starts takes [src] down!"), SPAN_NOTICE("You take [src] down!")) + var/obj/item/flag/plantable/flag_item = new flag_type(loc) + user.put_in_hands(flag_item) + COOLDOWN_START(flag_item, warcry_cooldown_item, COOLDOWN_TIMELEFT(src, warcry_cooldown_struc)) + qdel(src) + +/// Proc for when the flag gets forcefully dismantled (due to general damage, explosions, etc.) +/obj/structure/flag/plantable/proc/demolish(flag_type) + playsound(loc, 'sound/effects/flag_raised.ogg', 30) + visible_message(SPAN_WARNING("[src] crumples to the ground!")) + var/obj/item/flag/plantable/flag_item = new flag_type(loc) + COOLDOWN_START(flag_item, warcry_cooldown_item, COOLDOWN_TIMELEFT(src, warcry_cooldown_struc)) + qdel(src) + +// Procs for handling damage. +/obj/structure/flag/plantable/update_health(damage) + if(damage) + health -= damage + if(health <= 0) + demolish(flag_type) + +/obj/structure/flag/plantable/ex_act(severity) + if(health <= 0) + return + update_health(severity) + +/obj/structure/flag/plantable/attack_alien(mob/living/carbon/xenomorph/xeno) + if(xeno.a_intent == INTENT_HARM) + if(unslashable) + return + xeno.animation_attack_on(src) + playsound(loc, 'sound/effects/metalhit.ogg', 25, 1) + xeno.visible_message(SPAN_DANGER("[xeno] slashes [src]!"), SPAN_DANGER("We slash [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT) + update_health(rand(xeno.melee_damage_lower, xeno.melee_damage_upper)) + return XENO_ATTACK_ACTION + else + to_chat(xeno, SPAN_WARNING("We stare at [src] cluelessly.")) + return XENO_NONCOMBAT_ACTION + +/obj/structure/flag/plantable/bullet_act(obj/projectile/bullet) + bullet_ping(bullet) + visible_message(SPAN_DANGER("[src] is hit by [bullet]!"), null, 4, CHAT_TYPE_TAKING_HIT) + update_health(bullet.damage) + return TRUE + +/obj/structure/flag/plantable/attackby(obj/item/weapon, mob/living/user) + if(!indestructible) + visible_message(SPAN_DANGER("[src] has been hit by [user] with [weapon]!"), null, 5, CHAT_TYPE_MELEE_HIT) + user.animation_attack_on(src) + playsound(loc, 'sound/effects/metalhit.ogg', 25, 1) + update_health(weapon.force * weapon.demolition_mod) + +/obj/item/flag/plantable + name = "plantable flag" + desc = "A flag of something. This one looks ready to be planted into the ground." + w_class = SIZE_LARGE + throw_range = 2 + icon = 'icons/obj/structures/plantable_flag.dmi' + inhand_x_dimension = 64 + inhand_y_dimension = 64 + unacidable = TRUE + item_icons = list( + WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_64.dmi', + WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_64.dmi' + ) + + /// The typepath of the flag structure that gets spawned when the flag is planted. + var/flag_type = /obj/structure/flag/plantable + /// Used to check if nearby mobs belong to a faction when calculating for the stronger warcry. + var/faction + /// Does the flag play a unique warcry when planted? (Only while on harm intent.) + var/play_warcry = FALSE + /// The warcry's sound path. + var/warcry_sound + /// When there are more than 14 allies nearby, play this stronger warcry. + var/warcry_extra_sound + /// How many nearby allies do we need for the stronger warcry to be played? + var/allies_required = 14 + /// Used to limit the spam of the warcry_extra_sound + COOLDOWN_DECLARE(warcry_cooldown_item) + +/obj/item/flag/plantable/get_examine_text(mob/user) + . = ..() + if(play_warcry && user.faction == faction) + . += SPAN_NOTICE("Planting the flag while in HARM intent will cause you to bellow out a rallying warcry!") + +/// Proc for turning the flag item into a structure. +/obj/item/flag/plantable/proc/plant_flag(mob/living/user, play_warcry = FALSE, warcry_sound, warcry_extra_sound, faction) + if(user.action_busy) + return + + if(SSinterior.in_interior(user)) + to_chat(usr, SPAN_WARNING("There's no way to plant [src] in here!")) + return + + var/turf/turf_to_plant = get_step(user, user.dir) + if(istype(turf_to_plant, /turf/open)) + var/turf/open/floor = turf_to_plant + if(!floor.allow_construction || istype(floor, /turf/open/space)) + to_chat(user, SPAN_WARNING("You cannot deploy [src] here, find a more secure surface!")) + return + else + to_chat(user, SPAN_WARNING("[turf_to_plant] is blocking you from deploying [src]!")) + return + + for(var/obj/object in turf_to_plant) + if(object.density) + to_chat(usr, SPAN_WARNING("You need a clear, open area to plant [src], something is blocking the way in front of you!")) + return + + user.visible_message(SPAN_NOTICE("[user] starts planting [src] into the ground..."), SPAN_NOTICE("You start planting [src] into the ground...")) + playsound(user, 'sound/effects/flag_raising.ogg', 30) + if(!do_after(user, 6 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC)) + return + + user.visible_message(SPAN_NOTICE("[user] plants [src] into the ground!"), SPAN_NOTICE("You plant [src] into the ground!")) + var/obj/structure/flag/plantable/planted_flag = new flag_type(turf_to_plant) + + // If there are more than 14 allies nearby, play a stronger rallying cry. + // Otherwise, play the default warcry sound if there is one. If not, play a generic flag raising sfx. + if(play_warcry && user.faction == faction && user.a_intent == INTENT_HARM) + var/allies_nearby = 0 + if(COOLDOWN_FINISHED(src, warcry_cooldown_item)) + for (var/mob/living/carbon/human in orange(planted_flag, 7)) + if (human.is_dead() || human.faction != faction) + continue + allies_nearby++ + if (prob(40) && human != user) + human.emote("warcry") + + user.show_speech_bubble("warcry") + if(allies_nearby >= allies_required) + playsound(user, warcry_extra_sound, 40) + // Start a cooldown on the flag structure. This way we can keep track of the cooldown when the flag is hoisted and taken down. + COOLDOWN_START(planted_flag, warcry_cooldown_struc, 90 SECONDS) + user.manual_emote("shouts an invigorating rallying cry!") + else + playsound(user, warcry_sound, 30) + user.manual_emote("shouts an inspiring cry!") + // Ditto. If the cooldown isn't finished we have to transfer the leftover time to the structure. + COOLDOWN_START(planted_flag, warcry_cooldown_struc, COOLDOWN_TIMELEFT(src, warcry_cooldown_item)) + else + playsound(loc, 'sound/effects/flag_raised.ogg', 30) + + qdel(src) + +/obj/item/flag/plantable/attack_self(mob/user) + ..() + plant_flag(user, play_warcry, warcry_sound, warcry_extra_sound, faction) + +// UNITED AMERICAS FLAG // +////////////////////////// + +/obj/item/flag/plantable/ua + name = "\improper United Americas flag" + desc = "The flag of the United Americas. This one looks ready to be planted into the ground." + icon = 'icons/obj/structures/plantable_flag.dmi' + icon_state = "flag_ua" + flag_type = /obj/structure/flag/plantable/ua + faction = FACTION_MARINE + play_warcry = TRUE + warcry_sound = 'sound/effects/flag_warcry_ua.ogg' + warcry_extra_sound = 'sound/effects/flag_warcry_ua_extra.ogg' + +/obj/structure/flag/plantable/ua + name = "\improper United Americas flag" + desc = "The flag of the United Americas. Semper fi." + icon_state = "flag_ua_planted" + flag_type = /obj/item/flag/plantable/ua diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index baa91db19396..06636d2c3f76 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -268,6 +268,7 @@ return TRUE /datum/action/item_action/specialist/santabag/action_activate() + . = ..() var/obj/item/storage/backpack/santabag/santa_bag = holder_item santa_bag.refill_santa_bag(owner) update_button_icon() @@ -537,6 +538,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r button.overlays += IMG /datum/action/item_action/rto_pack/use_phone/action_activate() + . = ..() for(var/obj/item/storage/backpack/marine/satchel/rto/radio_backpack in owner) radio_backpack.use_phone(owner) return @@ -870,6 +872,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r return TRUE /datum/action/item_action/specialist/toggle_cloak/action_activate() + . = ..() var/obj/item/storage/backpack/marine/satchel/scout_cloak/SC = holder_item SC.camouflage() diff --git a/code/game/objects/items/storage/large_holster.dm b/code/game/objects/items/storage/large_holster.dm index 02983e1552ed..d8e1ee51d0d8 100644 --- a/code/game/objects/items/storage/large_holster.dm +++ b/code/game/objects/items/storage/large_holster.dm @@ -375,6 +375,7 @@ return TRUE /datum/action/item_action/specialist/toggle_fuel/action_activate() + . = ..() var/obj/item/storage/large_holster/fuelpack/FP = holder_item if (!istype(FP)) return diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index f93f2dab0984..2dc064aa86d4 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -416,7 +416,7 @@ var/offset_x = worn_x_dimension var/offset_y = worn_y_dimension - if(inhands) + if(inhands == 1 || inhands == 0) offset_x = inhand_x_dimension offset_y = inhand_y_dimension diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm index c3f0b97e509a..68b899f78f15 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm @@ -245,6 +245,7 @@ do_buckle(mob, user) ADD_TRAIT(mob, TRAIT_NESTED, TRAIT_SOURCE_BUCKLE) + ADD_TRAIT(mob, TRAIT_NO_STRAY, TRAIT_SOURCE_BUCKLE) SEND_SIGNAL(mob, COMSIG_MOB_NESTED, user) if(!human) @@ -275,6 +276,7 @@ buckled_mob.pixel_y = 0 buckled_mob.old_y = 0 REMOVE_TRAIT(buckled_mob, TRAIT_NESTED, TRAIT_SOURCE_BUCKLE) + REMOVE_TRAIT(buckled_mob, TRAIT_NO_STRAY, TRAIT_SOURCE_BUCKLE) var/mob/living/carbon/human/buckled_human = buckled_mob var/mob/dead/observer/G = ghost_of_buckled_mob diff --git a/code/game/objects/structures/vulture_spotter.dm b/code/game/objects/structures/vulture_spotter.dm index dc341edf0446..dcbfd88c9c08 100644 --- a/code/game/objects/structures/vulture_spotter.dm +++ b/code/game/objects/structures/vulture_spotter.dm @@ -313,6 +313,7 @@ tripod = WEAKREF(spotting_tripod) /datum/action/vulture_tripod_unscope/action_activate() + . = ..() if(!tripod) return diff --git a/code/game/turfs/transit.dm b/code/game/turfs/transit.dm index 00175ac5e365..5b4645805d3b 100644 --- a/code/game/turfs/transit.dm +++ b/code/game/turfs/transit.dm @@ -138,6 +138,12 @@ clear_active_explosives() ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_SOURCE_DROPSHIP_INTERACTION) ADD_TRAIT(src, TRAIT_UNDENSE, TRAIT_SOURCE_DROPSHIP_INTERACTION) + ADD_TRAIT(src, TRAIT_NO_STRAY, TRAIT_SOURCE_DROPSHIP_INTERACTION) + RegisterSignal(src, COMSIG_MOVABLE_FORCEMOVE_PRE_CROSSED, PROC_REF(cancel_cross)) + RegisterSignal(src, list( + COMSIG_LIVING_FLAMER_FLAMED, + COMSIG_LIVING_PREIGNITION + ), PROC_REF(cancel_fire)) var/image/cables = image('icons/obj/structures/droppod_32x64.dmi', src, "chute_cables_static") overlays += cables var/image/chute = image('icons/obj/structures/droppod_64x64.dmi', src, "chute_static") @@ -163,8 +169,18 @@ return REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_SOURCE_DROPSHIP_INTERACTION) REMOVE_TRAIT(src, TRAIT_UNDENSE, TRAIT_SOURCE_DROPSHIP_INTERACTION) + REMOVE_TRAIT(src, TRAIT_NO_STRAY, TRAIT_SOURCE_DROPSHIP_INTERACTION) + UnregisterSignal(src, list( + COMSIG_MOVABLE_FORCEMOVE_PRE_CROSSED, + COMSIG_LIVING_FLAMER_FLAMED, + COMSIG_LIVING_PREIGNITION + )) overlays -= cables overlays -= chute + for(var/atom/movable/atom in loc) + if(atom == src) + continue + atom.Cross(src) /atom/movable/proc/clear_active_explosives() for(var/obj/item/explosive/explosive in contents) @@ -232,6 +248,13 @@ death(last_damage_data) status_flags |= PERMANENTLY_DEAD +/atom/movable/proc/cancel_cross() + SIGNAL_HANDLER + return COMPONENT_IGNORE_CROSS + +/atom/movable/proc/cancel_fire() + SIGNAL_HANDLER + return COMPONENT_NO_BURN /turf/open/space/transit/dropship/alamo shuttle_tag = DROPSHIP_ALAMO diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 0b27cf268a12..e826b0b64767 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -367,6 +367,10 @@ retrieved_icon.Scale(128, 128) Insert("intents", retrieved_icon) + retrieved_icon = icon('icons/mob/xenos/predalien.dmi', "Normal Predalien Walking") + retrieved_icon.Scale(128, 128) + Insert("predalien", retrieved_icon) + return ..() diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index 7406e6baa754..6e086e651a10 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -40,6 +40,7 @@ return TRUE /datum/action/item_action/view_publications/action_activate() + . = ..() var/obj/item/clothing/glasses/hud/health/hud = holder_item hud.tgui_interact(owner) diff --git a/code/modules/clothing/glasses/night.dm b/code/modules/clothing/glasses/night.dm index b2b6f8406dcc..984a906eabed 100644 --- a/code/modules/clothing/glasses/night.dm +++ b/code/modules/clothing/glasses/night.dm @@ -184,6 +184,7 @@ button.overlays += image('icons/mob/hud/actions.dmi', button, action_icon_state) /datum/action/item_action/m56_goggles/far_sight/action_activate() + . = ..() if(target) var/obj/item/clothing/glasses/night/m56_goggles/G = target G.set_far_sight(owner, !G.far_sight) diff --git a/code/modules/clothing/suits/marine_armor/ghillie.dm b/code/modules/clothing/suits/marine_armor/ghillie.dm index 1f1b71227655..44729ac16b2f 100644 --- a/code/modules/clothing/suits/marine_armor/ghillie.dm +++ b/code/modules/clothing/suits/marine_armor/ghillie.dm @@ -150,6 +150,7 @@ return TRUE /datum/action/item_action/specialist/prepare_position/action_activate() + . = ..() var/obj/item/clothing/suit/storage/marine/ghillie/GS = holder_item GS.camouflage() diff --git a/code/modules/clothing/suits/marine_armor/intel.dm b/code/modules/clothing/suits/marine_armor/intel.dm index b3f0f93e004d..12aa824648d1 100644 --- a/code/modules/clothing/suits/marine_armor/intel.dm +++ b/code/modules/clothing/suits/marine_armor/intel.dm @@ -18,6 +18,7 @@ update_icon() /datum/action/item_action/intel/action_activate() + . = ..() if(!ishuman(owner)) return diff --git a/code/modules/clothing/suits/marine_armor/spec_fire.dm b/code/modules/clothing/suits/marine_armor/spec_fire.dm index 52343a204f68..c3f2863b3545 100644 --- a/code/modules/clothing/suits/marine_armor/spec_fire.dm +++ b/code/modules/clothing/suits/marine_armor/spec_fire.dm @@ -145,6 +145,7 @@ return TRUE /datum/action/item_action/specialist/fire_shield/action_activate() + . = ..() var/obj/item/clothing/suit/storage/marine/M35/armor = holder_item if (!istype(armor)) return diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm index c7353840d439..74cb5ea552ee 100644 --- a/code/modules/clothing/under/marine_uniform.dm +++ b/code/modules/clothing/under/marine_uniform.dm @@ -1210,6 +1210,7 @@ button.overlays += button_overlay /datum/action/item_action/specialist/toggle_cbrn_hood/action_activate() + . = ..() var/obj/item/clothing/under/marine/cbrn/armor = holder_item if(!istype(armor)) return diff --git a/code/modules/cm_aliens/structures/fruit.dm b/code/modules/cm_aliens/structures/fruit.dm index f555cac64b8c..b2a0fd27d65b 100644 --- a/code/modules/cm_aliens/structures/fruit.dm +++ b/code/modules/cm_aliens/structures/fruit.dm @@ -185,7 +185,7 @@ bound_xeno.current_fruits.Remove(src) var/number_of_fruit = length(bound_xeno.current_fruits) - var/datum/action/xeno_action/onclick/plant_resin_fruit/plant_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/plant_resin_fruit) + var/datum/action/xeno_action/onclick/plant_resin_fruit/plant_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/plant_resin_fruit) plant_action.button.set_maptext(SMALL_FONTS_COLOR(7, number_of_fruit, "#e69d00"), 19, 2) plant_action.update_button_icon() @@ -377,7 +377,7 @@ /obj/item/reagent_container/food/snacks/resin_fruit/proc/delete_fruit() if(bound_xeno) bound_xeno.current_fruits.Remove(src) - var/datum/action/xeno_action/onclick/plant_resin_fruit/prf = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/plant_resin_fruit) + var/datum/action/xeno_action/onclick/plant_resin_fruit/prf = get_action(bound_xeno, /datum/action/xeno_action/onclick/plant_resin_fruit) var/number_of_fruit = length(bound_xeno.current_fruits) prf.button.set_maptext(SMALL_FONTS_COLOR(7, number_of_fruit, "#e69d00"), 19, 2) prf.update_button_icon() diff --git a/code/modules/cm_aliens/structures/special/egg_morpher.dm b/code/modules/cm_aliens/structures/special/egg_morpher.dm index c4fb5c0a900c..ac501bb5c970 100644 --- a/code/modules/cm_aliens/structures/special/egg_morpher.dm +++ b/code/modules/cm_aliens/structures/special/egg_morpher.dm @@ -14,14 +14,14 @@ var/huggers_to_grow_max = 12 var/huggers_reserved = 0 var/mob/captured_mob - var/datum/shape/rectangle/range_bounds + var/datum/shape/range_bounds appearance_flags = KEEP_TOGETHER layer = FACEHUGGER_LAYER /obj/effect/alien/resin/special/eggmorph/Initialize(mapload, hive_ref) . = ..() - range_bounds = RECT(x, y, EGGMORPG_RANGE, EGGMORPG_RANGE) + range_bounds = SQUARE(x, y, EGGMORPG_RANGE) /obj/effect/alien/resin/special/eggmorph/Destroy() if (stored_huggers && linked_hive) @@ -158,7 +158,7 @@ /obj/effect/alien/resin/special/eggmorph/proc/check_facehugger_target() if(!range_bounds) - range_bounds = RECT(x, y, EGGMORPG_RANGE, EGGMORPG_RANGE) + range_bounds = SQUARE(x, y, EGGMORPG_RANGE) var/list/targets = SSquadtree.players_in_range(range_bounds, z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) if(isnull(targets) || !length(targets)) diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm index 5ba670d89bc1..951cd30f84ff 100644 --- a/code/modules/cm_marines/equipment/kit_boxes.dm +++ b/code/modules/cm_marines/equipment/kit_boxes.dm @@ -248,12 +248,9 @@ return TRUE /obj/item/spec_kit/proc/select_and_spawn(mob/living/carbon/human/user) - var/selection = tgui_input_list(user, "Pick your specialist equipment type.", "Specialist Kit Selection", GLOB.available_specialist_kit_boxes) + var/selection = tgui_input_list(user, "Pick your specialist equipment type.", "Specialist Kit Selection", GLOB.available_specialist_kit_boxes, 10 SECONDS) if(!selection || QDELETED(src)) return FALSE - if(!skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_TRAINED) && !skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL)) - to_chat(user, SPAN_WARNING("You already unwrapped your [name], give this one to someone else!")) - return if(!GLOB.available_specialist_kit_boxes[selection] || GLOB.available_specialist_kit_boxes[selection] <= 0) to_chat(user, SPAN_WARNING("No more kits of this type may be chosen!")) return FALSE @@ -299,6 +296,7 @@ user.put_in_hands(spec_box) card.set_assignment((user.assigned_squad && squad_assignment_update ? (user.assigned_squad.name + " ") : "") + card.assignment + " ([specialist_assignment])") GLOB.data_core.manifest_modify(user.real_name, WEAKREF(user), card.assignment) + GLOB.available_specialist_kit_boxes[selection]-- return TRUE return FALSE diff --git a/code/modules/cm_marines/equipment/mortar/mortar_shells.dm b/code/modules/cm_marines/equipment/mortar/mortar_shells.dm index dae0910cc9b4..1cb93c6a809e 100644 --- a/code/modules/cm_marines/equipment/mortar/mortar_shells.dm +++ b/code/modules/cm_marines/equipment/mortar/mortar_shells.dm @@ -167,23 +167,43 @@ return ..() /obj/item/mortar_shell/flamer_fire_act(dam, datum/cause_data/flame_cause_data) + addtimer(VARSET_CALLBACK(src, burning, FALSE), 5 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_DELETE_ME) + if(burning) return burning = TRUE cause_data = create_cause_data("Burning Mortar Shell", flame_cause_data.resolve_mob(), src) - handle_fire() + handle_fire(cause_data) -/obj/item/mortar_shell/proc/handle_fire() - visible_message(SPAN_WARNING("[src] catches on fire and starts cooking off! It's gonna blow!")) - anchored = TRUE // don't want other explosions launching it elsewhere +/obj/item/mortar_shell/proc/can_explode() + return TRUE - var/datum/effect_system/spark_spread/sparks = new() - sparks.set_up(n = 10, loca = loc) - sparks.start() - new /obj/effect/warning/explosive(loc, 5 SECONDS) +/obj/item/mortar_shell/custom/can_explode() + for(var/obj/item/reagent_container/glass/container in warhead?.containers) + for(var/datum/reagent/reagent in container?.reagents?.reagent_list) + if(reagent.explosive) + return TRUE - addtimer(CALLBACK(src, PROC_REF(detonate), loc), 5 SECONDS) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), (src)), 5.5 SECONDS) + return FALSE + +/obj/item/mortar_shell/flare/can_explode() + return FALSE + +/obj/item/mortar_shell/proc/handle_fire(cause_data) + if(can_explode()) + visible_message(SPAN_WARNING("[src] catches on fire and starts cooking off! It's gonna blow!")) + anchored = TRUE // don't want other explosions launching it elsewhere + var/datum/effect_system/spark_spread/sparks = new() + sparks.set_up(n = 10, loca = loc) + sparks.start() + new /obj/effect/warning/explosive(loc, 5 SECONDS) + + addtimer(CALLBACK(src, PROC_REF(explode), cause_data), 5 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), (src)), 5.5 SECONDS) + + +/obj/item/mortar_shell/proc/explode(flame_cause_data) + cell_explosion(src, 100, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, flame_cause_data) /obj/structure/closet/crate/secure/mortar_ammo name = "\improper M402 mortar ammo crate" diff --git a/code/modules/cm_preds/yaut_actions.dm b/code/modules/cm_preds/yaut_actions.dm index f55f58e0a557..0d260363ab15 100644 --- a/code/modules/cm_preds/yaut_actions.dm +++ b/code/modules/cm_preds/yaut_actions.dm @@ -49,6 +49,7 @@ return TRUE /datum/action/predator_action/action_activate() + . = ..() if(!can_use_action()) return FALSE @@ -248,6 +249,7 @@ action_icon_state = "looc_toggle" /datum/action/yautja_emote_panel/action_activate() + . = ..() var/mob/living/carbon/human/human_owner = owner var/datum/species/yautja/yautja_species = human_owner.species yautja_species.open_emote_panel() diff --git a/code/modules/cm_preds/yaut_bracers.dm b/code/modules/cm_preds/yaut_bracers.dm index 5577691d64c2..77efbb7ad4ef 100644 --- a/code/modules/cm_preds/yaut_bracers.dm +++ b/code/modules/cm_preds/yaut_bracers.dm @@ -556,7 +556,7 @@ set src in usr . = cloaker_internal(usr, FALSE) -/obj/item/clothing/gloves/yautja/hunter/proc/cloaker_internal(mob/caller, forced = FALSE) +/obj/item/clothing/gloves/yautja/hunter/proc/cloaker_internal(mob/caller, forced = FALSE, silent = FALSE, instant = FALSE) . = check_random_function(caller, forced) if(.) return @@ -600,15 +600,21 @@ M.see_invisible = SEE_INVISIBLE_LEVEL_ONE log_game("[key_name_admin(usr)] has enabled their cloaking device.") - M.visible_message(SPAN_WARNING("[M] vanishes into thin air!"), SPAN_NOTICE("You are now invisible to normal detection.")) - playsound(M.loc,'sound/effects/pred_cloakon.ogg', 15, 1) - animate(M, alpha = new_alpha, time = 1.5 SECONDS, easing = SINE_EASING|EASE_OUT) + if(!silent) + M.visible_message(SPAN_WARNING("[M] vanishes into thin air!"), SPAN_NOTICE("You are now invisible to normal detection.")) + playsound(M.loc,'sound/effects/pred_cloakon.ogg', 15, 1) + + if(!instant) + animate(M, alpha = new_alpha, time = 1.5 SECONDS, easing = SINE_EASING|EASE_OUT) + else + M.alpha = new_alpha var/datum/mob_hud/security/advanced/SA = GLOB.huds[MOB_HUD_SECURITY_ADVANCED] SA.remove_from_hud(M) var/datum/mob_hud/xeno_infection/XI = GLOB.huds[MOB_HUD_XENO_INFECTION] XI.remove_from_hud(M) - anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir) + if(!instant) + anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir) var/datum/action/predator_action/bracer/cloak/cloak_action for(cloak_action as anything in M.actions) @@ -634,6 +640,8 @@ if(!user) return + SEND_SIGNAL(src, COMSIG_PRED_BRACER_DECLOAKED) + UnregisterSignal(user, COMSIG_HUMAN_EXTINGUISH) UnregisterSignal(user, COMSIG_HUMAN_PRE_BULLET_ACT) UnregisterSignal(user, COMSIG_MOB_EFFECT_CLOAK_CANCEL) diff --git a/code/modules/cm_tech/hologram.dm b/code/modules/cm_tech/hologram.dm index 1fcba71a4560..1d85df9e49ad 100644 --- a/code/modules/cm_tech/hologram.dm +++ b/code/modules/cm_tech/hologram.dm @@ -102,6 +102,7 @@ GLOBAL_LIST_EMPTY_TYPED(hologram_list, /mob/hologram) var/mob/hologram/linked_hologram /datum/action/leave_hologram/action_activate() + . = ..() qdel(src) /datum/action/leave_hologram/Destroy() diff --git a/code/modules/cm_tech/implements/adv_weapon.dm b/code/modules/cm_tech/implements/adv_weapon.dm index 3cc8f1ceb4d6..f7b1008e0882 100644 --- a/code/modules/cm_tech/implements/adv_weapon.dm +++ b/code/modules/cm_tech/implements/adv_weapon.dm @@ -130,6 +130,7 @@ name = "Start Charging" /datum/action/item_action/techweb_railgun_start_charge/action_activate() + . = ..() if (target) var/obj/item/weapon/gun/rifle/techweb_railgun/TR = target TR.start_charging(owner) @@ -138,6 +139,7 @@ name = "Abort Charge" /datum/action/item_action/techweb_railgun_abort_charge/action_activate() + . = ..() if (target) var/obj/item/weapon/gun/rifle/techweb_railgun/TR = target TR.abort_charge(owner) diff --git a/code/modules/defenses/bell_tower.dm b/code/modules/defenses/bell_tower.dm index 68d58f02b481..7ce252b3f4d7 100644 --- a/code/modules/defenses/bell_tower.dm +++ b/code/modules/defenses/bell_tower.dm @@ -257,7 +257,7 @@ STOP_PROCESSING(SSobj, src) return - var/list/targets = SSquadtree.players_in_range(RECT(M.x, M.y, area_range, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) + var/list/targets = SSquadtree.players_in_range(SQUARE(M.x, M.y, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) if(!targets) return diff --git a/code/modules/defenses/planted_flag.dm b/code/modules/defenses/planted_flag.dm index d2b9b23e8f3b..d44f22f38b68 100644 --- a/code/modules/defenses/planted_flag.dm +++ b/code/modules/defenses/planted_flag.dm @@ -7,7 +7,7 @@ desc = "A planted flag with the iconic USCM flag plastered all over it, you feel a burst of energy by its mere sight." handheld_type = /obj/item/defenses/handheld/planted_flag disassemble_time = 10 - var/datum/shape/rectangle/range_bounds + var/datum/shape/range_bounds var/area_range = PLANTED_FLAG_RANGE var/buff_intensity = PLANTED_FLAG_BUFF health = 200 @@ -33,7 +33,7 @@ apply_area_effect() start_processing() - range_bounds = RECT(x, y, PLANTED_FLAG_RANGE, PLANTED_FLAG_RANGE) + range_bounds = SQUARE(x, y, PLANTED_FLAG_RANGE) update_icon() /obj/structure/machinery/defenses/planted_flag/Destroy() @@ -70,9 +70,9 @@ /obj/structure/machinery/defenses/planted_flag/proc/apply_area_effect() if(!range_bounds) - range_bounds = RECT(x, y, area_range, area_range) + range_bounds = SQUARE(x, y, area_range) - var/list/targets = SSquadtree.players_in_range(RECT(x, y, area_range, area_range), z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) + var/list/targets = SSquadtree.players_in_range(SQUARE(x, y, area_range), z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) if(!targets) return @@ -180,7 +180,7 @@ if(!M.x && !M.y && !M.z) return - var/list/targets = SSquadtree.players_in_range(RECT(M.x, M.y, area_range, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) + var/list/targets = SSquadtree.players_in_range(SQUARE(M.x, M.y, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) targets |= M for(var/mob/living/carbon/human/H in targets) diff --git a/code/modules/defenses/sentry.dm b/code/modules/defenses/sentry.dm index 695b3387d909..8ad4cd407e75 100644 --- a/code/modules/defenses/sentry.dm +++ b/code/modules/defenses/sentry.dm @@ -12,7 +12,7 @@ var/list/targets = list() // Lists of current potential targets var/list/other_targets = list() //List of special target types to shoot at, if needed. var/atom/movable/target = null - var/datum/shape/rectangle/range_bounds + var/datum/shape/range_bounds var/datum/effect_system/spark_spread/spark_system //The spark system, used for generating... sparks? var/last_fired = 0 var/fire_delay = 4 @@ -93,17 +93,17 @@ /obj/structure/machinery/defenses/sentry/proc/set_range() if(omni_directional) - range_bounds = RECT(x, y, 8, 8) + range_bounds = SQUARE(x, y, 8) return switch(dir) if(EAST) - range_bounds = RECT(x + 4, y, 7, 7) + range_bounds = SQUARE(x + 4, y, 7) if(WEST) - range_bounds = RECT(x - 4, y, 7, 7) + range_bounds = SQUARE(x - 4, y, 7) if(NORTH) - range_bounds = RECT(x, y + 4, 7, 7) + range_bounds = SQUARE(x, y + 4, 7) if(SOUTH) - range_bounds = RECT(x, y - 4, 7, 7) + range_bounds = SQUARE(x, y - 4, 7) /obj/structure/machinery/defenses/sentry/proc/unset_range() SIGNAL_HANDLER @@ -614,17 +614,17 @@ var/dbl_range = range * 2 if(omni_directional) - range_bounds = RECT(x, y, dbl_range, dbl_range) + range_bounds = SQUARE(x, y, dbl_range) return switch(dir) if(EAST) - range_bounds = RECT(x+range, y, dbl_range, dbl_range) + range_bounds = SQUARE(x+range, y, dbl_range) if(WEST) - range_bounds = RECT(x-range, y, dbl_range, dbl_range) + range_bounds = SQUARE(x-range, y, dbl_range) if(NORTH) - range_bounds = RECT(x, y+range, dbl_range, dbl_range) + range_bounds = SQUARE(x, y+range, dbl_range) if(SOUTH) - range_bounds = RECT(x, y-range, dbl_range, dbl_range) + range_bounds = SQUARE(x, y-range, dbl_range) //the turret inside the shuttle sentry deployment system /obj/structure/machinery/defenses/sentry/premade/dropship @@ -672,13 +672,13 @@ /obj/structure/machinery/defenses/sentry/dmr/set_range() switch(dir) if(EAST) - range_bounds = RECT(x + (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x + (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE) if(WEST) - range_bounds = RECT(x - (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x - (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE) if(NORTH) - range_bounds = RECT(x, y + (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y + (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE) if(SOUTH) - range_bounds = RECT(x, y - (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y - (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE) #undef SENTRY_SNIPER_RANGE /obj/structure/machinery/defenses/sentry/shotgun diff --git a/code/modules/defenses/sentry_computer.dm b/code/modules/defenses/sentry_computer.dm index 59c6409d552c..639a74e6ba30 100644 --- a/code/modules/defenses/sentry_computer.dm +++ b/code/modules/defenses/sentry_computer.dm @@ -402,8 +402,7 @@ var/obj/structure/machinery/defenses/sentry/defense = sentry if (defense.has_camera) defense.set_range() - var/datum/shape/rectangle/current_bb = defense.range_bounds - SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, current_bb.center_x, current_bb.center_y, defense.loc.z, current_bb.width, current_bb.height) + SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, defense.range_bounds, defense.loc.z) return TRUE if("ping") diff --git a/code/modules/defenses/sentry_flamer.dm b/code/modules/defenses/sentry_flamer.dm index 979d18eb41d1..2c5e9ae62677 100644 --- a/code/modules/defenses/sentry_flamer.dm +++ b/code/modules/defenses/sentry_flamer.dm @@ -90,13 +90,13 @@ /obj/structure/machinery/defenses/sentry/flamer/plasma/set_range() switch(dir) if(EAST) - range_bounds = RECT(x + (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x + (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE) if(WEST) - range_bounds = RECT(x - (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x - (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE) if(NORTH) - range_bounds = RECT(x, y + (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y + (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE) if(SOUTH) - range_bounds = RECT(x, y - (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y - (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE) #undef FLAMER_SENTRY_SNIPER_RANGE diff --git a/code/modules/gear_presets/_select_equipment.dm b/code/modules/gear_presets/_select_equipment.dm index 5311a7a79a3b..138e091ad5a4 100644 --- a/code/modules/gear_presets/_select_equipment.dm +++ b/code/modules/gear_presets/_select_equipment.dm @@ -138,6 +138,9 @@ new_human.set_languages(languages) /datum/equipment_preset/proc/load_preset(mob/living/carbon/human/new_human, randomise = FALSE, count_participant = FALSE, client/mob_client, show_job_gear = TRUE) + if(!new_human.hud_used) + new_human.create_hud() + load_race(new_human, mob_client) if(randomise || uses_special_name) load_name(new_human, randomise, mob_client) diff --git a/code/modules/mentor/looc_toggle.dm b/code/modules/mentor/looc_toggle.dm index 7c5b95b1fcb0..b224e72e79d2 100644 --- a/code/modules/mentor/looc_toggle.dm +++ b/code/modules/mentor/looc_toggle.dm @@ -13,6 +13,7 @@ // Called when the action is clicked on. /datum/action/looc_toggle/action_activate() + . = ..() if(owner.looc_overhead) button.icon_state = "template" owner.looc_overhead = FALSE diff --git a/code/modules/mob/camera/imaginary_friend.dm b/code/modules/mob/camera/imaginary_friend.dm index 4e7be80056de..0a4d5ee65c5c 100644 --- a/code/modules/mob/camera/imaginary_friend.dm +++ b/code/modules/mob/camera/imaginary_friend.dm @@ -280,6 +280,7 @@ action_icon_state = "joinmob" /datum/action/innate/imaginary_orbit/action_activate() + . = ..() var/mob/camera/imaginary_friend/friend = owner friend.recall() @@ -288,6 +289,7 @@ action_icon_state = "hidemob" /datum/action/innate/imaginary_hide/action_activate() + . = ..() var/mob/camera/imaginary_friend/friend = owner if(friend.hidden) friend.hidden = FALSE diff --git a/code/modules/mob/dead/observer/actions.dm b/code/modules/mob/dead/observer/actions.dm index 7daae802dc7a..192c6cd1e3b8 100644 --- a/code/modules/mob/dead/observer/actions.dm +++ b/code/modules/mob/dead/observer/actions.dm @@ -3,6 +3,7 @@ action_icon_state = "ghost" /datum/action/ghost/action_activate() + . = ..() if(!owner.client) return @@ -38,6 +39,7 @@ qdel(src) /datum/action/join_ert/action_activate() + . = ..() if(!owner.client) return @@ -50,6 +52,7 @@ listen_signal = COMSIG_KB_OBSERVER_JOIN_PREDATOR /datum/action/join_predator/action_activate() + . = ..() var/mob/dead/observer/activator = owner activator.join_as_yautja() @@ -58,6 +61,7 @@ action_icon_state = "view_crew_manifest" /datum/action/observer_action/view_crew_manifest/action_activate() + . = ..() show_browser(owner, GLOB.data_core.get_manifest(), "Crew Manifest", "manifest", "size=450x750") /datum/action/observer_action/view_hive_status @@ -65,6 +69,7 @@ action_icon_state = "view_hive_status" /datum/action/observer_action/view_hive_status/action_activate() + . = ..() var/mob/dead/observer/activator = owner activator.hive_status() @@ -74,6 +79,7 @@ listen_signal = COMSIG_KB_OBSERVER_JOIN_XENO /datum/action/observer_action/join_xeno/action_activate() + . = ..() if(!owner.client) return @@ -90,6 +96,7 @@ listen_signal = COMSIG_KB_OBSERVER_JOIN_LESSER_DRONE /datum/action/observer_action/join_lesser_drone/action_activate() + . = ..() if(!owner.client) return diff --git a/code/modules/mob/living/carbon/human/human_abilities.dm b/code/modules/mob/living/carbon/human/human_abilities.dm index 76ebbed06de6..9976fe37a4ff 100644 --- a/code/modules/mob/living/carbon/human/human_abilities.dm +++ b/code/modules/mob/living/carbon/human/human_abilities.dm @@ -20,6 +20,7 @@ cooldown = COMMAND_ORDER_COOLDOWN /datum/action/human_action/issue_order/action_activate() + . = ..() if(!ishuman(owner)) return var/mob/living/carbon/human/H = owner @@ -58,6 +59,7 @@ return FALSE /datum/action/human_action/smartpack/action_activate() + . = ..() if(!istype(owner, /mob/living/carbon/human)) return var/mob/living/carbon/human/H = owner @@ -129,6 +131,7 @@ CULT // Called when the action is clicked on. /datum/action/human_action/activable/action_activate() + . = ..() if(!ishuman(owner)) return var/mob/living/carbon/human/H = owner @@ -286,6 +289,7 @@ CULT action_icon_state = "cultist_channel_hivemind" /datum/action/human_action/activable/cult/speak_hivemind/action_activate() + . = ..() if(!can_use_action()) return @@ -316,6 +320,7 @@ CULT var/list/items_to_spawn = list(/obj/item/clothing/suit/cultist_hoodie/, /obj/item/clothing/head/cultist_hood/) /datum/action/human_action/activable/cult/obtain_equipment/action_activate() + . = ..() if(!can_use_action()) return @@ -515,6 +520,7 @@ CULT action_icon_state = "mutineer_begin" /datum/action/human_action/activable/mutineer/mutineer_begin/action_activate() + . = ..() if(!can_use_action()) return @@ -549,6 +555,7 @@ CULT UnregisterSignal(L, COMSIG_MOB_RESET_VIEW) /datum/action/human_action/cancel_view/action_activate() + . = ..() if(!can_use_action()) return @@ -575,6 +582,7 @@ CULT UnregisterSignal(L, COMSIG_MOB_RESET_VIEW) /datum/action/human_action/vehicle_unbuckle/action_activate() + . = ..() if(!can_use_action()) return @@ -600,6 +608,7 @@ CULT action_icon_state = "cancel_view" /datum/action/human_action/mg_exit/action_activate() + . = ..() if(!can_use_action()) return @@ -619,6 +628,7 @@ CULT UnregisterSignal(user, COMSIG_MOB_RESET_VIEW) /datum/action/human_action/toggle_arc_antenna/action_activate() + . = ..() if(!can_use_action()) return diff --git a/code/modules/mob/living/carbon/human/species/working_joe/_species.dm b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm index c032e25708eb..f2c0e8d4cf26 100644 --- a/code/modules/mob/living/carbon/human/species/working_joe/_species.dm +++ b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm @@ -50,6 +50,7 @@ /datum/action/joe_emote_panel/action_activate() + . = ..() if(!can_use_action()) return diff --git a/code/modules/mob/living/carbon/xenomorph/Embryo.dm b/code/modules/mob/living/carbon/xenomorph/Embryo.dm index d0890bd3cf37..61ba87cd001b 100644 --- a/code/modules/mob/living/carbon/xenomorph/Embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/Embryo.dm @@ -191,7 +191,7 @@ if(!picked) // Get a candidate from observers - var/list/candidates = get_alien_candidates(hive) + var/list/candidates = get_alien_candidates(hive, abomination = (isyautja(affected_mob) || (flags_embryo & FLAG_EMBRYO_PREDATOR))) if(candidates && length(candidates)) // If they were facehugged by a player thats still in queue, they get second dibs on the new larva. if(hugger_ckey) diff --git a/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm b/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm index 1fb48f699efa..3f37845380f0 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm @@ -18,6 +18,7 @@ return TRUE /datum/action/xeno_action/watch_xeno/action_activate() + . = ..() var/mob/living/carbon/xenomorph/X = owner if (!X.check_state(TRUE)) return FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index f0fd8a4d86a7..e7320b17c333 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -264,7 +264,7 @@ /mob/living/carbon/xenomorph/proc/pounced_mob(mob/living/L) // This should only be called back by a mob that has pounce, so no need to check - var/datum/action/xeno_action/activable/pounce/pounceAction = get_xeno_action_by_type(src, /datum/action/xeno_action/activable/pounce) + var/datum/action/xeno_action/activable/pounce/pounceAction = get_action(src, /datum/action/xeno_action/activable/pounce) // Unconscious or dead, or not throwing but used pounce. if(!check_state() || (!throwing && !pounceAction.action_cooldown_check())) @@ -336,7 +336,7 @@ pounced_mob(L) /mob/living/carbon/xenomorph/proc/pounced_obj(obj/O) - var/datum/action/xeno_action/activable/pounce/pounceAction = get_xeno_action_by_type(src, /datum/action/xeno_action/activable/pounce) + var/datum/action/xeno_action/activable/pounce/pounceAction = get_action(src, /datum/action/xeno_action/activable/pounce) // Unconscious or dead, or not throwing but used pounce if(!check_state() || (!throwing && !pounceAction.action_cooldown_check())) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index b07f766b179d..eed2dce5f7a8 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -343,6 +343,8 @@ var/atom/movable/vis_obj/xeno_wounds/wound_icon_holder var/atom/movable/vis_obj/xeno_pack/backpack_icon_holder + /// If TRUE, the xeno cannot slash anything + var/cannot_slash = FALSE /mob/living/carbon/xenomorph/Initialize(mapload, mob/living/carbon/xenomorph/old_xeno, hivenumber) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm index c749b0adb5ba..2431e4629876 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm @@ -108,7 +108,7 @@ var/mob/living/carbon/xenomorph/xeno = owner if(!action_cooldown_check()) // activate c/d only if we already spit for (var/action_type in action_types_to_cd) - var/datum/action/xeno_action/xeno_action = get_xeno_action_by_type(xeno, action_type) + var/datum/action/xeno_action/xeno_action = get_action(xeno, action_type) if (!istype(xeno_action)) continue @@ -149,7 +149,7 @@ to_chat(xeno, SPAN_XENOHIGHDANGER("We dump our acid through our pores, creating a shroud of gas!")) for (var/action_type in action_types_to_cd) - var/datum/action/xeno_action/xeno_action = get_xeno_action_by_type(xeno, action_type) + var/datum/action/xeno_action/xeno_action = get_action(xeno, action_type) if (!istype(xeno_action)) continue @@ -218,7 +218,7 @@ empowered = FALSE empowering_charge_counter = 0 button.overlays -= "+empowered" - var/datum/action/xeno_action/activable/acid_mine/mine = get_xeno_action_by_type(xeno, /datum/action/xeno_action/activable/acid_mine) + var/datum/action/xeno_action/activable/acid_mine/mine = get_action(xeno, /datum/action/xeno_action/activable/acid_mine) if(!mine.empowered) mine.empowered = TRUE mine.button.overlays += "+empowered" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm index e1af5e36a40f..1dd4dc5a1c87 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm @@ -82,7 +82,7 @@ // This ties the pounce/throwing backend into the old collision backend /mob/living/carbon/xenomorph/crusher/pounced_obj(obj/O) - var/datum/action/xeno_action/activable/pounce/crusher_charge/CCA = get_xeno_action_by_type(src, /datum/action/xeno_action/activable/pounce/crusher_charge) + var/datum/action/xeno_action/activable/pounce/crusher_charge/CCA = get_action(src, /datum/action/xeno_action/activable/pounce/crusher_charge) if (istype(CCA) && !CCA.action_cooldown_check() && !(O.type in CCA.not_reducing_objects)) CCA.reduce_cooldown(50) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm index d7a4f987623a..8736d612c822 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm @@ -183,6 +183,7 @@ return ..() /datum/action/xeno_action/activable/fortify/action_activate() + . = ..() ..() var/mob/living/carbon/xenomorph/xeno = owner if(xeno.fortify && xeno.selected_ability != src) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index c5988f12539d..b262624bfe01 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -485,6 +485,7 @@ listen_signal = COMSIG_KB_XENO_EVOLVE /datum/action/xeno_action/onclick/evolve/action_activate() + . = ..() var/mob/living/carbon/xenomorph/xeno = owner xeno.do_evolve() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm index 014cb3d2f24b..843cfeac540b 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm @@ -398,7 +398,7 @@ return if(X.layer == XENO_HIDING_LAYER) //Xeno is currently hiding, unhide him - var/datum/action/xeno_action/onclick/xenohide/hide = get_xeno_action_by_type(X, /datum/action/xeno_action/onclick/xenohide) + var/datum/action/xeno_action/onclick/xenohide/hide = get_action(X, /datum/action/xeno_action/onclick/xenohide) if(hide) hide.post_attack() @@ -911,7 +911,7 @@ to_chat(stabbing_xeno, SPAN_XENOWARNING("We must be above ground to do this.")) return - if(!stabbing_xeno.check_state()) + if(!stabbing_xeno.check_state() || stabbing_xeno.cannot_slash) return FALSE var/pre_result = pre_ability_act(stabbing_xeno, targetted_atom) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm index 094732300a1f..3c1d3a04543d 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm @@ -13,7 +13,7 @@ break if(found) - var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_xeno_action_by_type(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_action(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) if(lurker_invis) lurker_invis.invisibility_off() // Full cooldown diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm index 199df345fb62..4fe0e9107995 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm @@ -87,7 +87,7 @@ if(!X.check_state(1)) return - var/datum/action/xeno_action/activable/cleave/cAction = get_xeno_action_by_type(X, /datum/action/xeno_action/activable/cleave) + var/datum/action/xeno_action/activable/cleave/cAction = get_action(X, /datum/action/xeno_action/activable/cleave) if (!istype(cAction)) return @@ -328,7 +328,7 @@ if(!X.check_state(1)) return - var/datum/action/xeno_action/activable/warden_heal/WH = get_xeno_action_by_type(X, /datum/action/xeno_action/activable/warden_heal) + var/datum/action/xeno_action/activable/warden_heal/WH = get_action(X, /datum/action/xeno_action/activable/warden_heal) if (!istype(WH)) return diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm index 4d3a792af89a..3cbf0769514f 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm @@ -418,8 +418,8 @@ shake_camera(target_carbon, 2, 1) - var/datum/action/xeno_action/activable/prae_abduct/abduct_action = get_xeno_action_by_type(oppressor_user, /datum/action/xeno_action/activable/prae_abduct) - var/datum/action/xeno_action/activable/tail_lash/tail_lash_action = get_xeno_action_by_type(oppressor_user, /datum/action/xeno_action/activable/tail_lash) + var/datum/action/xeno_action/activable/prae_abduct/abduct_action = get_action(oppressor_user, /datum/action/xeno_action/activable/prae_abduct) + var/datum/action/xeno_action/activable/tail_lash/tail_lash_action = get_action(oppressor_user, /datum/action/xeno_action/activable/tail_lash) if(abduct_action && !abduct_action.action_cooldown_check()) abduct_action.reduce_cooldown(5 SECONDS) if(tail_lash_action && !tail_lash_action.action_cooldown_check()) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/predalien/predalien_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/predalien/predalien_powers.dm index 3ec4855f9c3a..a240c3928a3c 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/predalien/predalien_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/predalien/predalien_powers.dm @@ -117,7 +117,7 @@ xeno.anchored = FALSE unroot_human(carbon, TRAIT_SOURCE_ABILITY("Devastate")) - return ..() + return ..() /datum/action/xeno_action/onclick/feralrush/use_ability(atom/A) @@ -149,6 +149,7 @@ predatoralien.recalculate_armor() playsound(predatoralien, 'sound/voice/predalien_growl.ogg', 75, 0, status = 0) apply_cooldown() + return ..() /datum/action/xeno_action/onclick/feralrush/proc/remove_rush_effects() @@ -180,7 +181,7 @@ if(!xeno.check_state()) return - var/datum/action/xeno_action/activable/feralfrenzy/guttype = get_xeno_action_by_type(xeno, /datum/action/xeno_action/activable/feralfrenzy) + var/datum/action/xeno_action/activable/feralfrenzy/guttype = get_action(xeno, /datum/action/xeno_action/activable/feralfrenzy) if(!guttype) return @@ -248,7 +249,7 @@ else predalien_smash.visible_message(SPAN_XENOWARNING("[predalien_smash]'s claws twitch."), SPAN_XENOWARNING("We couldn't grab our target. Wait a moment to try again.")) - return TRUE + return ..() /mob/living/carbon/xenomorph/predalien/stop_pulling() if(isliving(pulling) && smashing) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm index 381acba92a51..6ef111aed66f 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm @@ -401,6 +401,7 @@ remove_personal_ally() if("Clear Personal Allies") clear_personal_allies() + return ..() /datum/action/xeno_action/onclick/manage_hive/proc/add_personal_ally() var/mob/living/carbon/xenomorph/queen/user_xeno = owner diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm index 80cf5c1e37ac..bff59186fd04 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm @@ -51,6 +51,7 @@ // Any strain or caste-specific state should be stored on behavior_delegate objects // which use_ability invocations can modify using typechecks and typecasts where appropriate. /datum/action/xeno_action/proc/use_ability(atom/target) + SHOULD_CALL_PARENT(TRUE) if(!owner) return FALSE track_xeno_ability_stats() @@ -129,10 +130,17 @@ /// A wrapper for use_ability that sends a signal /datum/action/xeno_action/proc/use_ability_wrapper(...) // TODO: make hidden a part of can_use_action - if(!hidden && can_use_action() && use_ability(arglist(args))) + if(!can_use_action()) + SEND_SIGNAL(src, COMSIG_XENO_FAILED_ACTION_USED, owner) + return FALSE + + SEND_SIGNAL(src, COMSIG_XENO_PRE_ACTION_USED, owner) + + if(!hidden && use_ability(arglist(args))) SEND_SIGNAL(src, COMSIG_XENO_ACTION_USED, owner) return TRUE + SEND_SIGNAL(src, COMSIG_XENO_FAILED_ACTION_USED, owner) return FALSE // For actions that do something on each life tick @@ -150,6 +158,7 @@ // For non-activable Xeno actions, this is used to // actually DO the action. /datum/action/xeno_action/activable/action_activate() + . = ..() if(!owner) return if(hidden) @@ -201,6 +210,7 @@ no_cooldown_msg = TRUE /datum/action/xeno_action/onclick/action_activate() + . = ..() use_ability_wrapper(null) // Adds a cooldown to this @@ -362,17 +372,6 @@ deltimer(charge_timer_id) charge_timer_id = TIMER_ID_NULL -// Helper proc to get an action on a target Xeno by type. -// Used to interact with abilities from the outside -/proc/get_xeno_action_by_type(mob/living/carbon/xenomorph/X, typepath) - if (!istype(X)) - CRASH("xeno_action.dm: get_xeno_action_by_type invoked with non-xeno first argument.") - - for (var/datum/action/xeno_action/XA in X.actions) - if (istype(XA, typepath)) - return XA - return null - // Helper proc to check if there is anything blocking the way from mob M to the atom A // Max distance can be supplied to check some of the way instead of the whole way. /proc/check_clear_path_to_target(mob/M, atom/A, smash_windows = TRUE, max_distance = 1000) @@ -420,6 +419,7 @@ return FALSE /datum/action/xeno_action/active_toggle/action_activate() + . = ..() toggle_toggle() /datum/action/xeno_action/active_toggle/life_tick() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index 24ac22d6bc52..a84b9965f9c3 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -261,11 +261,11 @@ H.apply_armoured_damage(get_xeno_damage_slash(H, damage), ARMOR_MELEE, BRUTE, bound_xeno.zone_selected) - var/datum/action/xeno_action/activable/pounce/crusher_charge/cAction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/pounce/crusher_charge) + var/datum/action/xeno_action/activable/pounce/crusher_charge/cAction = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/crusher_charge) if (!cAction.action_cooldown_check()) cAction.reduce_cooldown(cdr_amount) - var/datum/action/xeno_action/onclick/crusher_shield/sAction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/crusher_shield) + var/datum/action/xeno_action/onclick/crusher_shield/sAction = get_action(bound_xeno, /datum/action/xeno_action/onclick/crusher_shield) if (!sAction.action_cooldown_check()) sAction.reduce_cooldown(base_cdr_amount) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm index 93d40820bf7b..7df87f63cf3a 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm @@ -136,6 +136,6 @@ /datum/behavior_delegate/hellhound_base/melee_attack_additional_effects_self() ..() - var/datum/action/xeno_action/onclick/xenohide/hide = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/xenohide) + var/datum/action/xeno_action/onclick/xenohide/hide = get_action(bound_xeno, /datum/action/xeno_action/onclick/xenohide) if(hide) hide.post_attack() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index 0ab9e9862b16..1dca7eb23f70 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -87,7 +87,7 @@ original_damage *= buffed_slash_damage_ratio target_carbon.set_effect(get_xeno_stun_duration(target_carbon, 3), SUPERSLOW) next_slash_buffed = FALSE - var/datum/action/xeno_action/onclick/lurker_assassinate/ability = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/lurker_assassinate) + var/datum/action/xeno_action/onclick/lurker_assassinate/ability = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_assassinate) if (ability) ability.button.icon_state = "template" @@ -114,19 +114,19 @@ /datum/behavior_delegate/lurker_base/melee_attack_additional_effects_self() ..() - var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) if (lurker_invis_action) lurker_invis_action.invisibility_off() // Full cooldown /datum/behavior_delegate/lurker_base/proc/decloak_handler(mob/source) SIGNAL_HANDLER - var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) if(istype(lurker_invis_action)) lurker_invis_action.invisibility_off(0.5) // Partial refund of remaining time /// Implementation for enabling invisibility. /datum/behavior_delegate/lurker_base/proc/on_invisibility() - var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/pounce/lurker) + var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/lurker) if(lurker_pounce_action) lurker_pounce_action.knockdown = TRUE // pounce knocks down lurker_pounce_action.freeze_self = TRUE @@ -137,7 +137,7 @@ /// Implementation for disabling invisibility. /datum/behavior_delegate/lurker_base/proc/on_invisibility_off() - var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/pounce/lurker) + var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/lurker) if(lurker_pounce_action) lurker_pounce_action.knockdown = FALSE // pounce no longer knocks down lurker_pounce_action.freeze_self = FALSE @@ -155,7 +155,7 @@ . += "Invisibility Remaining: [time_left] second\s." return - var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invisibility_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invisibility_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) if(!lurker_invisibility_action) return @@ -177,7 +177,7 @@ if(!bound_xeno || !bound_xeno.stealth) return - var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invisibility_action = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invisibility_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility) if(!lurker_invisibility_action) return diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm index 830f4fc5a9cf..b60f150c442d 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm @@ -69,16 +69,19 @@ weed_food_states = list("Predalien_1","Predalien_2","Predalien_3") weed_food_states_flipped = list("Predalien_1","Predalien_2","Predalien_3") var/smashing = FALSE + /// If the pred alert/player notif should happen when the predalien spawns + var/should_announce_spawn = TRUE /mob/living/carbon/xenomorph/predalien/Initialize(mapload, mob/living/carbon/xenomorph/oldxeno, h_number) . = ..() - addtimer(CALLBACK(src, PROC_REF(announce_spawn)), 3 SECONDS) - hunter_data.dishonored = TRUE - hunter_data.dishonored_reason = "An abomination upon the honor of us all!" - hunter_data.dishonored_set = src - hud_set_hunter() + if(should_announce_spawn) + addtimer(CALLBACK(src, PROC_REF(announce_spawn)), 3 SECONDS) + hunter_data.dishonored = TRUE + hunter_data.dishonored_reason = "An abomination upon the honor of us all!" + hunter_data.dishonored_set = src + hud_set_hunter() AddComponent(/datum/component/footstep, 4, 25, 11, 2, "alien_footstep_medium") @@ -102,8 +105,20 @@ You must still listen to the queen. /mob/living/carbon/xenomorph/predalien/resist_fire() - ..() - SetKnockDown(0.1 SECONDS) + ..() + SetKnockDown(0.1 SECONDS) + +/mob/living/carbon/xenomorph/predalien/get_examine_text(mob/user) + . = ..() + var/datum/behavior_delegate/predalien_base/predalienkills = behavior_delegate + . += "It has [predalienkills.kills] kills to its name!" + +/mob/living/carbon/xenomorph/predalien/tutorial + should_announce_spawn = FALSE + +/mob/living/carbon/xenomorph/predalien/tutorial/gib(datum/cause_data/cause = create_cause_data("gibbing", src)) + death(cause, gibbed = TRUE) + /datum/behavior_delegate/predalien_base name = "Base Predalien Behavior Delegate" @@ -127,12 +142,3 @@ You must still listen to the queen. original_damage *= 1.5 return original_damage + kills * 2.5 - -/mob/living/carbon/xenomorph/predalien/get_examine_text(mob/user) - . = ..() - var/datum/behavior_delegate/predalien_base/predalienkills = behavior_delegate - var/kills = predalienkills.kills - . += "It has [kills] kills to its name!" - - - diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index 6e5da79fbed1..90614e338071 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm @@ -90,7 +90,7 @@ /datum/behavior_delegate/ravager_base/melee_attack_additional_effects_self() ..() - var/datum/action/xeno_action/activable/pounce/charge/cAction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/pounce/charge) + var/datum/action/xeno_action/activable/pounce/charge/cAction = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/charge) if (!cAction.action_cooldown_check()) cAction.reduce_cooldown(slash_charge_cdr) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index 8721294173e9..12fdb8d02843 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -91,6 +91,6 @@ /datum/behavior_delegate/runner_base/melee_attack_additional_effects_self() ..() - var/datum/action/xeno_action/onclick/xenohide/hide = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/xenohide) + var/datum/action/xeno_action/onclick/xenohide/hide = get_action(bound_xeno, /datum/action/xeno_action/onclick/xenohide) if(hide) hide.post_attack() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm index 01963496f967..3e7416f39fc5 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm @@ -95,7 +95,7 @@ addtimer(CALLBACK(src, PROC_REF(paralyzing_slash), carbon_target), NEURO_TOUCH_DELAY) next_slash_buffed = FALSE if(!next_slash_buffed) - var/datum/action/xeno_action/onclick/paralyzing_slash/ability = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/paralyzing_slash) + var/datum/action/xeno_action/onclick/paralyzing_slash/ability = get_action(bound_xeno, /datum/action/xeno_action/onclick/paralyzing_slash) if (ability && istype(ability)) ability.button.icon_state = "template" return original_damage diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm b/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm index 360b4e8bbdde..eca88761ad9b 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm @@ -201,7 +201,7 @@ if(xenoSrc.stat == DEAD) return - var/datum/action/xeno_action/A = get_xeno_action_by_type(xenoSrc, /datum/action/xeno_action/activable/queen_give_plasma) + var/datum/action/xeno_action/A = get_action(xenoSrc, /datum/action/xeno_action/activable/queen_give_plasma) A?.use_ability_wrapper(xenoTarget) if("heal") @@ -214,7 +214,7 @@ if(xenoSrc.stat == DEAD) return - var/datum/action/xeno_action/A = get_xeno_action_by_type(xenoSrc, /datum/action/xeno_action/activable/queen_heal) + var/datum/action/xeno_action/A = get_action(xenoSrc, /datum/action/xeno_action/activable/queen_heal) A?.use_ability_wrapper(xenoTarget, TRUE) if("overwatch") diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm index f64bfd6b500f..857a76969354 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm @@ -73,7 +73,7 @@ found = trap break - var/datum/action/xeno_action/activable/boiler_trap/trap_ability = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/boiler_trap) + var/datum/action/xeno_action/activable/boiler_trap/trap_ability = get_action(bound_xeno, /datum/action/xeno_action/activable/boiler_trap) if (found) target_human.apply_armoured_damage(bonus_damage_shotgun_trapped, ARMOR_BIO, BURN) trap_ability.empowering_charge_counter = trap_ability.empower_charge_max diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm index 5ebafc88eaef..7ceaf2fed75e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -276,9 +276,10 @@ addtimer(CALLBACK(xeno.hive, TYPE_PROC_REF(/datum/hive_status, free_respawn), xeno.client), 5 SECONDS) xeno.gib(create_cause_data("sacrificing itself", src)) + return ..() /datum/action/xeno_action/activable/healer_sacrifice/action_activate() - ..() + . = ..() var/mob/living/carbon/xenomorph/xeno = owner if(xeno.selected_ability != src) return diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm index 747463eb5ee5..89737f9ff595 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm @@ -43,19 +43,20 @@ name = "Coerce Resin (100)" action_icon_state = "secrete_resin" ability_name = "coerce resin" - var/last_use = 0 xeno_cooldown = 1 SECONDS thick = FALSE make_message = FALSE no_cooldown_msg = TRUE - var/care_about_adjacency = TRUE build_speed_mod = 2 // the actual building part takes twice as long macro_path = /datum/action/xeno_action/verb/verb_coerce_resin action_type = XENO_ACTION_CLICK + var/last_use = 0 + var/care_about_adjacency = TRUE + /datum/action/xeno_action/activable/secrete_resin/remote/use_ability(atom/target_atom, mods) if(!can_remote_build()) to_chat(owner, SPAN_XENONOTICE("We must be standing on weeds to establish a connection to the resin.")) @@ -70,8 +71,8 @@ var/turf/target_turf = get_turf(target_atom) if(!target_turf) return - - if(!(target_turf in view(10, owner))) + + if(care_about_adjacency && !(target_turf in view(10, owner))) to_chat(owner, SPAN_XENONOTICE("We must have a direct line of sight!")) return diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm index 310db35ab370..01f567398c44 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm @@ -54,7 +54,7 @@ last_combat_time = world.time /datum/behavior_delegate/praetorian_vanguard/proc/next_pierce_spin() - var/datum/action/xeno_action/activable/pierce/pAction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/pierce) + var/datum/action/xeno_action/activable/pierce/pAction = get_action(bound_xeno, /datum/action/xeno_action/activable/pierce) if (istype(pAction)) pAction.should_spin_instead = TRUE @@ -62,7 +62,7 @@ return /datum/behavior_delegate/praetorian_vanguard/proc/next_pierce_normal() - var/datum/action/xeno_action/activable/pierce/pAction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/pierce) + var/datum/action/xeno_action/activable/pierce/pAction = get_action(bound_xeno, /datum/action/xeno_action/activable/pierce) if (istype(pAction)) pAction.should_spin_instead = FALSE return @@ -88,6 +88,6 @@ new_shield.explosive_armor_amount = 1.5*XENO_EXPOSIVEARMOR_MOD_VERY_LARGE to_chat(praetorian, SPAN_XENOHIGHDANGER("We feel our defensive shell regenerate! It will block one hit!")) - var/datum/action/xeno_action/activable/cleave/caction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/cleave) + var/datum/action/xeno_action/activable/cleave/caction = get_action(bound_xeno, /datum/action/xeno_action/activable/cleave) if (istype(caction)) caction.buffed = TRUE diff --git a/code/modules/movement/movement.dm b/code/modules/movement/movement.dm index e12a5b439296..8151d2df6707 100644 --- a/code/modules/movement/movement.dm +++ b/code/modules/movement/movement.dm @@ -140,11 +140,11 @@ destination.Entered(src, oldloc) if(destarea && (old_area != destarea || !isturf(oldloc))) destarea.Entered(src, oldloc) - - for(var/atom/movable/AM in destination) - if(AM == src) - continue - AM.Crossed(src, oldloc) + if(!(SEND_SIGNAL(src, COMSIG_MOVABLE_FORCEMOVE_PRE_CROSSED) & COMPONENT_IGNORE_CROSS)) + for(var/atom/movable/AM in destination) + if(AM == src) + continue + AM.Crossed(src, oldloc) Moved(oldloc, NONE, TRUE) . = TRUE diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index f7ffbf2875e2..d16f1b6fdd30 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -427,6 +427,10 @@ SEND_SIGNAL(src, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) /obj/item/weapon/gun/proc/handle_random_attachments() + #ifdef AUTOWIKI // no randomness for my gun pictures, please + return + #endif + var/attachmentchoice var/randchance = random_spawn_chance diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 7d015e4bac8d..e2108364e9ac 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -1054,6 +1054,7 @@ Defined in conflicts.dm of the #defines folder. button.name = name /datum/action/item_action/toggle_zoom_level/action_activate() + . = ..() var/obj/item/weapon/gun/G = holder_item var/obj/item/attachable/scope/variable_zoom/S = G.attachments["rail"] S.toggle_zoom_level() @@ -1674,6 +1675,7 @@ Defined in conflicts.dm of the #defines folder. /datum/action/item_action/vulture /datum/action/item_action/vulture/action_activate() + . = ..() var/obj/item/weapon/gun/gun_holder = holder_item var/obj/item/attachable/vulture_scope/scope = gun_holder.attachments["rail"] if(!istype(scope)) @@ -3515,6 +3517,7 @@ Defined in conflicts.dm of the #defines folder. button.overlays += image('icons/mob/hud/actions.dmi', button, action_icon_state) /datum/action/item_action/bipod/toggle_full_auto_switch/action_activate() + . = ..() var/obj/item/weapon/gun/holder_gun = holder_item var/obj/item/attachable/bipod/attached_bipod = holder_gun.attachments["under"] diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index b2ec3dea63ce..717914e38eba 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -268,6 +268,7 @@ /datum/action/item_action/taser/action_activate() + . = ..() var/obj/item/weapon/gun/energy/taser/taser = holder_item if(!ishuman(owner)) return diff --git a/code/modules/projectiles/guns/lever_action.dm b/code/modules/projectiles/guns/lever_action.dm index a8fb78f72a9c..179ce8d787d0 100644 --- a/code/modules/projectiles/guns/lever_action.dm +++ b/code/modules/projectiles/guns/lever_action.dm @@ -378,7 +378,6 @@ their unique feature is that a direct hit will buff your damage and firerate /obj/item/attachable/bayonet/upp, // Barrel /obj/item/attachable/bayonet, /obj/item/attachable/extended_barrel, - /obj/item/attachable/heavy_barrel, /obj/item/attachable/suppressor, /obj/item/attachable/compensator, /obj/item/attachable/reddot, // Rail @@ -393,9 +392,9 @@ their unique feature is that a direct hit will buff your damage and firerate /obj/item/weapon/gun/lever_action/xm88/set_gun_config_values() ..() - set_fire_delay(FIRE_DELAY_TIER_2) + set_fire_delay(FIRE_DELAY_TIER_2 + FIRE_DELAY_TIER_11) lever_delay = FIRE_DELAY_TIER_3 - accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 + accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_2 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_8 burst_scatter_mult = 0 diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index ad85220400fb..fbe24434d542 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -557,6 +557,7 @@ //---ability actions--\\ /datum/action/item_action/m46c/action_activate() + . = ..() var/obj/item/weapon/gun/rifle/m46c/protag_gun = holder_item if(!ishuman(owner)) return diff --git a/code/modules/projectiles/guns/shotguns.dm b/code/modules/projectiles/guns/shotguns.dm index b1b3bb3c2ab4..a0bb3f8f852c 100644 --- a/code/modules/projectiles/guns/shotguns.dm +++ b/code/modules/projectiles/guns/shotguns.dm @@ -838,6 +838,7 @@ can cause issues with ammo types getting mixed up during the burst. return TRUE /datum/action/item_action/specialist/twobore_brace/action_activate() + . = ..() var/obj/item/weapon/gun/shotgun/double/twobore/G = holder_item if(G.braced) return diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index e5c9fff3a126..7c628463b1ef 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -178,6 +178,7 @@ //---ability actions--\\ /datum/action/item_action/smartgun/action_activate() + . = ..() var/obj/item/weapon/gun/smartgun/G = holder_item if(!ishuman(owner)) return @@ -595,6 +596,7 @@ // ID lock action \\ /datum/action/item_action/co_sg/action_activate() + . = ..() var/obj/item/weapon/gun/smartgun/co/protag_gun = holder_item if(!ishuman(owner)) return diff --git a/code/modules/projectiles/guns/smgs.dm b/code/modules/projectiles/guns/smgs.dm index 69fd5d968750..466a09612c54 100644 --- a/code/modules/projectiles/guns/smgs.dm +++ b/code/modules/projectiles/guns/smgs.dm @@ -168,7 +168,8 @@ /obj/item/attachable/lasersight, // Under /obj/item/attachable/gyro, /obj/item/attachable/bipod, - /obj/item/attachable/burstfire_assembly + /obj/item/attachable/burstfire_assembly, + /obj/item/attachable/attached_gun/grenade/m203, ) flags_gun_features = GUN_CAN_POINTBLANK|GUN_ANTIQUE @@ -192,6 +193,13 @@ damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_4 recoil_unwielded = RECOIL_AMOUNT_TIER_5 +/obj/item/weapon/gun/smg/mp5/Initialize(mapload, spawn_empty) + . = ..() + if(prob(10)) + var/obj/item/attachable/attached_gun/grenade/m203/UGL = new(src) + UGL.Attach(src) + update_attachable(UGL.slot) + //------------------------------------------------------- //MP27, based on the MP27, based on the M7. diff --git a/code/modules/projectiles/guns/specialist/launcher/grenade_launcher.dm b/code/modules/projectiles/guns/specialist/launcher/grenade_launcher.dm index e2643c580a16..06ac5428bfc6 100644 --- a/code/modules/projectiles/guns/specialist/launcher/grenade_launcher.dm +++ b/code/modules/projectiles/guns/specialist/launcher/grenade_launcher.dm @@ -222,6 +222,7 @@ update_icon() /datum/action/item_action/toggle_firing_level/action_activate() + . = ..() var/obj/item/weapon/gun/launcher/grenade/G = holder_item if(!ishuman(owner)) return diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index b40477a8a460..b400350e415b 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -62,6 +62,7 @@ ACTIONS SPECIALSIT SNIPER CAN TAKE */ /datum/action/item_action/specialist/aimed_shot/action_activate() + . = ..() if(!ishuman(owner)) return var/mob/living/carbon/human/H = owner @@ -276,6 +277,7 @@ return TRUE /datum/action/item_action/specialist/toggle_laser/action_activate() + . = ..() var/obj/item/weapon/gun/rifle/sniper/sniper_rifle = holder_item if(owner.get_held_item() != sniper_rifle) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 0e335aa81da3..d91e2ca47c1a 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -841,8 +841,8 @@ //mobs use get_projectile_hit_chance instead of get_projectile_hit_boolean /mob/living/proc/get_projectile_hit_chance(obj/projectile/P) - if((body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_NESTED)) && src != P.original) - return FALSE // Snowflake check for xeno nests, because we want bullets to fly through even though they're standing in it + if((body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_NO_STRAY)) && src != P.original) + return FALSE var/ammo_flags = P.ammo.flags_ammo_behavior | P.projectile_override_flags if(ammo_flags & AMMO_XENO) if((status_flags & XENO_HOST) && HAS_TRAIT(src, TRAIT_NESTED)) diff --git a/code/modules/shuttle/computers/dropship_computer.dm b/code/modules/shuttle/computers/dropship_computer.dm index 08a35b83071d..a28f65ce475d 100644 --- a/code/modules/shuttle/computers/dropship_computer.dm +++ b/code/modules/shuttle/computers/dropship_computer.dm @@ -314,7 +314,7 @@ var/original_evilution = hive.evolution_bonus hive.override_evilution(XENO_HIJACK_EVILUTION_BUFF, TRUE) if(hive.living_xeno_queen) - var/datum/action/xeno_action/onclick/grow_ovipositor/ovi_ability = get_xeno_action_by_type(hive.living_xeno_queen, /datum/action/xeno_action/onclick/grow_ovipositor) + var/datum/action/xeno_action/onclick/grow_ovipositor/ovi_ability = get_action(hive.living_xeno_queen, /datum/action/xeno_action/onclick/grow_ovipositor) ovi_ability.reduce_cooldown(ovi_ability.xeno_cooldown) addtimer(CALLBACK(hive, TYPE_PROC_REF(/datum/hive_status, override_evilution), original_evilution, FALSE), XENO_HIJACK_EVILUTION_TIME) diff --git a/code/modules/surgery/surgery_toggle.dm b/code/modules/surgery/surgery_toggle.dm index b9ca3ca93311..973d1c5b682f 100644 --- a/code/modules/surgery/surgery_toggle.dm +++ b/code/modules/surgery/surgery_toggle.dm @@ -18,6 +18,7 @@ // Called when the action is clicked on. /datum/action/surgery_toggle/action_activate() + . = ..() if(owner.mob_flags & SURGERY_MODE_ON) button.icon_state = "template" owner.mob_flags &= ~SURGERY_MODE_ON diff --git a/colonialmarines.dme b/colonialmarines.dme index b479f0af62c5..254cbb0112ca 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -698,6 +698,7 @@ #include "code\datums\tutorial\ss13\basic_ss13.dm" #include "code\datums\tutorial\ss13\intents.dm" #include "code\datums\tutorial\xenomorph\_xenomorph.dm" +#include "code\datums\tutorial\xenomorph\abomination.dm" #include "code\datums\tutorial\xenomorph\xenomorph_basic.dm" #include "code\datums\weather\weather_event.dm" #include "code\datums\weather\weather_map_holder.dm" diff --git a/html/changelogs/AutoChangeLog-pr-6674.yml b/html/changelogs/AutoChangeLog-pr-6674.yml deleted file mode 100644 index 719cef4a6bb1..000000000000 --- a/html/changelogs/AutoChangeLog-pr-6674.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "cuberound" -delete-after: True -changes: - - rscadd: "roof structures added, can be also used for lattices and billboards, go transparent when you are near them" \ No newline at end of file diff --git a/html/changelogs/archive/2024-07.yml b/html/changelogs/archive/2024-07.yml index 9e2bace15655..98c6fd5dbb20 100644 --- a/html/changelogs/archive/2024-07.yml +++ b/html/changelogs/archive/2024-07.yml @@ -127,3 +127,33 @@ 2024-07-14: kiVts: - bugfix: Denied request on req is working again +2024-07-15: + cuberound: + - rscadd: roof structures added, can be also used for lattices and billboards, go + transparent when you are near them +2024-07-16: + Git-Nivrak: + - rscdel: Mortar shells no longer blow up their payload, instead they will create + a small fixed explosion. + Nomoresolvalou: + - rscadd: Added neckties and stethoscope to the synthetic snowflake vendor + Steelpoint: + - balance: The XM88 now deals higher damage per-bullet at the cost of a slightly + lower rate of fire and accuracy. This is identical to as if it had a barrel + charger attached to it. + - balance: Per the above, the barrel charger is no longer compatible with the XM88. +2024-07-17: + AndroBetel: + - rscadd: MP5 has 10% chance to spawn with M203 attached. + VileBeggar: + - rscadd: The CIC armoury now contains a plantable flag of the United Americas. + Zonespace27: + - rscadd: Added a tutorial for xenomorph Abominations. You must complete the tutorial + before being able to roll for Abomination. + harryob: + - bugfix: queens can remote build again + ihatethisengine: + - balance: being mid-paradrop won't trigger traps, fire and stray bullets before + you land. + realforest2001: + - bugfix: Fixes riflemen spec_kits not being usable by riflemen. diff --git a/icons/mob/humans/onmob/items_lefthand_64.dmi b/icons/mob/humans/onmob/items_lefthand_64.dmi index 057d7f1cad66..d005d8c5f049 100644 Binary files a/icons/mob/humans/onmob/items_lefthand_64.dmi and b/icons/mob/humans/onmob/items_lefthand_64.dmi differ diff --git a/icons/mob/humans/onmob/items_righthand_64.dmi b/icons/mob/humans/onmob/items_righthand_64.dmi index 599ef5935f2e..72335e39bfff 100644 Binary files a/icons/mob/humans/onmob/items_righthand_64.dmi and b/icons/mob/humans/onmob/items_righthand_64.dmi differ diff --git a/icons/obj/structures/plantable_flag.dmi b/icons/obj/structures/plantable_flag.dmi new file mode 100644 index 000000000000..c92311529be3 Binary files /dev/null and b/icons/obj/structures/plantable_flag.dmi differ diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm index 9617bfaccb6c..b4a195ae5969 100644 --- a/maps/map_files/USS_Almayer/USS_Almayer.dmm +++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm @@ -2665,6 +2665,7 @@ /obj/item/device/radio/marine, /obj/item/device/radio/marine, /obj/item/folded_tent/cmd, +/obj/item/flag/plantable/ua, /turf/open/floor/almayer/redfull, /area/almayer/command/cic) "asR" = ( diff --git a/sound/effects/.wav b/sound/effects/.wav new file mode 100644 index 000000000000..a5aa273379f6 Binary files /dev/null and b/sound/effects/.wav differ diff --git a/sound/effects/flag_lowering.ogg b/sound/effects/flag_lowering.ogg new file mode 100644 index 000000000000..d514e097913d Binary files /dev/null and b/sound/effects/flag_lowering.ogg differ diff --git a/sound/effects/flag_raised.ogg b/sound/effects/flag_raised.ogg new file mode 100644 index 000000000000..5da7eca55acb Binary files /dev/null and b/sound/effects/flag_raised.ogg differ diff --git a/sound/effects/flag_raising.ogg b/sound/effects/flag_raising.ogg new file mode 100644 index 000000000000..cc2770f2ecb8 Binary files /dev/null and b/sound/effects/flag_raising.ogg differ diff --git a/sound/effects/flag_warcry_ua.ogg b/sound/effects/flag_warcry_ua.ogg new file mode 100644 index 000000000000..eb0ddecc66eb Binary files /dev/null and b/sound/effects/flag_warcry_ua.ogg differ diff --git a/sound/effects/flag_warcry_ua_extra.ogg b/sound/effects/flag_warcry_ua_extra.ogg new file mode 100644 index 000000000000..c723cca44620 Binary files /dev/null and b/sound/effects/flag_warcry_ua_extra.ogg differ diff --git a/tgui/packages/tgui/interfaces/TutorialMenu.tsx b/tgui/packages/tgui/interfaces/TutorialMenu.tsx index 14abfa957b1c..c47db9fd746d 100644 --- a/tgui/packages/tgui/interfaces/TutorialMenu.tsx +++ b/tgui/packages/tgui/interfaces/TutorialMenu.tsx @@ -60,25 +60,30 @@ export const TutorialMenu = (props) => { {tutorial_categories.map( (tutorial_category) => tutorial_category.name === categoryIndex && - tutorial_category.tutorials.map((tutorial) => ( -
- -
- )), + + + )), )}