Middle Mouse Button now toggles equipment safety on mechs. (#66185) (#13292)

- Mechs now have a weapons_safety toggle. If set to true, clicking does not use equipment. This is mostly intended to allow users to keep from accidentally firing. Weapon safety defaults to off, but will keep the same state it was in between pilot exit/entry events.
- All mechs now use the green reticle mouse icon. If weapons_safety is enabled, the mouse is reverted to normal. The reticle (if shown) still turns red during an EMP-related weapons fault.
- AIs can use mech weapons if the safety is off, and use AI clicks if the safety is on.

Co-authored-by: zxaber <37497534+zxaber@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-05-03 17:05:31 +02:00
committed by GitHub
parent f25fa2b28b
commit 4c46268492
8 changed files with 65 additions and 21 deletions

View File

@@ -20,6 +20,11 @@
return return
next_click = world.time + 1 next_click = world.time + 1
var/list/modifiers = params2list(params)
if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, modifiers) & COMSIG_MOB_CANCEL_CLICKON)
return
if(!can_interact_with(A)) if(!can_interact_with(A))
return return
@@ -51,7 +56,6 @@
send2tgs_adminless_only("NOCHEAT", message) send2tgs_adminless_only("NOCHEAT", message)
return return
var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, SHIFT_CLICK)) if(LAZYACCESS(modifiers, SHIFT_CLICK))
if(LAZYACCESS(modifiers, CTRL_CLICK)) if(LAZYACCESS(modifiers, CTRL_CLICK))
CtrlShiftClickOn(A) CtrlShiftClickOn(A)

View File

@@ -34,6 +34,7 @@
light_range = 8 light_range = 8
generic_canpass = FALSE generic_canpass = FALSE
hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD) hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD)
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi'
///What direction will the mech face when entered/powered on? Defaults to South. ///What direction will the mech face when entered/powered on? Defaults to South.
var/dir_in = SOUTH var/dir_in = SOUTH
///How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain. ///How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain.
@@ -145,6 +146,8 @@
var/silicon_icon_state = null var/silicon_icon_state = null
///Currently ejecting, and unable to do things ///Currently ejecting, and unable to do things
var/is_currently_ejecting = FALSE var/is_currently_ejecting = FALSE
///Safety for weapons. Won't fire if enabled, and toggled by middle click.
var/weapons_safety = FALSE
var/datum/effect_system/smoke_spread/smoke_system = new var/datum/effect_system/smoke_spread/smoke_system = new
@@ -292,6 +295,37 @@
icon_state = get_mecha_occupancy_state() icon_state = get_mecha_occupancy_state()
return ..() return ..()
/**
* Toggles Weapons Safety
*
* Handles enabling or disabling the safety function.
*/
/obj/vehicle/sealed/mecha/proc/set_safety(mob/user)
weapons_safety = !weapons_safety
SEND_SOUND(user, sound('sound/machines/beep.ogg', volume = 25))
balloon_alert(user, "equipment [weapons_safety ? "safe" : "ready"]")
set_mouse_pointer()
/**
* Updates the pilot's mouse cursor override.
*
* If the mech's weapons safety is enabled, there should be no override, and the user gets their regular mouse cursor. If safety
* is off but the mech's equipment is disabled (such as by EMP), the cursor should be the red disabled version. Otherwise, if
* safety is off and the equipment is functional, the cursor should be the regular green cursor. This proc sets the cursor.
* correct and then updates it for each mob in the occupants list.
*/
/obj/vehicle/sealed/mecha/proc/set_mouse_pointer()
if(weapons_safety)
mouse_pointer = ""
else
if(equipment_disabled)
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse-disable.dmi'
else
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi'
for(var/mob/mob_occupant as anything in occupants)
mob_occupant.update_mouse_pointer()
//override this proc if you need to split up mecha control between multiple people (see savannah_ivanov.dm) //override this proc if you need to split up mecha control between multiple people (see savannah_ivanov.dm)
/obj/vehicle/sealed/mecha/auto_assign_occupant_flags(mob/M) /obj/vehicle/sealed/mecha/auto_assign_occupant_flags(mob/M)
if(driver_amount() < max_drivers) if(driver_amount() < max_drivers)
@@ -334,7 +368,7 @@
var/mob/mob_occupant = occupant var/mob/mob_occupant = occupant
SEND_SOUND(mob_occupant, sound('sound/items/timer.ogg', volume=50)) SEND_SOUND(mob_occupant, sound('sound/items/timer.ogg', volume=50))
to_chat(mob_occupant, span_notice("Equipment control unit has been rebooted successfully.")) to_chat(mob_occupant, span_notice("Equipment control unit has been rebooted successfully."))
mob_occupant.update_mouse_pointer() set_mouse_pointer()
/obj/vehicle/sealed/mecha/CheckParts(list/parts_list) /obj/vehicle/sealed/mecha/CheckParts(list/parts_list)
. = ..() . = ..()
@@ -561,14 +595,19 @@
///Called when a driver clicks somewhere. Handles everything like equipment, punches, etc. ///Called when a driver clicks somewhere. Handles everything like equipment, punches, etc.
/obj/vehicle/sealed/mecha/proc/on_mouseclick(mob/user, atom/target, list/modifiers) /obj/vehicle/sealed/mecha/proc/on_mouseclick(mob/user, atom/target, list/modifiers)
SIGNAL_HANDLER SIGNAL_HANDLER
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
set_safety(user)
return COMSIG_MOB_CANCEL_CLICKON
if(weapons_safety)
return
if(isAI(user)) //For AIs: If safeties are off, use mech functions. If safeties are on, use AI functions.
. = COMSIG_MOB_CANCEL_CLICKON
if(modifiers[SHIFT_CLICK]) //Allows things to be examined. if(modifiers[SHIFT_CLICK]) //Allows things to be examined.
return return
if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled
return return
if(completely_disabled || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT)) if(completely_disabled || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT))
return return
if(isAI(user) == !LAZYACCESS(modifiers, MIDDLE_CLICK))//BASICALLY if a human uses MMB, or an AI doesn't, then do nothing.
return
if(phasing) if(phasing)
balloon_alert(user, "not while [phasing]!") balloon_alert(user, "not while [phasing]!")
return return
@@ -633,11 +672,6 @@
target.mech_melee_attack(src, user) target.mech_melee_attack(src, user)
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown) TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown)
/obj/vehicle/sealed/mecha/proc/on_middlemouseclick(mob/user, atom/target, params)
SIGNAL_HANDLER
if(isAI(user))
on_mouseclick(user, target, params)
////////////////////////////////// //////////////////////////////////
//////// Movement procs //////// //////// Movement procs ////////
////////////////////////////////// //////////////////////////////////
@@ -970,7 +1004,7 @@
AI.remote_control = src AI.remote_control = src
to_chat(AI, AI.can_dominate_mechs ? span_greenannounce("Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!") :\ to_chat(AI, AI.can_dominate_mechs ? span_greenannounce("Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!") :\
span_notice("You have been uploaded to a mech's onboard computer.")) span_notice("You have been uploaded to a mech's onboard computer."))
to_chat(AI, "<span class='reallybig boldnotice'>Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions.</span>") to_chat(AI, "<span class='reallybig boldnotice'>Use Middle-Mouse to toggle equipment safety. Clicks with safety enabled will pass AI commands.</span>")
///Handles an actual AI (simple_animal mecha pilot) entering the mech ///Handles an actual AI (simple_animal mecha pilot) entering the mech
@@ -1040,6 +1074,7 @@
log_message("[newoccupant] moved in as pilot.", LOG_MECHA) log_message("[newoccupant] moved in as pilot.", LOG_MECHA)
setDir(dir_in) setDir(dir_in)
playsound(src, 'sound/machines/windowdoor.ogg', 50, TRUE) playsound(src, 'sound/machines/windowdoor.ogg', 50, TRUE)
set_mouse_pointer()
if(!internal_damage) if(!internal_damage)
SEND_SOUND(newoccupant, sound('sound/mecha/nominal.ogg',volume=50)) SEND_SOUND(newoccupant, sound('sound/mecha/nominal.ogg',volume=50))
return TRUE return TRUE
@@ -1158,7 +1193,6 @@
/obj/vehicle/sealed/mecha/add_occupant(mob/M, control_flags) /obj/vehicle/sealed/mecha/add_occupant(mob/M, control_flags)
RegisterSignal(M, COMSIG_LIVING_DEATH, .proc/mob_exit) RegisterSignal(M, COMSIG_LIVING_DEATH, .proc/mob_exit)
RegisterSignal(M, COMSIG_MOB_CLICKON, .proc/on_mouseclick) RegisterSignal(M, COMSIG_MOB_CLICKON, .proc/on_mouseclick)
RegisterSignal(M, COMSIG_MOB_MIDDLECLICKON, .proc/on_middlemouseclick) //For AIs
RegisterSignal(M, COMSIG_MOB_SAY, .proc/display_speech_bubble) RegisterSignal(M, COMSIG_MOB_SAY, .proc/display_speech_bubble)
. = ..() . = ..()
update_appearance() update_appearance()
@@ -1166,7 +1200,6 @@
/obj/vehicle/sealed/mecha/remove_occupant(mob/M) /obj/vehicle/sealed/mecha/remove_occupant(mob/M)
UnregisterSignal(M, COMSIG_LIVING_DEATH) UnregisterSignal(M, COMSIG_LIVING_DEATH)
UnregisterSignal(M, COMSIG_MOB_CLICKON) UnregisterSignal(M, COMSIG_MOB_CLICKON)
UnregisterSignal(M, COMSIG_MOB_MIDDLECLICKON)
UnregisterSignal(M, COMSIG_MOB_SAY) UnregisterSignal(M, COMSIG_MOB_SAY)
M.clear_alert(ALERT_CHARGE) M.clear_alert(ALERT_CHARGE)
M.clear_alert(ALERT_MECH_DAMAGE) M.clear_alert(ALERT_MECH_DAMAGE)

View File

@@ -2,7 +2,6 @@
force = 30 force = 30
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY) internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY)
armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 20, BOMB = 20, BIO = 0, FIRE = 100, ACID = 100) armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 20, BOMB = 20, BIO = 0, FIRE = 100, ACID = 100)
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi'
destruction_sleep_duration = 40 destruction_sleep_duration = 40
exit_delay = 40 exit_delay = 40

View File

@@ -181,15 +181,11 @@
take_damage(30 / severity, BURN, ENERGY, 1) take_damage(30 / severity, BURN, ENERGY, 1)
log_message("EMP detected", LOG_MECHA, color="red") log_message("EMP detected", LOG_MECHA, color="red")
if(istype(src, /obj/vehicle/sealed/mecha/combat)) //todo this stupid mouse icon should be a flag
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse-disable.dmi'
for(var/occus in occupants)
var/mob/living/occupant = occus
occupant.update_mouse_pointer()
if(!equipment_disabled && LAZYLEN(occupants)) //prevent spamming this message with back-to-back EMPs if(!equipment_disabled && LAZYLEN(occupants)) //prevent spamming this message with back-to-back EMPs
to_chat(occupants, span_warning("Error -- Connection to equipment control unit has been lost.")) to_chat(occupants, span_warning("Error -- Connection to equipment control unit has been lost."))
addtimer(CALLBACK(src, /obj/vehicle/sealed/mecha.proc/restore_equipment), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) addtimer(CALLBACK(src, /obj/vehicle/sealed/mecha.proc/restore_equipment), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
equipment_disabled = TRUE equipment_disabled = TRUE
set_mouse_pointer()
/obj/vehicle/sealed/mecha/should_atmos_process(datum/gas_mixture/air, exposed_temperature) /obj/vehicle/sealed/mecha/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return exposed_temperature > max_temperature return exposed_temperature > max_temperature

View File

@@ -122,6 +122,7 @@
data["cabin_pressure"] = round(return_pressure(), 0.01) data["cabin_pressure"] = round(return_pressure(), 0.01)
data["cabin_temp"] = return_temperature() data["cabin_temp"] = return_temperature()
data["dna_lock"] = dna_lock data["dna_lock"] = dna_lock
data["weapons_safety"] = weapons_safety
data["mech_view"] = ui_view.assigned_map data["mech_view"] = ui_view.assigned_map
if(radio) if(radio)
data["mech_electronics"] = list( data["mech_electronics"] = list(
@@ -268,6 +269,9 @@
tgui_alert(usr, "You cannot set a name that contains a word prohibited in IC chat!") tgui_alert(usr, "You cannot set a name that contains a word prohibited in IC chat!")
return return
name = userinput name = userinput
if("toggle_safety")
set_safety(usr)
return
if("dna_lock") if("dna_lock")
var/mob/living/carbon/user = usr var/mob/living/carbon/user = usr
if(!istype(user) || !user.dna) if(!istype(user) || !user.dna)

View File

@@ -13,11 +13,12 @@ export const ArmPane=(props:{weapon:MechWeapon}, context) => {
} = props.weapon; } = props.weapon;
const { const {
power_level, power_level,
weapons_safety,
} = data; } = data;
return ( return (
<Stack fill vertical> <Stack fill vertical>
<Stack.Item bold> <Stack.Item bold color={weapons_safety ? "red" : ""}>
{name} {weapons_safety ? "SAFETY OVERRIDE IN EFFECT" : name}
</Stack.Item> </Stack.Item>
<Stack.Item> <Stack.Item>
<Stack> <Stack>
@@ -62,7 +63,7 @@ export const ArmPane=(props:{weapon:MechWeapon}, context) => {
<Stack.Item> <Stack.Item>
<Snowflake weapon={props.weapon} /> <Snowflake weapon={props.weapon} />
</Stack.Item> </Stack.Item>
<Stack.Item> <Stack.Item color={weapons_safety ? "red" : ""}>
{desc} {desc}
</Stack.Item> </Stack.Item>
</Stack> </Stack>

View File

@@ -8,6 +8,7 @@ export const MechStatPane = (props, context) => {
const { const {
name, name,
integrity, integrity,
weapons_safety,
air_source, air_source,
cabin_pressure, cabin_pressure,
cabin_dangerous_highpressure, cabin_dangerous_highpressure,
@@ -42,6 +43,11 @@ export const MechStatPane = (props, context) => {
<LabeledList.Item label="Power"> <LabeledList.Item label="Power">
<PowerBar /> <PowerBar />
</LabeledList.Item> </LabeledList.Item>
<LabeledList.Item label="Safety">
<Button color={weapons_safety ? "red" : ""} onClick={() => act('toggle_safety')}>
{weapons_safety ? "Dis" : "En"}able
</Button>
</LabeledList.Item>
</LabeledList> </LabeledList>
</Section> </Section>
</Stack.Item> </Stack.Item>

View File

@@ -81,6 +81,7 @@ export type OperatorData = {
mech_electronics: MechElectronics; mech_electronics: MechElectronics;
right_arm_weapon: MechWeapon | null; right_arm_weapon: MechWeapon | null;
left_arm_weapon: MechWeapon | null; left_arm_weapon: MechWeapon | null;
weapons_safety: boolean;
mech_equipment: string[]; mech_equipment: string[];
mech_view: string; mech_view: string;
mineral_material_amount: number; mineral_material_amount: number;