diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mind.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mind.dm new file mode 100644 index 0000000000..2cca5fe18c --- /dev/null +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mind.dm @@ -0,0 +1,2 @@ +///from mind/transfer_to. Sent after the mind has been transferred to a different body: (mob/previous_body) +#define COMSIG_MIND_TRANSFERRED "mind_transferred" diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index 0271cd6334..dd995ba864 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -72,9 +72,13 @@ #define COMSIG_MOB_PRE_CLICK "mob_pre_click" #define COMPONENT_INTERRUPT_CLICK (1<<0) -///from base of /mob/Login(): () +/// From base of /mob/Login(), called when a client logs into this mob: () +/// Not to be confused with [COMSIG_MOB_LOGGED_IN] #define COMSIG_MOB_LOGIN "mob_login" -///from base of /mob/Logout(): () +/// From base of /mob/Login(), called after a client logs into this mob: () +/// Not to be confused with [COMSIG_MOB_LOGIN] +#define COMSIG_MOB_LOGGED_IN "mob_logged_in" +/// From base of /mob/Logout(): () #define COMSIG_MOB_LOGOUT "mob_logout" //from /mob/proc/on_deafness_gain() diff --git a/code/__DEFINES/dcs/signals/signals_client.dm b/code/__DEFINES/dcs/signals/signals_client.dm index 6733e07035..e7e74771fc 100644 --- a/code/__DEFINES/dcs/signals/signals_client.dm +++ b/code/__DEFINES/dcs/signals/signals_client.dm @@ -19,8 +19,8 @@ /// Called after one or more verbs are added: (list of verbs added) #define COMSIG_CLIENT_VERB_REMOVED "client_verb_removed" -/// Called after a client logs into a mob: (mob) -#define COMSIG_CLIENT_MOB_LOGIN "client_mob_changed" +/// Called from /mob/Login() after a client logs into a mob: (mob) +#define COMSIG_CLIENT_MOB_LOGGED_IN "client_mob_logged_in" /// Called when something is added to a client's screen : /client/proc/add_to_screen(screen_add) #define COMSIG_CLIENT_SCREEN_ADD "client_screen_add" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 89904c5a1b..825f427695 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -34,9 +34,11 @@ #define COMSIG_GLOB_REMOVE_VOTE_BUTTON "!remove_vote_button" -#define COMSIG_GLOB_CLIENT_LOGIN "!client_login" +/// Called from /client/New() when a client logs in to the game: (client) +#define COMSIG_GLOB_CLIENT_LOGGED_IN "!client_logged_in" -#define COMSIG_GLOB_MOB_LOGIN "!mob_login" +/// Called from /mob/Login() when a client logs into a mob: (mob) +#define COMSIG_GLOB_MOB_LOGGED_IN "!mob_logged_in" ///from /datum/controller/subsystem/ticker/PostSetup #define COMSIG_GLOB_POST_SETUP "!post_setup" diff --git a/code/__DEFINES/sounds.dm b/code/__DEFINES/sounds.dm index 6c5d2879f3..13a4468427 100644 --- a/code/__DEFINES/sounds.dm +++ b/code/__DEFINES/sounds.dm @@ -61,6 +61,9 @@ #define SOUND_ENVIRONMENT_DIZZY 24 #define SOUND_ENVIRONMENT_PSYCHOTIC 25 +#define SOUND_ECHO_REVERB_ON list(0, 0, 0, 0, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 0) +#define SOUND_ECHO_REVERB_OFF list(0, 0, -10000, -10000, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 0) //-10000 to Room & RoomHF makes enviromental reverb effectively inaudible + #define AMBIENCE_SHIP 'sound/ambience/shipambience.ogg' #define AMBIENCE_JUNGLE 'sound/ambience/ambienceLV624.ogg' #define AMBIENCE_RIVER 'sound/ambience/ambienceriver.ogg' diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index f84bac20b1..74f3149610 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -53,3 +53,5 @@ GLOBAL_VAR(xeno_queue_candidate_count) GLOBAL_VAR(obfs_x) /// A number between -500 and 500. GLOBAL_VAR(obfs_y) + +GLOBAL_VAR_INIT(ai_xeno_weeding, TRUE) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index d114aff6b7..18587c0545 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -59,9 +59,11 @@ /atom/movable/screen/action_button/attack_ghost(mob/dead/observer/user) return -/atom/movable/screen/action_button/clicked(mob/user) +/atom/movable/screen/action_button/clicked(mob/user, list/mods) if(!user || !source_action) return TRUE + if(source_action.owner != user) + return TRUE if(source_action.can_use_action()) source_action.action_activate() @@ -97,7 +99,7 @@ icon_state = "hide" var/hidden = 0 -/atom/movable/screen/action_button/hide_toggle/clicked(mob/user, mods) +/atom/movable/screen/action_button/hide_toggle/clicked(mob/user, list/mods) user.hud_used.action_buttons_hidden = !user.hud_used.action_buttons_hidden hidden = user.hud_used.action_buttons_hidden if(hidden) @@ -107,7 +109,7 @@ name = "Hide Buttons" icon_state = "hide" user.update_action_buttons() - return 1 + return TRUE /atom/movable/screen/action_button/ghost/minimap/get_button_screen_loc(button_number) return "SOUTH:6,CENTER+1:24" @@ -214,7 +216,7 @@ /atom/movable/screen/zone_sel/robot icon = 'icons/mob/hud/screen1_robot.dmi' -/atom/movable/screen/clicked(mob/user) +/atom/movable/screen/clicked(mob/user, list/mods) if(!user) return TRUE diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm index 1c2a6d3e24..a26d024b17 100644 --- a/code/controllers/subsystem/minimap.dm +++ b/code/controllers/subsystem/minimap.dm @@ -717,6 +717,7 @@ SUBSYSTEM_DEF(minimaps) user.client.register_map_obj(map_holder.map) ui = new(user, src, "TacticalMap") ui.open() + RegisterSignal(user.mind, COMSIG_MIND_TRANSFERRED, PROC_REF(on_mind_transferred)) /datum/tacmap/drawing/tgui_interact(mob/user, datum/tgui/ui) var/mob/living/carbon/xenomorph/xeno = user @@ -755,6 +756,7 @@ SUBSYSTEM_DEF(minimaps) tacmap_ready_time = SSminimaps.next_fire + 2 SECONDS addtimer(CALLBACK(src, PROC_REF(on_tacmap_fire), faction), SSminimaps.next_fire - world.time + 1 SECONDS) user.client.register_map_obj(map_holder.map) + RegisterSignal(user.mind, COMSIG_MIND_TRANSFERRED, PROC_REF(on_mind_transferred)) ui = new(user, src, "TacticalMap") ui.open() @@ -835,6 +837,9 @@ SUBSYSTEM_DEF(minimaps) return data +/datum/tacmap/ui_close(mob/user) + UnregisterSignal(user.mind, COMSIG_MIND_TRANSFERRED) + /datum/tacmap/drawing/ui_close(mob/user) . = ..() action_queue_change = 0 @@ -950,6 +955,11 @@ SUBSYSTEM_DEF(minimaps) return UI_INTERACTIVE +// This gets removed when the player changes bodies (i.e. xeno evolution), so re-register it when that happens. +/datum/tacmap/proc/on_mind_transferred(datum/mind/source, mob/previous_body) + SIGNAL_HANDLER + source.current.client.register_map_obj(map_holder.map) + /datum/tacmap_holder var/map_ref var/atom/movable/screen/minimap/map diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index cfe66421c9..d3cb19c40e 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -180,7 +180,7 @@ SUBSYSTEM_DEF(ticker) CHECK_TICK mode.announce() if(mode.taskbar_icon) - RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGIN, PROC_REF(handle_mode_icon)) + RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN, PROC_REF(handle_mode_icon)) set_clients_taskbar_icon(mode.taskbar_icon) if(GLOB.perf_flags & PERF_TOGGLE_LAZYSS) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index a56e10636a..34350613ce 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -59,7 +59,7 @@ SUBSYSTEM_DEF(vote) voting.Cut() remove_action_buttons() - UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGIN) + UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN) for(var/c in GLOB.player_list) update_static_data(c) @@ -370,7 +370,7 @@ SUBSYSTEM_DEF(vote) if(send_clients_vote) C.mob.vote() - RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGIN, PROC_REF(handle_client_joining)) + RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN, PROC_REF(handle_client_joining)) SStgui.update_uis(src) return TRUE return FALSE diff --git a/code/datums/action.dm b/code/datums/action.dm index 0510a43415..3a597ad262 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -11,9 +11,9 @@ var/cost = 0 // By default an action has no cost -> will be utilized by skill actions/xeno actions var/action_flags = 0 // Check out __game.dm for flags /// Whether the action is hidden from its owner - /// Useful for when you want to preserve action state while preventing - /// a mob from using said action - var/hidden = FALSE + var/hidden = FALSE //Preserve action state while preventing mob from using action + ///Hide the action from the owner without preventing them from using it (incase of keybind listen_signal) + var/player_hidden = FALSE var/unique = TRUE /// A signal on the mob that will cause the action to activate var/listen_signal @@ -227,7 +227,7 @@ var/atom/movable/screen/action_button/B = A.button if(reload_screen) client.add_to_screen(B) - if(A.hidden) + if(A.hidden || A.player_hidden) B.screen_loc = null continue button_number++ diff --git a/code/datums/ammo/bullet/special_ammo.dm b/code/datums/ammo/bullet/special_ammo.dm index 127e8b1ba1..3a592fc8b2 100644 --- a/code/datums/ammo/bullet/special_ammo.dm +++ b/code/datums/ammo/bullet/special_ammo.dm @@ -104,9 +104,9 @@ icon_state = "bullet" // Keeping it bog standard with the turret but allows it to be changed accurate_range = 12 - damage = 35 + damage = 40 penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive - accuracy = HIT_ACCURACY_TIER_3 + accuracy = HIT_ACCURACY_TIER_5 /datum/ammo/bullet/machinegun/set_bullet_traits() . = ..() @@ -158,7 +158,7 @@ accurate_range = 12 /datum/ammo/bullet/m60 - name = "M60 bullet" + name = "Mk70 bullet" headshot_state = HEADSHOT_OVERLAY_MEDIUM accuracy = HIT_ACCURACY_TIER_2 diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm index e14066ffb7..225149ecb4 100644 --- a/code/datums/components/overlay_lighting.dm +++ b/code/datums/components/overlay_lighting.dm @@ -199,7 +199,7 @@ get_new_turfs() -///Adds the luminosity and source for the afected movable atoms to keep track of their visibility. +///Adds the luminosity and source for the affected movable atoms to keep track of their visibility. /datum/component/overlay_lighting/proc/add_dynamic_lumi() LAZYSET(current_holder.affected_movable_lights, src, lumcount_range + 1) current_holder.underlays += visible_mask @@ -207,7 +207,7 @@ if(directional) current_holder.underlays += cone -///Removes the luminosity and source for the afected movable atoms to keep track of their visibility. +///Removes the luminosity and source for the affected movable atoms to keep track of their visibility. /datum/component/overlay_lighting/proc/remove_dynamic_lumi() LAZYREMOVE(current_holder.affected_movable_lights, src) current_holder.underlays -= visible_mask @@ -267,6 +267,9 @@ ///Used to determine the new valid current_holder from the parent's loc. /datum/component/overlay_lighting/proc/check_holder() var/atom/movable/movable_parent = GET_PARENT + if(QDELETED(movable_parent)) + set_holder(null) + return if(isturf(movable_parent.loc)) set_holder(movable_parent) return @@ -275,13 +278,21 @@ set_holder(null) return if(isturf(inside.loc)) - set_holder(inside) + // storage items block light, also don't be moving into a qdeleted item + if(QDELETED(inside) || istype(inside, /obj/item/storage)) + set_holder(null) + else + set_holder(inside) return set_holder(null) ///Called when the current_holder is qdeleted, to remove the light effect. /datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force) + SIGNAL_HANDLER + if(QDELETED(current_holder)) + set_holder(null) + return UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) if(directional) UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE) @@ -290,6 +301,7 @@ ///Called when current_holder changes loc. /datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced) + SIGNAL_HANDLER if(!(overlay_lighting_flags & LIGHTING_ON)) return make_luminosity_update() @@ -450,8 +462,7 @@ . = lum_power lum_power = new_lum_power var/difference = . - lum_power - for(var/t in affected_turfs) - var/turf/lit_turf = t + for(var/turf/lit_turf as anything in affected_turfs) lit_turf.dynamic_lumcount -= difference ///Here we append the behavior associated to changing lum_power. diff --git a/code/datums/emergency_calls/cryo_marines.dm b/code/datums/emergency_calls/cryo_marines.dm index 19f73a9843..f7a486bc04 100644 --- a/code/datums/emergency_calls/cryo_marines.dm +++ b/code/datums/emergency_calls/cryo_marines.dm @@ -48,7 +48,6 @@ leader = human leaders++ human.client?.prefs.copy_all_to(human, JOB_SQUAD_LEADER, TRUE, TRUE) - arm_equipment(human, /datum/equipment_preset/uscm/leader/cryo, mind == null, TRUE) to_chat(human, SPAN_ROLE_HEADER("You are a Squad Leader in the USCM")) to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) @@ -62,7 +61,6 @@ else if (medics < max_medics && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(human.client, JOB_SQUAD_MEDIC, time_required_for_job)))) medics++ human.client?.prefs.copy_all_to(human, JOB_SQUAD_MEDIC, TRUE, TRUE) - arm_equipment(human, /datum/equipment_preset/uscm/medic/cryo, mind == null, TRUE) to_chat(human, SPAN_ROLE_HEADER("You are a Hospital Corpsman in the USCM")) to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) @@ -75,7 +73,6 @@ to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) else human.client?.prefs.copy_all_to(human, JOB_SQUAD_MARINE, TRUE, TRUE) - arm_equipment(human, /datum/equipment_preset/uscm/pfc/cryo, mind == null, TRUE) to_chat(human, SPAN_ROLE_HEADER("You are a Rifleman in the USCM")) to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) diff --git a/code/datums/emergency_calls/cryo_marines_heavy.dm b/code/datums/emergency_calls/cryo_marines_heavy.dm index f4fe3c9f2a..c733b9101e 100644 --- a/code/datums/emergency_calls/cryo_marines_heavy.dm +++ b/code/datums/emergency_calls/cryo_marines_heavy.dm @@ -39,7 +39,6 @@ if(leaders < cryo_squad.max_leaders && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job)) leader = H leaders++ - arm_equipment(H, /datum/equipment_preset/uscm/leader_equipped/cryo, TRUE, TRUE) to_chat(H, SPAN_ROLE_HEADER("You are a Squad Leader in the USCM")) to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name].")) else if (heavies < max_heavies && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_HEAVY) && check_timelock(H.client, JOB_SQUAD_SPECIALIST, time_required_for_job)) @@ -49,7 +48,6 @@ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name].")) else if(smartgunners < max_smartgunners && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(H.client, JOB_SQUAD_SMARTGUN, time_required_for_job)) smartgunners++ - arm_equipment(H, /datum/equipment_preset/uscm/smartgunner_equipped/cryo, TRUE, TRUE) to_chat(H, SPAN_ROLE_HEADER("You are a Smartgunner in the USCM")) to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name].")) else if(engineers < max_engineers && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(H.client, JOB_SQUAD_ENGI, time_required_for_job)) @@ -59,11 +57,9 @@ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name].")) else if (medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job)) medics++ - arm_equipment(H, /datum/equipment_preset/uscm/medic_equipped/cryo, TRUE, TRUE) to_chat(H, SPAN_ROLE_HEADER("You are a Hospital Corpsman in the USCM")) to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name].")) else - arm_equipment(H, /datum/equipment_preset/uscm/private_equipped/cryo, TRUE, TRUE) to_chat(H, SPAN_ROLE_HEADER("You are a Rifleman in the USCM")) to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name].")) diff --git a/code/datums/fluff_emails.dm b/code/datums/fluff_emails.dm index f7083541dd..a71ad083bb 100644 --- a/code/datums/fluff_emails.dm +++ b/code/datums/fluff_emails.dm @@ -3,11 +3,9 @@ var/title //email title var/entry_text //email content - //emails for the Almayer computers /datum/fluff_email/almayer - /datum/fluff_email/almayer/iwantout title = "RE: I want out." entry_text = {" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index fe59699fb9..ae6304dbcd 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -32,11 +32,11 @@ msg_admin_niche("[key]/[ckey] has tried to transfer to deleted [new_character].") return - SEND_SIGNAL(current.client, COMSIG_CLIENT_MIND_TRANSFER, new_character) - + var/mob/old_current = current if(current) current.mind = null //remove ourself from our old body's mind variable nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user + SStgui.on_transfer(current, new_character) // and active TGUI instances if(key) if(new_character.key != key) @@ -66,6 +66,7 @@ continue player_entity = setup_player_entity(ckey) + SEND_SIGNAL(src, COMSIG_MIND_TRANSFERRED, old_current) SEND_SIGNAL(new_character, COMSIG_MOB_NEW_MIND, current.client) new_character.refresh_huds(current) //inherit the HUDs from the old body diff --git a/code/datums/skills/uscm.dm b/code/datums/skills/uscm.dm index c2d05bd786..2e2a53b610 100644 --- a/code/datums/skills/uscm.dm +++ b/code/datums/skills/uscm.dm @@ -310,6 +310,7 @@ COMMAND STAFF SKILL_INTEL = SKILL_INTEL_TRAINED, SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, ) /datum/skills/SEA diff --git a/code/datums/soundOutput.dm b/code/datums/soundOutput.dm index 85548d6c90..0fddd9b503 100644 --- a/code/datums/soundOutput.dm +++ b/code/datums/soundOutput.dm @@ -4,13 +4,25 @@ var/list/soundscape_playlist = list() //Updated on changing areas var/ambience = null //The file currently being played as ambience var/status_flags = 0 //For things like ear deafness, psychodelic effects, and other things that change how all sounds behave - var/list/echo -/datum/soundOutput/New(client/C) - if(!C) + + /// Currently applied environmental reverb. + VAR_PROTECTED/owner_environment = SOUND_ENVIRONMENT_NONE + +/datum/soundOutput/New(client/client) + if(!client) qdel(src) return - owner = C - . = ..() + owner = client + RegisterSignal(owner.mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_moved)) + RegisterSignal(owner.mob, COMSIG_MOB_LOGOUT, PROC_REF(on_mob_logout)) + RegisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN, PROC_REF(on_client_mob_logged_in)) + return ..() + +/datum/soundOutput/Destroy() + UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT)) + UnregisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN) + owner = null + return ..() /datum/soundOutput/proc/process_sound(datum/sound_template/T) var/sound/S = sound(T.file, T.repeat, T.wait) @@ -24,7 +36,6 @@ S.offset = T.offset S.pitch = T.pitch S.status = T.status - S.echo = T.echo if(T.x && T.y && T.z) var/turf/owner_turf = get_turf(owner.mob) if(owner_turf) @@ -40,16 +51,12 @@ S.x = T.x - owner_turf.x S.y = 0 S.z = T.y - owner_turf.y - var/area/A = owner_turf.loc - S.environment = A.sound_environment S.y += T.y_s_offset S.x += T.x_s_offset + S.echo = SOUND_ECHO_REVERB_ON //enable environment reverb for positional sounds if(owner.mob.ear_deaf > 0) S.status |= SOUND_MUTE - if(owner.mob.sound_environment_override != SOUND_ENVIRONMENT_NONE) - S.environment = owner.mob.sound_environment_override - sound_to(owner,S) /datum/soundOutput/proc/update_ambience(area/target_area, ambience_override, force_update = FALSE) @@ -86,7 +93,6 @@ S.status = status_flags if(target_area) - S.environment = target_area.sound_environment var/muffle if(target_area.ceiling_muffle) switch(target_area.ceiling) @@ -130,6 +136,51 @@ S.status = SOUND_UPDATE sound_to(owner, S) +/// Pulls mob's area's sound_environment and applies if necessary and not overridden. +/datum/soundOutput/proc/update_area_environment() + var/area/owner_area = get_area(owner.mob) + var/new_environment = owner_area.sound_environment + + if(owner.mob.sound_environment_override != SOUND_ENVIRONMENT_NONE) //override in effect, can't apply + return + + set_owner_environment(new_environment) + +/// Pulls mob's sound_environment_override and applies if necessary. +/datum/soundOutput/proc/update_mob_environment_override() + var/new_environment_override = owner.mob.sound_environment_override + + if(new_environment_override == SOUND_ENVIRONMENT_NONE) //revert to area environment + update_area_environment() + return + + set_owner_environment(new_environment_override) + +/// Pushes new_environment to owner and updates owner_environment var. +/datum/soundOutput/proc/set_owner_environment(new_environment = SOUND_ENVIRONMENT_NONE) + if(new_environment ~= src.owner_environment) //no need to change + return + + var/sound/sound = sound() + sound.environment = new_environment + sound_to(owner, sound) + + src.owner_environment = new_environment + +/datum/soundOutput/proc/on_mob_moved(datum/source, atom/oldloc, direction, Forced) + SIGNAL_HANDLER //COMSIG_MOVABLE_MOVED + update_area_environment() + +/datum/soundOutput/proc/on_mob_logout(datum/source) + SIGNAL_HANDLER //COMSIG_MOB_LOGOUT + UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT)) + +/datum/soundOutput/proc/on_client_mob_logged_in(datum/source, mob/new_mob) + SIGNAL_HANDLER //COMSIG_CLIENT_MOB_LOGGED_IN + RegisterSignal(owner.mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_moved)) + RegisterSignal(owner.mob, COMSIG_MOB_LOGOUT, PROC_REF(on_mob_logout)) + update_mob_environment_override() + /client/proc/adjust_volume_prefs(volume_key, prompt = "", channel_update = 0) volume_preferences[volume_key] = (tgui_input_number(src, prompt, "Volume", volume_preferences[volume_key]*100)) / 100 if(volume_preferences[volume_key] > 1) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index cda3da5e2e..568c36e2c5 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -410,10 +410,6 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li var/willing = null //We don't want to allow people to be forced into despawning. var/mob/living/M = G.grabbed_thing - if(M.stat == DEAD) //This mob is dead - to_chat(user, SPAN_WARNING("[src] immediately rejects [M]. \He passed away!")) - return - if(isxeno(M)) to_chat(user, SPAN_WARNING("There is no way [src] will accept [M]!")) return diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index e6daba29ae..f00ba138ef 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -244,7 +244,7 @@ ), PROC_REF(turn_on)) wearer = user RegisterSignal(user, COMSIG_MOB_STAT_SET_ALIVE, PROC_REF(update_minimap_icon)) - RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(add_hud_tracker)) + RegisterSignal(user, COMSIG_MOB_LOGGED_IN, PROC_REF(add_hud_tracker)) RegisterSignal(user, COMSIG_MOB_DEATH, PROC_REF(update_minimap_icon)) RegisterSignal(user, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(update_minimap_icon)) if(headset_hud_on) @@ -261,7 +261,7 @@ UnregisterSignal(user, list( COMSIG_LIVING_REJUVENATED, COMSIG_HUMAN_REVIVED, - COMSIG_MOB_LOGIN, + COMSIG_MOB_LOGGED_IN, COMSIG_MOB_DEATH, COMSIG_HUMAN_SET_UNDEFIBBABLE, COMSIG_MOB_STAT_SET_ALIVE diff --git a/code/game/sound.dm b/code/game/sound.dm index f2574975a7..6bee74ba01 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,3 +1,5 @@ +/sound + echo = SOUND_ECHO_REVERB_OFF //disable enviroment reverb by default, soundOutput re-enables for positional sounds /datum/sound_template //Basically a sound datum, but only serves as a way to carry info to soundOutput //copied sound datum vars @@ -23,8 +25,6 @@ var/falloff = 1 ///Changes the environmental reverb for all 3D sounds until another environment is specified. The default value (-1) specifies no change in environment. A numeric value from 0 to 25 specifies a set of reverb presets for the environment. var/environment = -1 - ///If set to an 18-element list, this value customizes reverbration settings for this sound only. - var/list/echo //custom vars ///The category of this sound for client volume purposes: VOLUME_SFX (Sound effects), VOLUME_AMB (Ambience and Soundscapes) and VOLUME_ADM (Admin sounds and some other stuff) @@ -59,16 +59,40 @@ * * channel - use this only when you want to force the sound to play on a specific channel * * status - combined bit flags: SOUND_MUTE, SOUND_PAUSED, SOUND_STREAM, SOUND_UPDATE * * falloff - max range till sound volume starts dropping as distance increases - * * echo - customizes reverbration settings for this sound * * y_s_offset - vertical sound position offset * * x_s_offset - horizontal sound position offset * * Returns selected channel on success, FALSE on failure */ -/proc/playsound(atom/source, sound/soundin, vol = 100, vary = FALSE, sound_range, vol_cat = VOLUME_SFX, channel = 0, status, falloff = 1, list/echo, y_s_offset, x_s_offset) +/proc/playsound(atom/source, sound/soundin, vol = 100, vary = FALSE, sound_range, vol_cat = VOLUME_SFX, channel = 0, status, falloff = 1, y_s_offset, x_s_offset) if(isarea(source)) error("[source] is an area and is trying to make the sound: [soundin]") return FALSE + var/datum/sound_template/S = new() + + var/sound/SD = soundin + if(istype(SD)) + S.file = SD.file + S.wait = SD.wait + S.repeat = SD.repeat + else + S.file = get_sfx(soundin) + S.channel = channel ? channel : get_free_channel() + S.status = status + S.falloff = falloff + S.volume = vol + S.volume_cat = vol_cat + S.y_s_offset = y_s_offset + S.x_s_offset = x_s_offset + if(vary != FALSE) + if(vary > 1) + S.frequency = vary + else + S.frequency = GET_RANDOM_FREQ // Same frequency for everybody + + if(!sound_range) + sound_range = floor(0.25*vol) //if no specific range, the max range is equal to a quarter of the volume. + S.range = sound_range var/turf/turf_source = get_turf(source) if(!turf_source?.z) @@ -100,7 +124,6 @@ template.frequency = GET_RANDOM_FREQ // Same frequency for everybody template.status = status template.falloff = falloff - template.echo = echo template.volume_cat = vol_cat template.range = sound_range || floor(0.25 * vol) //if no specific range, the max range is equal to a quarter of the volume. @@ -147,13 +170,12 @@ * * vol_cat - the category of this sound for client volume purposes: VOLUME_SFX (Sound effects), VOLUME_AMB (Ambience and Soundscapes), VOLUME_ADM (Admin sounds) * * channel - use this only when you want to force the sound to play on a specific channel * * status - combined bit flags: SOUND_MUTE, SOUND_PAUSED, SOUND_STREAM, SOUND_UPDATE - * * echo - customizes reverbration settings for this sound * * y_s_offset - vertical sound position offset * * x_s_offset - horizontal sound position offset * * Returns FALSE on failure */ -/proc/playsound_client(client/C, sound/soundin, atom/origin, vol = 100, random_freq, vol_cat = VOLUME_SFX, channel = 0, status, list/echo, y_s_offset, x_s_offset) +/proc/playsound_client(client/C, sound/soundin, atom/origin, vol = 100, random_freq, vol_cat = VOLUME_SFX, channel = 0, status, y_s_offset, x_s_offset) if(!istype(C) || !C.soundOutput) return FALSE var/datum/sound_template/template = new() @@ -179,7 +201,6 @@ if(random_freq) template.frequency = GET_RANDOM_FREQ template.status = status - template.echo = echo template.volume_cat = vol_cat var/turf/turf_origin = get_turf(origin) @@ -206,7 +227,7 @@ * * Returns FALSE on failure */ -/proc/playsound_area(area/A, sound/soundin, vol = 100, channel = 0, status, vol_cat = VOLUME_SFX, list/echo, y_s_offset, x_s_offset) +/proc/playsound_area(area/A, sound/soundin, vol = 100, channel = 0, status, vol_cat = VOLUME_SFX, y_s_offset, x_s_offset) if(!isarea(A)) return FALSE @@ -259,13 +280,12 @@ * * soundin - sound datum ( sound() ), sound file ('mysound.ogg'), or string to get a SFX ("male_warcry") * * volume - the initial volume of the sound, 0 is no sound at all, 75 is loud queen screech. * * vol_cat - the category of this sound for client volume purposes: VOLUME_SFX (Sound effects), VOLUME_AMB (Ambience and Soundscapes), VOLUME_ADM (Admin sounds) - * * echo - customizes reverbration settings for this sound * * y_s_offset - vertical sound position offset * * x_s_offset - horizontal sound position offset * * Returns selected channel on success, FALSE on failure */ -/proc/playsound_z(list/z, sound/soundin, volume = 100, vol_cat = VOLUME_SFX, echo, y_s_offset, x_s_offset) +/proc/playsound_z(list/z, sound/soundin, volume = 100, vol_cat = VOLUME_SFX, y_s_offset, x_s_offset) var/datum/sound_template/template = new() if(istype(soundin)) @@ -286,7 +306,6 @@ template.channel = SOUND_CHANNEL_Z template.volume = volume - template.echo = echo template.volume_cat = vol_cat template.x_s_offset = x_s_offset diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 5caf0cba02..0da273dfc9 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -335,8 +335,10 @@ var/list/roundstart_mod_verbs = list( add_verb(src, /client/proc/toggle_join_xeno) add_verb(src, /client/proc/game_master_rename_platoon) add_verb(src, /client/proc/toggle_vehicle_blockers) + add_verb(src, /client/proc/toggle_ai_xeno_weeding) add_verb(src, /client/proc/toggle_rappel_menu) add_verb(src, /client/proc/toggle_xeno_kidnapping) + add_verb(src, /client/proc/toggle_fire_support_menu) if(CLIENT_HAS_RIGHTS(src, R_SERVER)) add_verb(src, admin_verbs_server) if(CLIENT_HAS_RIGHTS(src, R_DEBUG)) @@ -372,8 +374,10 @@ var/list/roundstart_mod_verbs = list( /client/proc/toggle_join_xeno, /client/proc/game_master_rename_platoon, /client/proc/toggle_vehicle_blockers, + /client/proc/toggle_ai_xeno_weeding, /client/proc/toggle_rappel_menu, /client/proc/toggle_xeno_kidnapping, + /client/proc/toggle_fire_support_menu, admin_verbs_admin, admin_verbs_ban, admin_verbs_minor_event, diff --git a/code/modules/admin/game_master/extra_buttons/fire_support_menu.dm b/code/modules/admin/game_master/extra_buttons/fire_support_menu.dm new file mode 100644 index 0000000000..c3469071f3 --- /dev/null +++ b/code/modules/admin/game_master/extra_buttons/fire_support_menu.dm @@ -0,0 +1,291 @@ +#define FIRE_SUPPORT_CLICK_INTERCEPT_ACTION "fire_support_click_intercept_action" + +//Various ordnance selections +#define ORDNANCE_OPTIONS list("Banshee Missile", "Harpoon Missile", "Keeper Missile", "Napalm Missile", "Thermobaric Missile", "Widowmaker Missile", "Laser", "Minirocket", "Incendiary Minirocket", "Sentry Drop", "GAU-21", "Heavy GAU-21", "High Explosive", "Incendiary", "Cluster", "High Explosive", "Incendiary", "Fragmentation", "Flare") +#define MISSILE_ORDNANCE list("Banshee Missile", "Harpoon Missile", "Keeper Missile", "Napalm Missile", "Thermobaric Missile", "Widowmaker Missile") +#define ORBITAL_ORDNANCE list("High Explosive OB", "Incendiary OB", "Cluster OB") +#define MORTAR_ORDNANCE list("High Explosive Shell", "Incendiary Shell", "Fragmentation Shell", "Flare Shell") +#define MISC_ORDNANCE list("Laser", "Minirocket", "Incendiary Minirocket", "Sentry Drop", "GAU-21", "Heavy GAU-21") + +/client/proc/toggle_fire_support_menu() + set name = "Fire Support Menu" + set category = "Game Master.Extras" + if(!check_rights(R_ADMIN)) + return + new /datum/fire_support_menu(mob) + +///The actual menu datum +/datum/fire_support_menu + var/fire_support_click_intercept = FALSE + var/selected_ordnance = "Banshee Missile" + var/sound_cooldown = FALSE + ///Mortar to fire the abstract shells. + var/obj/structure/mortar/abstract_mortar = new() + var/client/holder + +/datum/fire_support_menu/New(user) + if(isclient(user)) + holder = user + else + var/mob/mob = user + holder = mob.client + + holder.click_intercept = src + tgui_interact(holder.mob) + +///Deletes the mortar when the menu is closed so we dont make a thousand of them. +/datum/fire_support_menu/Destroy(force, ...) + QDEL_NULL(abstract_mortar) + holder = null + return ..() + +/datum/fire_support_menu/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GameMasterFireSupportMenu", "Fire Support Menu") + ui.open() + +///Input all the options for the ordnance panel. Only fires once, as the available ammo types shouldnt change. And if they do, something's very wrong +/datum/fire_support_menu/ui_static_data(mob/user) + . = ..() + var/list/data = list() + + data["ordnance_options"] = ORDNANCE_OPTIONS + + data["missile_ordnance_options"] = MISSILE_ORDNANCE + data["orbital_ordnance_options"] = ORBITAL_ORDNANCE + data["mortar_ordnance_options"] = MORTAR_ORDNANCE + data["misc_ordnance_options"] = MISC_ORDNANCE + + return data + +//Input all the dynamic data, the selected ordnance, and whether it's armed or not. +/datum/fire_support_menu/ui_data(mob/user) + . = ..() + var/list/data = list() + + data["selected_ordnance"] = selected_ordnance + data["fire_support_click_intercept"] = fire_support_click_intercept + + return data + +/datum/fire_support_menu/ui_act(action, params) + . = ..() + switch(action) + if("toggle_click_fire_support") + fire_support_click_intercept = !fire_support_click_intercept + return + if("set_selected_ordnance") + selected_ordnance = params["ordnance"] + return + +/datum/fire_support_menu/ui_status(mob/user, datum/ui_state/state) + return UI_INTERACTIVE + +/datum/fire_support_menu/ui_close(mob/user) + var/client/user_client = user.client + if(user_client?.click_intercept == src) + user_client.click_intercept = null + + fire_support_click_intercept = FALSE + qdel(src) + +///Handles firing logic whenever the mouse is clicked, and the fire_support_click_intercept var is TRUE +/datum/fire_support_menu/proc/InterceptClickOn(mob/user, params, atom/object) + + var/turf/target_turf = get_turf(object) + if(fire_support_click_intercept) + switch(selected_ordnance) + //PREMADE ORDNANCE + + //DS missiles + if("Banshee Missile") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/rocket/banshee/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Harpoon Missile") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/rocket/harpoon/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Keeper Missile") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/rocket/keeper/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Napalm Missile") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/rocket/napalm/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Thermobaric Missile") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/rocket/thermobaric/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Widowmaker Missile") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/rocket/widowmaker/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + //Misc DS ammo + if("Laser") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/laser_battery/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Minirocket") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/minirocket/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Incendiary Minirocket") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/minirocket/incendiary/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Sentry Drop") + if(istype(target_turf, /turf/closed)) + to_chat(user, SPAN_WARNING("The selected drop site is a sheer wall!")) + return FALSE + else + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/sentry/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("GAU-21") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/heavygun/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Heavy GAU-21") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/structure/ship_ammo/heavygun/antitank/ammo = new() + + handle_dropship_ordnance(target_turf, ammo) + + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + //Orbital Bombardments + if("High Explosive OB") + var/obj/structure/ob_ammo/warhead/explosive/ammo = new() + + handle_orbital_ordnance(target_turf, ammo) + return TRUE + + if("Incendiary OB") + var/obj/structure/ob_ammo/warhead/incendiary/ammo = new() + + handle_orbital_ordnance(target_turf, ammo) + return TRUE + + if("Cluster OB") + var/obj/structure/ob_ammo/warhead/cluster/ammo = new() + + handle_orbital_ordnance(target_turf, ammo) + return TRUE + + //Mortar Shelling + if("High Explosive Shell") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/item/mortar_shell/he/ammo = new() + + abstract_mortar.handle_shell(target_turf, ammo) + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + + if("Incendiary Shell") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/item/mortar_shell/incendiary/ammo = new() + + abstract_mortar.handle_shell(target_turf, ammo) + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + + if("Fragmentation Shell") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/item/mortar_shell/frag/ammo = new() + + abstract_mortar.handle_shell(target_turf, ammo) + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + if("Flare Shell") + var/obj/effect/overlay/temp/blinking_laser/target_lase = new(target_turf) + var/obj/item/mortar_shell/flare/ammo = new() + + abstract_mortar.handle_shell(target_turf, ammo) + QDEL_IN(target_lase, 5 SECONDS) //to stop "unused var" warnings + return TRUE + + else + to_chat(user, SPAN_ANNOUNCEMENT_HEADER_ADMIN("Invalid ordnance selection! If this appears, yell at a coder!")) + return TRUE + +///Handles the dropship swooping sound effect, and makes sure it doesnt play 20 times a second. +/datum/fire_support_menu/proc/handle_dropship_sound(target_turf) + if(!sound_cooldown) + playsound(target_turf, 'sound/weapons/dropship_sonic_boom.ogg', 100, 1, 60) + sound_cooldown = TRUE + addtimer(VARSET_CALLBACK(src, sound_cooldown, FALSE), 10 SECONDS) + +///Handles the noises and actual detonation of dropship ammo. Mainly it doesnt play the warning sound for ammo of the ship_ammo/heavygun/ type. +/datum/fire_support_menu/proc/handle_dropship_ordnance(turf/target_turf, obj/structure/ship_ammo/ammo) + addtimer(CALLBACK(src, PROC_REF(handle_dropship_sound), target_turf), 0.5 SECONDS) + if(!istype(ammo, /obj/structure/ship_ammo/heavygun/)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), target_turf, ammo.warning_sound, ammo.warning_sound_volume, 1, 15), 1.5 SECONDS) + addtimer(CALLBACK(ammo, TYPE_PROC_REF(/obj/structure/ship_ammo, detonate_on), target_turf), 2.5 SECONDS) + QDEL_IN(ammo, 5 SECONDS) + +/datum/fire_support_menu/proc/handle_orbital_ordnance(turf/target_turf, obj/structure/ob_ammo/warhead/ammo) + ammo.warhead_impact(target_turf) + +#undef ORDNANCE_OPTIONS +#undef ORBITAL_ORDNANCE +#undef MORTAR_ORDNANCE +#undef MISC_ORDNANCE +#undef FIRE_SUPPORT_CLICK_INTERCEPT_ACTION diff --git a/code/modules/admin/game_master/extra_buttons/toggle_ai_xeno_weeding.dm b/code/modules/admin/game_master/extra_buttons/toggle_ai_xeno_weeding.dm new file mode 100644 index 0000000000..6cf536564a --- /dev/null +++ b/code/modules/admin/game_master/extra_buttons/toggle_ai_xeno_weeding.dm @@ -0,0 +1,10 @@ +/// For PvE CM a convenient button to enable/disable AI xenos weeding. +/client/proc/toggle_ai_xeno_weeding() + set name = "Toggle AI Xeno Weeding" + set category = "Game Master.Flags" + + if(!admin_holder || !check_rights(R_MOD, FALSE)) + return + + GLOB.ai_xeno_weeding = !GLOB.ai_xeno_weeding + message_admins("[src] has [GLOB.ai_xeno_weeding ? "enabled" : "disabled"] AI xeno weeding.") diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index d69833ec5c..8456b92463 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -464,7 +464,7 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( view = world_view_size - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CLIENT_LOGIN, src) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CLIENT_LOGGED_IN, src) ////////////// //DISCONNECT// @@ -820,3 +820,32 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( xeno_prefix = "XX" if(!xeno_postfix || xeno_name_ban) xeno_postfix = "" + +/client/verb/action_hide_menu() + set name = "Show/Hide Actions" + set category = "IC" + + var/mob/user = usr + + var/list/actions_list = list() + for(var/datum/action/action as anything in user.actions) + var/action_name = action.name + if(action.player_hidden) + action_name += " (Hidden)" + actions_list[action_name] += action + + if(!LAZYLEN(actions_list)) + to_chat(user, SPAN_WARNING("You have no actions available.")) + return + + var/selected_action_name = tgui_input_list(user, "Show or hide selected action", "Show/Hide Actions", actions_list, 30 SECONDS) + if(!selected_action_name) + to_chat(user, SPAN_WARNING("You did not select an action.")) + return + + var/datum/action/selected_action = actions_list[selected_action_name] + selected_action.player_hidden = !selected_action.player_hidden + user.update_action_buttons() + + if(!selected_action.player_hidden && selected_action.hidden) //Inform the player that even if they are unhiding it, itll still not be visible + to_chat(user, SPAN_NOTICE("[selected_action] is forcefully hidden, bypassing player unhiding.")) diff --git a/code/modules/clothing/suits/marine_armor.dm b/code/modules/clothing/suits/marine_armor.dm index d043bba007..6bdb55e7d7 100644 --- a/code/modules/clothing/suits/marine_armor.dm +++ b/code/modules/clothing/suits/marine_armor.dm @@ -468,6 +468,13 @@ /obj/item/storage/backpack/general_belt, /obj/item/device/motiondetector, /obj/item/device/walkman, + /obj/item/storage/large_holster/machete, + /obj/item/storage/belt/gun/type47, + ) + + smartgun_back = list( + /obj/item/storage/large_holster/machete, + /obj/item/ammo_box, ) diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index 32983f455c..1fb9868ed0 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -471,7 +471,7 @@ GUN_FIREMODE_AUTOMATIC, ) /// A multiplier for how slow this gun should fire in automatic as opposed to burst. 1 is normal, 1.2 is 20% slower, 0.8 is 20% faster, etc. - var/autofire_slow_mult = 1 + var/autofire_slow_mult = 0.7 /// If the gun is currently burst firing VAR_PROTECTED/burst_firing = FALSE /// If the gun should display its ammo count diff --git a/code/modules/cm_tech/implements/railgun.dm b/code/modules/cm_tech/implements/railgun.dm index ebff2ac57e..f627894bcf 100644 --- a/code/modules/cm_tech/implements/railgun.dm +++ b/code/modules/cm_tech/implements/railgun.dm @@ -6,7 +6,7 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) /obj/effect/landmark/railgun_computer name = "Railgun computer landmark" - desc = "A computer with an orange interface, it's idly blinking, awaiting a password." + desc = "A computer with an orange interface, it's idly blinking, awaiting a password. The higher your altitude, the faster your reload, and slower the shots hit." /obj/effect/landmark/railgun_computer/Initialize(mapload, ...) . = ..() @@ -26,6 +26,7 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) /obj/structure/machinery/computer/railgun name = "railgun computer" + desc = "A computer with an orange interface, fires the standard railgun shells. The higher your altitude, the faster your reload, and slower the shots hit." icon_state = "terminal" @@ -36,13 +37,15 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) var/max_ammo = 10 var/ammo = 10 - var/ammo_recharge_time = 30 SECONDS + var/ammo_recharge_time = 30 SECONDS //How long it takes to get a new shot to your ammo counter + var/ammo_delay = 10 SECONDS //How long it takes to hit the earth - var/fire_cooldown = 1.5 SECONDS + var/fire_cooldown = 1.5 SECONDS //Cooldown between shots var/next_fire = 0 var/power = 900 var/range = 2 + var/warning_color = "#0000ff" /// Computer and Railgun can only be used if this variable is cleared var/locked = TRUE @@ -102,13 +105,13 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) return FALSE if(locked) - to_chat(H, SPAN_WARNING("Railgun Safeties are on, unable to fire!")) + to_chat(H, SPAN_WARNING("Safeties are on, unable to fire!")) return FALSE if(istype(T, /turf/open/space)) // No firing into space return FALSE - if(protected_by_pylon(TURF_PROTECTION_OB, T)) + if(protected_by_pylon(TURF_PROTECTION_MORTAR, T)) to_chat(H, SPAN_WARNING("[icon2html(src)] This area is too reinforced to fire into.")) return FALSE @@ -149,12 +152,13 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) next_fire = world.time + fire_cooldown - addtimer(CALLBACK(src, PROC_REF(recharge_ammo)), ammo_recharge_time, TIMER_UNIQUE) + addtimer(CALLBACK(src, PROC_REF(recharge_ammo)), ammo_recharge_time*2-GLOB.ship_alt, TIMER_UNIQUE) ammo-- to_chat(H, SPAN_NOTICE("[icon2html(src)] Firing shell. [SPAN_BOLD("([ammo]/[max_ammo] shells left).")]")) var/obj/effect/warning/railgun/warning_zone = new(T) + warning_zone.color = warning_color var/image/I = image(warning_zone.icon, warning_zone.loc, warning_zone.icon_state, warning_zone.layer) I.color = warning_zone.color @@ -162,7 +166,7 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) H.client.images += I playsound_client(H.client, 'sound/machines/railgun/railgun_shoot.ogg') - addtimer(CALLBACK(src, PROC_REF(land_shot), T, H.client, warning_zone, I), 10 SECONDS) + addtimer(CALLBACK(src, PROC_REF(land_shot), T, H.client, warning_zone, I), ammo_delay*GLOB.ship_alt) /obj/structure/machinery/computer/railgun/proc/land_shot(turf/T, client/firer, obj/effect/warning/droppod/warning_zone, image/to_remove) if(warning_zone) @@ -269,3 +273,47 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) return COMPONENT_TURF_ALLOW_MOVEMENT + + +/obj/structure/machinery/computer/railgun/gatling + name = "orbital gatling computer" + desc = "The younger sister to the railgun, this one is way weaker, however, it fires significantly faster. The higher your altitude, the faster your reload, and slower the shots hit." + max_ammo = 100 + ammo = 100 + ammo_recharge_time = 1 SECONDS + fire_cooldown = 0.1 SECONDS + ammo_delay = 3 SECONDS + power = 50 + range = 1 + warning_color = "#00ff00" + + +/obj/structure/machinery/computer/railgun/orbital + name = "orbital computer" + desc = "An Orbital cannon with a very long recharge time. The higher your altitude, the faster your reload, and slower the shots hit." + max_ammo = 1 + ammo = 1 + ammo_recharge_time = 1 SECONDS + fire_cooldown = 10 MINUTES //So you know how long it takes betweenS + ammo_delay = 30 SECONDS + power = 1500 + range = 15 + warning_color = "#ff0000" + +/obj/structure/machinery/computer/railgun/napalm + name = "orbital napalm computer" + desc = "An Orbital cannon with a very long recharge time. The higher your altitude, the faster your reload, and slower the shots hit." + max_ammo = 5 + ammo = 5 + ammo_recharge_time = 45 SECONDS + ammo_delay = 5 SECONDS + warning_color = "#ff9100" + +/obj/structure/machinery/computer/railgun/napalm/land_shot(turf/T, client/firer, obj/effect/warning/droppod/warning_zone, image/to_remove) + if(warning_zone) + qdel(warning_zone) + + if(firer) + firer.images -= to_remove + playsound(T, 'sound/machines/railgun/railgun_impact.ogg', sound_range = 75) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flame_radius), create_cause_data("railgun", firer.mob), 5, T, BURN_TIME_TIER_5 + 5, BURN_LEVEL_TIER_2, FLAMESHAPE_DEFAULT, FIRE_VARIANT_TYPE_B) diff --git a/code/modules/defenses/sentry_computer.dm b/code/modules/defenses/sentry_computer.dm index bb6f55d72b..7cb4f7bb84 100644 --- a/code/modules/defenses/sentry_computer.dm +++ b/code/modules/defenses/sentry_computer.dm @@ -48,41 +48,18 @@ // Stuff needed to render the map /// asset name for the game map - var/map_name - - /// camera screen which renders the world - var/atom/movable/screen/map_view/cam_screen - - /// camera screen which shows a blank error - var/atom/movable/screen/background/cam_background - - var/list/cam_plane_masters + var/camera_map_name /obj/item/device/sentry_computer/Initialize(mapload) . = ..() if(cell_type) cell = new cell_type() cell.charge = cell.maxcharge - // set up cameras - map_name = "sentry_computer_[REF(src)]_map" - cam_screen = new - cam_screen.name = "screen" - cam_screen.assigned_map = map_name - cam_screen.del_on_map_removal = FALSE - cam_screen.screen_loc = "[map_name]:1,1" - cam_background = new - cam_background.assigned_map = map_name - cam_background.del_on_map_removal = FALSE - - cam_plane_masters = list() - for(var/plane in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness) - var/atom/movable/screen/plane_master/instance = new plane() - instance.assigned_map = map_name - instance.del_on_map_removal = FALSE - if(instance.blend_mode_override) - instance.blend_mode = instance.blend_mode_override - instance.screen_loc = "[map_name]:CENTER" - cam_plane_masters += instance + + RegisterSignal(src, COMSIG_CAMERA_MAPNAME_ASSIGNED, PROC_REF(camera_mapname_update)) + + AddComponent(/datum/component/camera_manager) + SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR) faction_group = FACTION_LIST_MARINE transceiver.forceMove(src) @@ -94,16 +71,20 @@ /obj/item/device/sentry_computer/Destroy() . = ..() + UnregisterSignal(src, COMSIG_CAMERA_MAPNAME_ASSIGNED) QDEL_NULL(cell) - QDEL_NULL(cam_background) - QDEL_NULL(cam_screen) QDEL_NULL(transceiver) QDEL_NULL(voice) last_camera_turf = null current = null registered_tools = null + for(var/obj/structure/machinery/defenses/sentry/sentrygun as anything in paired_sentry) + unpair_sentry(sentrygun) paired_sentry = null +/obj/item/device/sentry_computer/proc/camera_mapname_update(source, value) + camera_map_name = value + /obj/item/device/sentry_computer/Move(NewLoc, direct) ..() if(table_setup || open || on) @@ -232,7 +213,7 @@ for(var/key_id in tool.encryption_keys) var/datum/weakref/ref = tool.encryption_keys[key_id] var/obj/item/device/sentry_computer/key_object = ref.resolve() - key_object.registered_tools -= id + key_object?.registered_tools -= id tool.encryption_keys = list() to_chat(user, SPAN_NOTICE("Existing encryption keys cleared.")) to_chat(usr, SPAN_NOTICE("You begin encryption key to \the [tool].")) @@ -321,7 +302,7 @@ if(current == target) current = null - update_active_camera() + SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR) /obj/item/device/sentry_computer/ui_status(mob/user, datum/ui_state/state) . = ..() @@ -332,19 +313,16 @@ /obj/item/device/sentry_computer/ui_close(mob/user) - - // Unregister map objects - user.client.clear_map(map_name) + SEND_SIGNAL(src, COMSIG_CAMERA_UNREGISTER_UI, user) /obj/item/device/sentry_computer/ui_static_data(mob/user) . = list() .["sentry_static"] = list() - .["mapRef"] = map_name + .["mapRef"] = camera_map_name var/index = 1 - for(var/sentry in paired_sentry) + for(var/obj/structure/machinery/defenses/sentry/sentrygun as anything in paired_sentry) var/list/sentry_holder = list() - var/obj/structure/machinery/defenses/sentry/sentrygun = sentry sentry_holder["selection_menu"] = list() sentry_holder["index"] = index sentry_holder["name"] = sentrygun.name @@ -396,13 +374,8 @@ /obj/item/device/sentry_computer/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) - update_active_camera() if (!ui) - // Register map objects - user.client.register_map_obj(cam_background) - user.client.register_map_obj(cam_screen) - for(var/plane in cam_plane_masters) - user.client.register_map_obj(plane) + SEND_SIGNAL(src, COMSIG_CAMERA_REGISTER_UI, user) ui = new(user, src, "SentryGunUI", name) ui.open() @@ -426,7 +399,17 @@ if("set-camera") current = sentry playsound(src, get_sfx("terminal_button"), 25, FALSE) - update_active_camera() + var/obj/structure/machinery/defenses/sentry/defense = sentry + if (defense.has_camera) + defense.set_watched_turfs() + var/list/turf/visible_turfs = defense.watching_turfs + var/list/bbox = get_bbox_of_atoms(visible_turfs) + var/center_x = (bbox[3] + bbox[1]) * 0.5 + var/center_y = (bbox[4] + bbox[2]) * 0.5 + var/size_x = bbox[3] - bbox[1] + 1 + var/size_y = bbox[4] - bbox[2] + 1 + SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, center_x, center_y, defense.loc.z, size_x, size_y) + return TRUE if("ping") playsound(sentry, 'sound/machines/twobeep.ogg', 50, 1) @@ -439,54 +422,8 @@ if("clear-camera") current = null playsound(src, get_sfx("terminal_button"), 25, FALSE) - update_active_camera() + SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR) return TRUE if("ui-interact") playsound(src, get_sfx("terminal_button"), 25, FALSE) return FALSE - -/** - * Set the displayed camera to the static not-connected. - */ -/obj/item/device/sentry_computer/proc/show_camera_static() - cam_screen.vis_contents.Cut() - last_camera_turf = null - cam_background.icon_state = "scanline2" - cam_background.fill_rect(1, 1, 15, 15) - -/** - * Update camera settings and redraw camera on the current variable. - */ -/obj/item/device/sentry_computer/proc/update_active_camera() - // Show static if can't use the camera - if(isnull(current) || !current.has_camera || current.placed != 1) - show_camera_static() - return - - // Is this camera located in or attached to a living thing, Vehicle or helmet? If so, assume the camera's loc is the living (or non) thing. - var/cam_location = current - if(isliving(current.loc) || isVehicle(current.loc)) - cam_location = current.loc - else if(istype(current.loc, /obj/item/clothing/head/helmet/marine)) - var/obj/item/clothing/head/helmet/marine/helmet = current.loc - cam_location = helmet.loc - // If we're not forcing an update for some reason and the cameras are in the same location, - // we don't need to update anything. - // Most security cameras will end here as they're not moving. - if(last_camera_turf == get_turf(cam_location)) - return - - // Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs. - last_camera_turf = get_turf(cam_location) - - current.set_watched_turfs() - var/list/turf/visible_turfs = current.watching_turfs - - var/list/bbox = get_bbox_of_atoms(visible_turfs) - var/size_x = bbox[3] - bbox[1] + 1 - var/size_y = bbox[4] - bbox[2] + 1 - cam_screen.icon = null - cam_screen.icon_state = "clear" - cam_screen.vis_contents = visible_turfs - cam_background.icon_state = "clear" - cam_background.fill_rect(1, 1, size_x, size_y) diff --git a/code/modules/escape_menu/escape_menu.dm b/code/modules/escape_menu/escape_menu.dm index c31234678b..b61bbd5b3f 100644 --- a/code/modules/escape_menu/escape_menu.dm +++ b/code/modules/escape_menu/escape_menu.dm @@ -49,7 +49,7 @@ GLOBAL_LIST_EMPTY(escape_menus) show_page() RegisterSignal(client, COMSIG_PARENT_QDELETING, PROC_REF(on_client_qdel)) - RegisterSignal(client, COMSIG_CLIENT_MOB_LOGIN, PROC_REF(on_client_mob_login)) + RegisterSignal(client, COMSIG_CLIENT_MOB_LOGGED_IN, PROC_REF(on_client_mob_login)) if (!isnull(ckey)) GLOB.escape_menus[ckey] = src diff --git a/code/modules/gear_presets/clf.dm b/code/modules/gear_presets/clf.dm index 9afc89ab65..91a44328e4 100644 --- a/code/modules/gear_presets/clf.dm +++ b/code/modules/gear_presets/clf.dm @@ -529,10 +529,10 @@ list("GUNNER KITS (CHOOSE 1)", 0, null, null, null), list("SVD Sniper Kit", 0, /obj/effect/essentials_set/kit/svd, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR), list("Custom Built Shotgun Kit", 0, /obj/effect/essentials_set/kit/custom_shotgun, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR), - list("M60 Machine Gun Kit", 0, /obj/effect/essentials_set/kit/m60, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR), + list("Mk70 Machine Gun Kit", 0, /obj/effect/essentials_set/kit/m60, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR), list("SPECIAL AMMUNITION", 0, null, null, null), - list("M60 Ammo Box (7.62x51mm)", 15, /obj/item/ammo_magazine/m60, null, VENDOR_ITEM_REGULAR), + list("Mk70 Ammo Box (7.62x51mm)", 15, /obj/item/ammo_magazine/m60, null, VENDOR_ITEM_REGULAR), list("Shotgun Incendiary Shells (Handful)", 15, /obj/item/ammo_magazine/handful/shotgun/incendiary, null, VENDOR_ITEM_REGULAR), list("SVD Magazine (7.62x54mmR)", 15, /obj/item/ammo_magazine/sniper/svd, null, VENDOR_ITEM_REGULAR), diff --git a/code/modules/gear_presets/uscm.dm b/code/modules/gear_presets/uscm.dm index 5cc00b0f42..82ba128bcd 100644 --- a/code/modules/gear_presets/uscm.dm +++ b/code/modules/gear_presets/uscm.dm @@ -61,6 +61,38 @@ var/obj/item/device/radio/headset/almayer/marine/equipped_headset = new_human.wear_r_ear equipped_headset.add_hud_tracker(new_human) +/datum/equipment_preset/uscm/proc/spawn_marine_fluff_items(mob/living/carbon/human/new_human) + var/obj/item/helmet_accessory = pick(GLOB.allowed_helmet_items) + new_human.equip_to_slot_or_del(new helmet_accessory, WEAR_IN_HELMET) + if(prob(50)) + var/obj/item/helmet_accessory_two = pick(GLOB.allowed_helmet_items) + new_human.equip_to_slot_or_del(new helmet_accessory_two, WEAR_IN_HELMET) + var/list/possible_masks = list(/obj/item/clothing/mask/gas) + subtypesof(/obj/item/clothing/mask/rebreather) + subtypesof(/obj/item/clothing/mask/tornscarf) + if(prob(50)) + var/obj/item/clothing/mask/new_mask = pick(possible_masks) + new_human.equip_to_slot_or_del(new new_mask, WEAR_FACE) + + var/list/possible_glasses = list(/obj/item/clothing/glasses/regular, /obj/item/clothing/glasses/regular/hipster, /obj/item/clothing/glasses/sunglasses, /obj/item/clothing/glasses/sunglasses/aviator, /obj/item/clothing/glasses/sunglasses/big) + subtypesof(/obj/item/clothing/glasses/mgoggles) + if(prob(50)) + var/obj/item/clothing/mask/new_glasses = pick(possible_glasses) + new_human.equip_to_slot_or_del(new new_glasses, WEAR_EYES) + +/datum/equipment_preset/uscm/proc/spawn_marine_armor(mob/living/carbon/human/new_human) + if(prob(66)) + new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/medium, WEAR_JACKET) + else if(prob(50)) + new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/light, WEAR_JACKET) + else + new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/heavy, WEAR_JACKET) + +/datum/equipment_preset/uscm/proc/spawn_marine_backpack(mob/living/carbon/human/new_human) + if(prob(75)) + new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel, WEAR_BACK) + else + new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine, WEAR_BACK) + +/datum/equipment_preset/uscm/proc/spawn_marine_sidearm(mob/living/carbon/human/new_human) + return //*****************************************************************************************************/ /datum/equipment_preset/uscm/pfc @@ -83,22 +115,6 @@ new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK) -/datum/equipment_preset/uscm/pfc/cryo - name = "USCM Cryo Squad Rifleman" - auto_squad_name = SQUAD_MARINE_CRYO - -/datum/equipment_preset/uscm/pfc/cryo/load_gear(mob/living/carbon/human/new_human) - ..() - new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo(new_human), WEAR_L_EAR) - -/datum/equipment_preset/uscm/pfc/cryo - name = "USCM Cryo Squad Rifleman" - auto_squad_name = SQUAD_MARINE_CRYO - -/datum/equipment_preset/uscm/pfc/cryo/load_gear(mob/living/carbon/human/new_human) - ..() - new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo(new_human), WEAR_L_EAR) - /datum/equipment_preset/uscm/pfc/lesser_rank paygrade = "ME1" @@ -158,13 +174,6 @@ new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK) -/datum/equipment_preset/uscm/sg/cryo - name = "USCM Cryo Squad Smartgunner" - auto_squad_name = SQUAD_MARINE_CRYO - -/datum/equipment_preset/uscm/sg/cryo/load_gear(mob/living/carbon/human/new_human) - ..() - new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo(new_human), WEAR_L_EAR) /datum/equipment_preset/uscm/sg/lesser_rank paygrade = "ME3" @@ -433,14 +442,6 @@ new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK) -/datum/equipment_preset/uscm/medic/cryo - name = "USCM Cryo Squad Hospital Corpsman" - auto_squad_name = SQUAD_MARINE_CRYO - -/datum/equipment_preset/uscm/medic/cryo/load_gear(mob/living/carbon/human/new_human) - ..() - new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo/med(new_human), WEAR_L_EAR) - /datum/equipment_preset/uscm/medic/lesser_rank paygrade = "ME3" @@ -500,14 +501,6 @@ new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK) -/datum/equipment_preset/uscm/tl/cryo - name = "USCM Cryo Squad Sergeant" - auto_squad_name = SQUAD_MARINE_CRYO - -/datum/equipment_preset/uscm/tl/cryo/load_gear(mob/living/carbon/human/new_human) - ..() - new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo/tl(new_human), WEAR_L_EAR) - /datum/equipment_preset/uscm/tl/upp name = "UPP Squad Sergeant" paygrade = "UE5" @@ -591,14 +584,6 @@ new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK) -/datum/equipment_preset/uscm/leader/cryo - name = "USCM Cryo Platoon Sergeant" - auto_squad_name = SQUAD_MARINE_CRYO - -/datum/equipment_preset/uscm/leader/cryo/load_gear(mob/living/carbon/human/new_human) - ..() - new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo/lead(new_human), WEAR_L_EAR) - /datum/equipment_preset/uscm/leader/lesser_rank paygrade = "ME6" @@ -680,10 +665,26 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BACK) -/datum/equipment_preset/uscm/private_equipped/cryo - name = "USCM Cryo Squad Rifleman (Equipped)" - auto_squad_name = SQUAD_MARINE_CRYO +/datum/equipment_preset/uscm/private_equipped/random + name = "USCM Squad Rifleman (Equipped Random)" +/datum/equipment_preset/uscm/private_equipped/random/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine(new_human), WEAR_BODY) + spawn_marine_armor(new_human) + spawn_marine_backpack(new_human) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/marine(new_human), WEAR_HEAD) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo(new_human), WEAR_L_EAR) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/storage/box/MRE(new_human), WEAR_IN_BACK) + + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine/m41amk1(new_human), WEAR_WAIST) + spawn_marine_fluff_items(new_human) //*****************************************************************************************************/ @@ -723,9 +724,26 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BACK) -/datum/equipment_preset/uscm/leader_equipped/cryo - name = "USCM Cryo Platoon Sergeant (Equipped)" - auto_squad_name = SQUAD_MARINE_CRYO +/datum/equipment_preset/uscm/leader_equipped/random + name = "USCM Platoon Sergeant (Equipped Random)" + +/datum/equipment_preset/uscm/leader_equipped/random/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine(new_human), WEAR_BODY) + spawn_marine_armor(new_human) + spawn_marine_backpack(new_human) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/marine/leader(new_human), WEAR_HEAD) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo/lead(new_human), WEAR_L_EAR) + new_human.equip_to_slot_or_del(new /obj/item/device/binoculars/range(new_human), WEAR_IN_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/storage/box/MRE(new_human), WEAR_IN_BACK) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine/m41amk1(new_human), WEAR_WAIST) + spawn_marine_fluff_items(new_human) //*****************************************************************************************************/ @@ -761,10 +779,58 @@ new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo(new_human), WEAR_L_EAR) -/datum/equipment_preset/uscm/smartgunner_equipped/cryo - name = "USCM Cryo Squad Smartgunner (Equipped)" - auto_squad_name = SQUAD_MARINE_CRYO +/datum/equipment_preset/uscm/smartgunner_equipped/random + name = "USCM Squad Smartgunner (Equipped Random)" +/datum/equipment_preset/uscm/smartgunner_equipped/random/spawn_marine_fluff_items(mob/living/carbon/human/new_human) + var/obj/item/helmet_accessory = pick(GLOB.allowed_helmet_items) + new_human.equip_to_slot_or_del(new helmet_accessory, WEAR_IN_HELMET) + if(prob(50)) + var/obj/item/helmet_accessory_two = pick(GLOB.allowed_helmet_items) + new_human.equip_to_slot_or_del(new helmet_accessory_two, WEAR_IN_HELMET) + var/list/possible_masks = list(/obj/item/clothing/mask/gas) + subtypesof(/obj/item/clothing/mask/rebreather) + subtypesof(/obj/item/clothing/mask/tornscarf) + if(prob(50)) + var/obj/item/clothing/mask/new_mask = pick(possible_masks) + new_human.equip_to_slot_or_del(new new_mask, WEAR_FACE) + +/datum/equipment_preset/uscm/smartgunner_equipped/random/spawn_marine_sidearm(mob/living/carbon/human/new_human) + var/sidearm = pick("m4a3", "mod88", "vp78", "m44") + switch(sidearm) + if("m4a3") + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/m4a3(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol(new_human), WEAR_IN_ACCESSORY) + if("mod88") + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/mod88(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/mod88(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/mod88(new_human), WEAR_IN_ACCESSORY) + if("vp78") + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp78(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp78(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp78(new_human), WEAR_IN_ACCESSORY) + if("m44") + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/revolver/m44(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/revolver(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/revolver(new_human), WEAR_IN_ACCESSORY) + +/datum/equipment_preset/uscm/smartgunner_equipped/random/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/storage/holster(new_human), WEAR_ACCESSORY) + spawn_marine_sidearm(new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/smartgunner(new_human), WEAR_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/smartgun(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/general_belt(new_human), WEAR_WAIST) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smartgun(new_human), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smartgun(new_human), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smartgun(new_human), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/marine(new_human), WEAR_HEAD) + new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m56_goggles/no_nightvision(new_human), WEAR_EYES) + new_human.equip_to_slot_or_del(new /obj/item/storage/box/MRE(new_human), WEAR_IN_JACKET) + spawn_marine_fluff_items(new_human) //*****************************************************************************************************/ @@ -861,9 +927,46 @@ new_human.equip_to_slot_or_del(new /obj/item/tool/surgery/surgical_line(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/tool/surgery/synthgraft(new_human), WEAR_IN_BACK) -/datum/equipment_preset/uscm/medic_equipped/cryo - name = "USCM Cryo Hospital Corpsman (Equipped)" - auto_squad_name = SQUAD_MARINE_CRYO +/datum/equipment_preset/uscm/medic_equipped/random + name = "USCM Squad Hospital Corpsman (Equipped Random)" + +/datum/equipment_preset/uscm/medic_equipped/random/spawn_marine_fluff_items(mob/living/carbon/human/new_human) + var/obj/item/helmet_accessory = pick(GLOB.allowed_helmet_items) + new_human.equip_to_slot_or_del(new helmet_accessory, WEAR_IN_HELMET) + if(prob(50)) + var/obj/item/helmet_accessory_two = pick(GLOB.allowed_helmet_items) + new_human.equip_to_slot_or_del(new helmet_accessory_two, WEAR_IN_HELMET) + + if(prob(50)) + var/list/possible_masks = list(/obj/item/clothing/mask/gas) + subtypesof(/obj/item/clothing/mask/rebreather) + subtypesof(/obj/item/clothing/mask/tornscarf) + if(prob(25)) + var/obj/item/clothing/mask/new_mask = pick(possible_masks) + new_human.equip_to_slot_or_del(new new_mask, WEAR_FACE) + else + new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/surgical(new_human), WEAR_FACE) + +/datum/equipment_preset/uscm/medic_equipped/random/load_gear(mob/living/carbon/human/new_human) + spawn_marine_backpack(new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/medic(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/marine/medic(new_human), WEAR_HEAD) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo/med(new_human), WEAR_L_EAR) + new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/medium(new_human), WEAR_JACKET) + spawn_marine_fluff_items(new_human) + new_human.equip_to_slot_or_del(new /obj/item/storage/firstaid/regular(new_human), WEAR_IN_BACK) + new_human.equip_to_slot_or_del(new /obj/item/storage/firstaid/adv(new_human), WEAR_IN_BACK) + new_human.equip_to_slot_or_del(new /obj/item/storage/belt/medical/lifesaver/full(new_human), WEAR_WAIST) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/medkit/full(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/storage/box/MRE(new_human), WEAR_IN_BACK) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/tool/surgery/surgical_line(new_human), WEAR_IN_BACK) + new_human.equip_to_slot_or_del(new /obj/item/tool/surgery/synthgraft(new_human), WEAR_IN_BACK) //*****************************************************************************************************/ @@ -972,9 +1075,29 @@ new_human.back.pickup(new_human) -/datum/equipment_preset/uscm/tl_equipped/cryo - name = "USCM Cryo Squad Sergeant (Equipped)" - auto_squad_name = SQUAD_MARINE_CRYO +/datum/equipment_preset/uscm/tl_equipped/random + name = "USCM Squad Sergeant (Equipped Random)" + +/datum/equipment_preset/uscm/tl_equipped/random/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/rto(new_human), WEAR_BACK) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine(new_human), WEAR_BODY) + spawn_marine_armor(new_human) + new_human.equip_to_slot_or_del(new /obj/item/device/binoculars/range(new_human), WEAR_IN_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/marine/rto(new_human), WEAR_HEAD) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/marine/cryo(new_human), WEAR_L_EAR) + + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/storage/box/MRE(new_human), WEAR_IN_BACK) + + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine/m41amk1(new_human), WEAR_WAIST) + spawn_marine_fluff_items(new_human) + + //############ Marine Raiders ############# //Operator diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 409c88388f..cf225caadc 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -32,6 +32,7 @@ plane = GHOST_PLANE layer = ABOVE_FLY_LAYER stat = DEAD + mob_flags = KNOWS_TECHNOLOGY var/adminlarva = FALSE var/ghostvision = TRUE var/can_reenter_corpse @@ -189,37 +190,38 @@ clean_observe_target() /// When the observer target gets a screen, our observer gets a screen minus some game screens we don't want the observer to touch -/mob/dead/observer/proc/observe_target_screen_add(observe_target_mob_client, add_to_screen) +/mob/dead/observer/proc/observe_target_screen_add(observe_target_mob_client, screen_add) SIGNAL_HANDLER - if(!client) - return - - if(istype(add_to_screen, /atom/movable/screen/action_button)) - return - - if(istype(add_to_screen, /atom/movable/screen/fullscreen)) - return + var/static/list/excluded_types = typecacheof(list( + /atom/movable/screen/fullscreen, + /atom/movable/screen/click_catcher, + /atom/movable/screen/escape_menu, + /atom/movable/screen/buildmode, + /obj/effect/detector_blip, + )) - if(istype(add_to_screen, /atom/movable/screen/click_catcher)) + if(!client) return - if(istype(add_to_screen, /atom/movable/screen/escape_menu)) - return + // `screen_add` can sometimes be a list, so it's safest to just handle everything as one. + var/list/stuff_to_add = (islist(screen_add) ? screen_add : list(screen_add)) - if(istype(add_to_screen, /obj/effect/detector_blip)) - return + for(var/item in stuff_to_add) + // Ignore anything that's in `excluded_types`. + if(is_type_in_typecache(item, excluded_types)) + continue - client.add_to_screen(add_to_screen) + client.add_to_screen(screen_add) /// When the observer target loses a screen, our observer loses it as well -/mob/dead/observer/proc/observe_target_screen_remove(observe_target_mob_client, remove_from_screen) +/mob/dead/observer/proc/observe_target_screen_remove(observe_target_mob_client, screen_remove) SIGNAL_HANDLER if(!client) return - client.remove_from_screen(remove_from_screen) + client.remove_from_screen(screen_remove) /// When the observe target ghosts our observer disconnect from their screen updates /mob/dead/observer/proc/observe_target_ghosting(mob/observer_target_mob) @@ -236,8 +238,9 @@ if(observe_target_client != new_client) observe_target_client = new_client - RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add)) - RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove)) + // Override the signal from any previous targets. + RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add), TRUE) + RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove), TRUE) /// When the observe target logs in our observer connect to the new client /mob/dead/observer/proc/observe_target_login(mob/living/new_character) @@ -246,8 +249,9 @@ if(observe_target_client != new_character.client) observe_target_client = new_character.client - RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add)) - RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove)) + // Override the signal from any previous targets. + RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add), TRUE) + RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove), TRUE) ///makes the ghost see the target hud and sets the eye at the target. /mob/dead/observer/proc/do_observe(atom/movable/target) @@ -257,52 +261,28 @@ ManualFollow(target) reset_perspective() - if(!ishuman(target) || !client.prefs?.auto_observe) + if(!iscarbon(target) || !client.prefs?.auto_observe) return - var/mob/living/carbon/human/human_target = target - - client.eye = human_target - - if(!human_target.hud_used) + var/mob/living/carbon/carbon_target = target + if(!carbon_target.hud_used) return client.clear_screen() - LAZYINITLIST(human_target.observers) - human_target.observers |= src - human_target.hud_used.show_hud(human_target.hud_used.hud_version, src) - - var/list/target_contents = human_target.get_contents() - - //Handles any currently open storage containers the target is looking in when we observe - for(var/obj/item/storage/checked_storage in target_contents) - if(!(human_target in checked_storage.content_watchers)) - continue - - client.add_to_screen(checked_storage.closer) - client.add_to_screen(checked_storage.contents) + client.eye = carbon_target + observe_target_mob = carbon_target - if(checked_storage.storage_slots) - client.add_to_screen(checked_storage.boxes) - else - client.add_to_screen(checked_storage.storage_start) - client.add_to_screen(checked_storage.storage_continue) - client.add_to_screen(checked_storage.storage_end) + carbon_target.auto_observed(src) - break - - observe_target_mob = human_target + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(observer_move_react)) RegisterSignal(observe_target_mob, COMSIG_PARENT_QDELETING, PROC_REF(clean_observe_target)) RegisterSignal(observe_target_mob, COMSIG_MOB_GHOSTIZE, PROC_REF(observe_target_ghosting)) RegisterSignal(observe_target_mob, COMSIG_MOB_NEW_MIND, PROC_REF(observe_target_new_mind)) RegisterSignal(observe_target_mob, COMSIG_MOB_LOGIN, PROC_REF(observe_target_login)) - RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(observer_move_react)) - - if(human_target.client) - observe_target_client = human_target.client + if(observe_target_mob.client) + observe_target_client = observe_target_mob.client RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add)) RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove)) - return /mob/dead/observer/reset_perspective(atom/A) if(observe_target_mob) @@ -620,7 +600,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return mind.transfer_to(mind.original, TRUE) - SStgui.on_transfer(src, mind.current) qdel(src) return TRUE @@ -758,12 +737,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!tx || !ty || !tz) return following = null - spawn(0) - // To stop the ghost flickering. - x = tx - y = ty - z = tz - sleep(15) + forceMove(locate(tx, ty, tz)) /mob/dead/observer/verb/dead_teleport_mob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak set category = "Ghost" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index b63ce0174a..4ea2f35aa6 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -416,6 +416,29 @@
"} show_browser(user, dat, name, "mob[name]") +/** + * Called by [/mob/dead/observer/proc/do_observe] when a carbon mob is observed by a ghost with [/datum/preferences/var/auto_observe] enabled. + * + * Any HUD changes past this point are handled by [/mob/dead/observer/proc/observe_target_screen_add] + * and [/mob/dead/observer/proc/observe_target_screen_remove]. + * + * Override on subtype mobs if they have any extra HUD elements/behaviour. + */ +/mob/living/carbon/proc/auto_observed(mob/dead/observer/observer) + SHOULD_CALL_PARENT(TRUE) + + LAZYINITLIST(observers) + observers |= observer + hud_used.show_hud(hud_used.hud_version, observer) + + // Add the player's action buttons (not the actions themselves) to the observer's screen. + for(var/datum/action/action as anything in actions) + // Skip any hidden ones (of course). + if(action.hidden || action.player_hidden) + continue + + observer.client.add_to_screen(action.button) + //generates realistic-ish pulse output based on preset levels /mob/living/carbon/proc/get_pulse(method) //method 0 is for hands, 1 is for machines, more accurate var/temp = 0 //see setup.dm:694 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index dfa646ef80..350bcec3e8 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -313,6 +313,29 @@
"} show_browser(user, dat, name, "mob[name]") +/** + * Handles any storage containers that the human is looking inside when auto-observed. + */ +/mob/living/carbon/human/auto_observed(mob/dead/observer/observer) + . = ..() + + // If `src` doesn't have an inventory open. + if(!s_active) + return + + // Add the storage interface to `observer`'s screen. + observer.client.add_to_screen(s_active.closer) + observer.client.add_to_screen(s_active.contents) + + // If the storage has a set number of item slots. + if(s_active.storage_slots) + observer.client.add_to_screen(s_active.boxes) + // If the storage instead has a maximum combined item 'weight'. + else + observer.client.add_to_screen(s_active.storage_start) + observer.client.add_to_screen(s_active.storage_continue) + observer.client.add_to_screen(s_active.storage_end) + // called when something steps onto a human // this handles mulebots and vehicles /mob/living/carbon/human/Crossed(atom/movable/AM) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index a89e2d0444..f27616508d 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -797,6 +797,11 @@ var/datum/mob_hud/MH = huds[MOB_HUD_XENO_INFECTION] MH.add_hud_to(src, src) +// Transfer any observing players over to the xeno's new body (`target`) on evolve/de-evolve. +/mob/living/carbon/xenomorph/transfer_observers_to(atom/target) + for(var/mob/dead/observer/observer as anything in observers) + observer.clean_observe_target() + observer.do_observe(target) /mob/living/carbon/xenomorph/check_improved_pointing() //xeno leaders get a big arrow and less cooldown diff --git a/code/modules/mob/living/carbon/xenomorph/ai/movement/drone.dm b/code/modules/mob/living/carbon/xenomorph/ai/movement/drone.dm index 263f354c78..cc330966f2 100644 --- a/code/modules/mob/living/carbon/xenomorph/ai/movement/drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/ai/movement/drone.dm @@ -10,6 +10,9 @@ //drones expand the hive /datum/xeno_ai_movement/drone/ai_move_idle(delta_time) + if(!GLOB.ai_xeno_weeding) + return ..() + var/mob/living/carbon/xenomorph/idle_xeno = parent if(idle_xeno.throwing) diff --git a/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm b/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm index e420f2c765..337086434d 100644 --- a/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm +++ b/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm @@ -9,7 +9,6 @@ var/ai_move_delay = 0 var/path_update_period = (0.5 SECONDS) - var/no_path_found = FALSE var/ai_range = 16 var/max_travel_distance = 24 var/min_travel_distance = 1 @@ -27,9 +26,6 @@ /// The actual cooldown declaration for forceful retargeting, reference forced_retarget_time for time in between checks COOLDOWN_DECLARE(forced_retarget_cooldown) - /// Amount of times no path found has occured - var/no_path_found_amount = 0 - /// The time interval between calculating new paths if we cannot find a path var/no_path_found_period = (2.5 SECONDS) @@ -193,22 +189,12 @@ /mob/living/carbon/xenomorph/proc/set_path(list/path) current_path = path if(!path) - no_path_found = TRUE + COOLDOWN_START(src, no_path_found_cooldown, no_path_found_period) /mob/living/carbon/xenomorph/proc/move_to_next_turf(turf/T, max_range = ai_range) if(!T) return FALSE - if(no_path_found) - - if(no_path_found_amount > 0) - COOLDOWN_START(src, no_path_found_cooldown, no_path_found_period) - no_path_found = FALSE - no_path_found_amount++ - return FALSE - - no_path_found_amount = 0 - if((!current_path || (next_path_generation < world.time && current_target_turf != T)) && COOLDOWN_FINISHED(src, no_path_found_cooldown)) if(!XENO_CALCULATING_PATH(src) || current_target_turf != T) SSxeno_pathfinding.calculate_path(src, T, max_range, src, CALLBACK(src, PROC_REF(set_path)), list(src, current_target)) diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index a2b92007d9..825fa4dcc9 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -26,6 +26,7 @@ if(stat < UNCONSCIOUS) set_stat(UNCONSCIOUS) sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC + client?.soundOutput?.update_mob_environment_override() /// Called when [TRAIT_KNOCKEDOUT] is removed from the mob. /mob/living/proc/on_knockedout_trait_loss(datum/source) @@ -33,6 +34,7 @@ if(stat <= UNCONSCIOUS) update_stat() sound_environment_override = SOUND_ENVIRONMENT_NONE + client?.soundOutput?.update_mob_environment_override() /// Called when [TRAIT_IMMOBILIZED] is added to the mob. /mob/living/proc/on_immobilized_trait_gain(datum/source) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 64c8513108..72fd380e58 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -485,12 +485,10 @@ if(CONSCIOUS) if(stat >= UNCONSCIOUS) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) - sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC add_traits(list(/*TRAIT_HANDS_BLOCKED, */ TRAIT_INCAPACITATED, TRAIT_FLOORED), STAT_TRAIT) if(UNCONSCIOUS) if(stat >= UNCONSCIOUS) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) //adding trait sources should come before removing to avoid unnecessary updates - sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC if(DEAD) SEND_SIGNAL(src, COMSIG_MOB_STAT_SET_ALIVE) // remove_from_dead_mob_list() @@ -500,12 +498,10 @@ if(CONSCIOUS) if(. >= UNCONSCIOUS) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) - sound_environment_override = SOUND_ENVIRONMENT_NONE remove_traits(list(/*TRAIT_HANDS_BLOCKED, */ TRAIT_INCAPACITATED, TRAIT_FLOORED, /*TRAIT_CRITICAL_CONDITION*/), STAT_TRAIT) if(UNCONSCIOUS) if(. >= UNCONSCIOUS) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) - sound_environment_override = SOUND_ENVIRONMENT_NONE if(DEAD) SEND_SIGNAL(src, COMSIG_MOB_STAT_SET_DEAD) // REMOVE_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 775e69dc0b..38157a0673 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -18,6 +18,8 @@ update_Login_details() + SEND_SIGNAL(src, COMSIG_MOB_LOGIN) + client.images = null client.screen = null //remove hud items just in case if(!hud_used) @@ -58,6 +60,6 @@ client.init_verbs() - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGIN, src) - SEND_SIGNAL(client, COMSIG_CLIENT_MOB_LOGIN, src) - SEND_SIGNAL(src, COMSIG_MOB_LOGIN) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGGED_IN, src) + SEND_SIGNAL(client, COMSIG_CLIENT_MOB_LOGGED_IN, src) + SEND_SIGNAL(src, COMSIG_MOB_LOGGED_IN) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index f0e5bc48a8..e2f40506b2 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -28,7 +28,8 @@ I'll make some notes on where certain variable defines should probably go. Changing this around would probably require a good look-over the pre-existing code. */ - var/list/observers //The list of people observing this mob. + /// The list of people observing this mob. + var/list/mob/dead/observer/observers var/zone_selected = "chest" var/use_me = 1 //Allows all mobs to use the me verb by default, will have to manually specify they cannot @@ -433,4 +434,3 @@ return src.regenerate_icons() - diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 7bda746325..2664c14a8a 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -584,7 +584,7 @@ var/global/list/limb_types_by_name = list( alert_overlay.layer = FLOAT_LAYER alert_overlay.plane = FLOAT_PLANE - + alert_overlay.underlays.Cut() screen_alert.overlays += alert_overlay /mob/proc/reset_lighting_alpha() diff --git a/code/modules/projectiles/guns/misc.dm b/code/modules/projectiles/guns/misc.dm index 098dafb5fd..c65d422344 100644 --- a/code/modules/projectiles/guns/misc.dm +++ b/code/modules/projectiles/guns/misc.dm @@ -63,8 +63,8 @@ //M60 /obj/item/weapon/gun/m60 - name = "\improper M60 General Purpose Machine Gun" - desc = "The M60. The Pig. The Action Hero's wet dream. \nAlt-click it to open the feed cover and allow for reloading." + name = "\improper H-G Mk70 Machine Gun" + desc = "Part of the Henjin-Garcia repro line, the Mk70 found surprising niche in Frontier colony home defense against aggressive, largescale xenofauna. \nAlt-click to open the feed tray cover for handling reloads." icon = 'icons/obj/items/weapons/guns/guns_by_faction/colony.dmi' icon_state = "m60" item_state = "m60" diff --git a/code/modules/projectiles/magazines/misc.dm b/code/modules/projectiles/magazines/misc.dm index 87568c9532..9e832a2a05 100644 --- a/code/modules/projectiles/magazines/misc.dm +++ b/code/modules/projectiles/magazines/misc.dm @@ -19,8 +19,8 @@ //M60 /obj/item/ammo_magazine/m60 - name = "M60 ammo box (7.62x51mm)" - desc = "A blast from the past chambered in 7.62X51mm NATO." + name = "Mk70 belt box (7.62x51mm)" + desc = "Limited production run by Henjin-Garcia of old Earth weapons. A 100rnd belt box for their Mk70 reproduction of the M60 GPMG." caliber = "7.62x51mm" icon = 'icons/obj/items/weapons/guns/ammo_by_faction/colony.dmi' icon_state = "m60" //PLACEHOLDER diff --git a/code/modules/vehicles/van/van.dm b/code/modules/vehicles/van/van.dm index 0b99d682c0..3dcc603445 100644 --- a/code/modules/vehicles/van/van.dm +++ b/code/modules/vehicles/van/van.dm @@ -82,7 +82,7 @@ icon_state = null - RegisterSignal(SSdcs, COMSIG_GLOB_MOB_LOGIN, PROC_REF(add_default_image)) + RegisterSignal(SSdcs, COMSIG_GLOB_MOB_LOGGED_IN, PROC_REF(add_default_image)) for(var/I in GLOB.player_list) add_default_image(SSdcs, I) @@ -124,7 +124,7 @@ mobs_under += L RegisterSignal(L, COMSIG_PARENT_QDELETING, PROC_REF(remove_under_van)) - RegisterSignal(L, COMSIG_MOB_LOGIN, PROC_REF(add_client)) + RegisterSignal(L, COMSIG_MOB_LOGGED_IN, PROC_REF(add_client)) RegisterSignal(L, COMSIG_MOVABLE_MOVED, PROC_REF(check_under_van)) if(L.client) @@ -140,7 +140,7 @@ UnregisterSignal(L, list( COMSIG_PARENT_QDELETING, - COMSIG_MOB_LOGIN, + COMSIG_MOB_LOGGED_IN, COMSIG_MOVABLE_MOVED, )) diff --git a/colonialmarines.dme b/colonialmarines.dme index a79cbe1f0e..d201d6567f 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -136,6 +136,7 @@ #include "code\__DEFINES\dcs\signals\atom\signals_obj.dm" #include "code\__DEFINES\dcs\signals\atom\signals_projectile.dm" #include "code\__DEFINES\dcs\signals\atom\signals_turf.dm" +#include "code\__DEFINES\dcs\signals\atom\mob\signals_mind.dm" #include "code\__DEFINES\dcs\signals\atom\mob\signals_mob.dm" #include "code\__DEFINES\dcs\signals\atom\mob\living\signals_human.dm" #include "code\__DEFINES\dcs\signals\atom\mob\living\signals_living.dm" @@ -1403,8 +1404,10 @@ #include "code\modules\admin\game_master\game_master_submenu.dm" #include "code\modules\admin\game_master\resin_panel.dm" #include "code\modules\admin\game_master\sound_panel.dm" +#include "code\modules\admin\game_master\extra_buttons\fire_support_menu.dm" #include "code\modules\admin\game_master\extra_buttons\rappel_menu.dm" #include "code\modules\admin\game_master\extra_buttons\rename_platoon.dm" +#include "code\modules\admin\game_master\extra_buttons\toggle_ai_xeno_weeding.dm" #include "code\modules\admin\game_master\extra_buttons\toggle_capture_crit.dm" #include "code\modules\admin\game_master\extra_buttons\toggle_join_xeno.dm" #include "code\modules\admin\game_master\extra_buttons\toggle_vehicle_blockers.dm" diff --git a/html/changelogs/archive/2024-08.yml b/html/changelogs/archive/2024-08.yml index db9a377dbb..232a1874b3 100644 --- a/html/changelogs/archive/2024-08.yml +++ b/html/changelogs/archive/2024-08.yml @@ -26,3 +26,37 @@ - rscadd: 'added more cigarette options in the loadout, along with a golden zippo :cl:' +2024-08-10: + Doubleumc: + - qol: Adds the ability to hide your action buttons + - bugfix: Fixed 'hidden' action buttons being shown to observing players. + - qol: Made any observers transfer over when a Xenomorph evolves/de-evolves. + - rscadd: Added 'observe' functionality to Xenomorphs, allowing observers to view + the target's UI. + - rscadd: Made observing a player also show their action buttons. + - spellcheck: Made observers see the marine version of CAS warnings, rather than + the xeno one. + - qol: Made open TGUI windows transfer over when a xeno player evolves. + - bugfix: Fixed observing a monkey/farwa/stok/etc. locking the camera onto it. + - bugfix: Observer minimap should no longer occasionally show wrong / no map. + - code_imp: environmental reverb applies more reliably and only to positional sounds + - bugfix: Notifications should no longer emit light. + - bugfix: Sprite-click shots onto Xenos are no longer affected by limb-targeting + penalty, because it was an accuracy debuff when there is no inherent benefit + to targeting Xeno limbs. + - rscadd: Locking down dropship's doors closes them before locking. + - bugfix: Fix handling of sentry_computer deletion + - refactor: Refactored the overlay_lighting component to better handle objects deleting + - bugfix: Fix putting lights in bags somereason keeping the light on + - refactor: sentry laptop now uses camera manager component + - bugfix: less lag from xenos pathfinding unreachable targets + - rscadd: Added GM button to toggle AI xeno weeding + Kitsunemitsu: + - rscadd: Added 3 more railgun types + - balance: Railgun now changes it's stats based off the altitude + sunofang: + - rscadd: Due to budget increases, Close Air Support now has ammo. + - admin: Added a fire support menu for GM's to use. +2024-08-11: + private-tristan: + - balance: M56D has been buffed with more damage, accuracy, and firerate. diff --git a/strings/metatips.txt b/strings/metatips.txt index 17ffd607a7..e0ede9c626 100644 --- a/strings/metatips.txt +++ b/strings/metatips.txt @@ -12,6 +12,7 @@ As a mentor, you can become the imaginary friend of a new player to teach them! You shouldn't ignore what your allies are up to. Sometimes they can be organizing a flank on the radio, sometimes they can be walking up behind you with a buck-loaded shotgun. Either way, it pays to be alert to what they're doing, as much to as what the enemies are. The Wiki (https://cm-ss13.com/wiki) is a very useful repository of information about the game, such as weapons, equipment, xenomorph castes and their strains. It may not be fully up to date much of the time, but the basics are usually accurate. As an observer, you may see how much remaining hijack time is left in the status panel. +As an observer, you can quickly follow someone by ctrl-clicking on their sprite. You can always AdminHelp with the F1 key to question a member of staff regarding rules or game bugs. As ghost you are given extra tools for spectating the round: you can jump and follow specific players, get notifications about CAS and OB strikes, can see all health bars, and such. You can press ESC key to bring up the game pause menu. It allows you change settings, AdminHelp and MentorHelp, and even access the Web Maps of game by clicking at top right. diff --git a/tgui/packages/tgui/interfaces/GameMasterFireSupportMenu.jsx b/tgui/packages/tgui/interfaces/GameMasterFireSupportMenu.jsx new file mode 100644 index 0000000000..f8be7b7f95 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GameMasterFireSupportMenu.jsx @@ -0,0 +1,98 @@ +import { auto } from '@popperjs/core'; + +import { useBackend } from '../backend'; +import { Button, Collapsible, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +export const GameMasterFireSupportMenu = (props, context) => { + const { act, data } = useBackend(); + return ( + + +
+ + + + + + + + {data.missile_ordnance_options.map((ordnance, i) => ( + + ))} + + + + {data.orbital_ordnance_options.map((ordnance, i) => ( + + ))} + + + + {data.mortar_ordnance_options.map((ordnance, i) => ( + + ))} + + + + {data.misc_ordnance_options.map((ordnance, i) => ( + + ))} + +
+
+
+ ); +};