Split up mecha.dm properly (#66986)

Co-authored-by: TiviPlus <572233640+TiviPlus@users.noreply.com>
This commit is contained in:
TiviPlus
2022-05-15 14:40:48 -04:00
committed by GitHub
co-authored by TiviPlus
parent 80d4f95239
commit 480751a6f4
7 changed files with 255 additions and 238 deletions
+84 -40
View File
@@ -538,14 +538,91 @@
diag_hud_set_mechcell()
diag_hud_set_mechstat()
/obj/vehicle/sealed/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech
. = ..()
if(enclosed || mecha_flags & SILICON_PILOT)
///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)
SIGNAL_HANDLER
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
set_safety(user)
return COMSIG_MOB_CANCEL_CLICKON
if(weapons_safety)
return
for(var/mob/living/cookedalive as anything in occupants)
if(cookedalive.fire_stacks < 5)
cookedalive.adjust_fire_stacks(1)
cookedalive.ignite_mob()
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.
return
if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled
return
if(completely_disabled || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT))
return
if(phasing)
balloon_alert(user, "not while [phasing]!")
return
if(user.incapacitated())
return
if(construction_state)
balloon_alert(user, "end maintenance first!")
return
if(!get_charge())
return
if(src == target)
return
var/dir_to_target = get_dir(src,target)
if(!(mecha_flags & OMNIDIRECTIONAL_ATTACKS) && dir_to_target && !(dir_to_target & dir))//wrong direction
return
if(internal_damage & MECHA_INT_CONTROL_LOST)
target = pick(view(3,target))
var/mob/living/livinguser = user
if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)))
balloon_alert(user, "wrong seat for equipment!")
return
var/obj/item/mecha_parts/mecha_equipment/selected
if(LAZYACCESS(modifiers, RIGHT_CLICK))
selected = equip_by_category[MECHA_R_ARM]
else
selected = equip_by_category[MECHA_L_ARM]
if(!selected)
return
if(!Adjacent(target) && (selected.range & MECHA_RANGED))
if(HAS_TRAIT(livinguser, TRAIT_PACIFISM) && selected.harmful)
to_chat(livinguser, span_warning("You don't want to harm other living beings!"))
return
if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, livinguser, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK)
return
INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, modifiers)
return
if((selected.range & MECHA_MELEE) && Adjacent(target))
if(isliving(target) && selected.harmful && HAS_TRAIT(livinguser, TRAIT_PACIFISM))
to_chat(livinguser, span_warning("You don't want to harm other living beings!"))
return
if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, livinguser, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK)
return
INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, modifiers)
return
if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_MELEE)))
to_chat(livinguser, span_warning("You're in the wrong seat to interact with your hands."))
return
var/on_cooldown = TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK)
var/adjacent = Adjacent(target)
if(SEND_SIGNAL(src, COMSIG_MECHA_MELEE_CLICK, livinguser, target, on_cooldown, adjacent) & COMPONENT_CANCEL_MELEE_CLICK)
return
if(on_cooldown || !adjacent)
return
if(internal_damage & MECHA_INT_CONTROL_LOST)
target = pick(oview(1,src))
if(!has_charge(melee_energy_drain))
return
use_power(melee_energy_drain)
if(force)
target.mech_melee_attack(src, user)
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown)
/// middle mouse click signal wrapper for AI users
/obj/vehicle/sealed/mecha/proc/on_middlemouseclick(mob/user, atom/target, params)
SIGNAL_HANDLER
if(isAI(user))
on_mouseclick(user, target, params)
///Displays a special speech bubble when someone inside the mecha speaks
/obj/vehicle/sealed/mecha/proc/display_speech_bubble(datum/source, list/speech_args)
@@ -556,20 +633,6 @@
speech_bubble_recipients.Add(M.client)
INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, image('icons/mob/talk.dmi', src, "machine[say_test(speech_args[SPEECH_MESSAGE])]",MOB_LAYER+1), speech_bubble_recipients, 30)
/obj/vehicle/sealed/mecha/enter_checks(mob/M)
if(atom_integrity <= 0)
to_chat(M, span_warning("You cannot get in the [src], it has been destroyed!"))
return FALSE
if(M.buckled)
to_chat(M, span_warning("You can't enter the exosuit while buckled."))
log_message("Permission denied (Buckled).", LOG_MECHA)
return FALSE
if(M.has_buckled_mobs())
to_chat(M, span_warning("You can't enter the exosuit with other creatures attached to you!"))
log_message("Permission denied (Attached mobs).", LOG_MECHA)
return FALSE
return ..()
/////////////////////////
////// Access stuff /////
@@ -586,25 +649,6 @@
return allowed(M)
///////////////////////
///// Power stuff /////
///////////////////////
/obj/vehicle/sealed/mecha/proc/has_charge(amount)
return (get_charge()>=amount)
/obj/vehicle/sealed/mecha/proc/get_charge()
return cell?.charge
/obj/vehicle/sealed/mecha/proc/use_power(amount)
return (get_charge() && cell.use(amount))
/obj/vehicle/sealed/mecha/proc/give_power(amount)
if(!isnull(get_charge()))
cell.give(amount)
return TRUE
return FALSE
/////////////////////////////////////
//////// Atmospheric stuff ////////
/////////////////////////////////////
@@ -1,88 +1,3 @@
///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)
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.
return
if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled
return
if(completely_disabled || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT))
return
if(phasing)
balloon_alert(user, "not while [phasing]!")
return
if(user.incapacitated())
return
if(construction_state)
balloon_alert(user, "end maintenance first!")
return
if(!get_charge())
return
if(src == target)
return
var/dir_to_target = get_dir(src,target)
if(!(mecha_flags & OMNIDIRECTIONAL_ATTACKS) && dir_to_target && !(dir_to_target & dir))//wrong direction
return
if(internal_damage & MECHA_INT_CONTROL_LOST)
target = pick(view(3,target))
var/mob/living/livinguser = user
if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)))
balloon_alert(user, "wrong seat for equipment!")
return
var/obj/item/mecha_parts/mecha_equipment/selected
if(LAZYACCESS(modifiers, RIGHT_CLICK))
selected = equip_by_category[MECHA_R_ARM]
else
selected = equip_by_category[MECHA_L_ARM]
if(!selected)
return
if(!Adjacent(target) && (selected.range & MECHA_RANGED))
if(HAS_TRAIT(livinguser, TRAIT_PACIFISM) && selected.harmful)
to_chat(livinguser, span_warning("You don't want to harm other living beings!"))
return
if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, livinguser, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK)
return
INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, modifiers)
return
if((selected.range & MECHA_MELEE) && Adjacent(target))
if(isliving(target) && selected.harmful && HAS_TRAIT(livinguser, TRAIT_PACIFISM))
to_chat(livinguser, span_warning("You don't want to harm other living beings!"))
return
if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, livinguser, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK)
return
INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, modifiers)
return
if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_MELEE)))
to_chat(livinguser, span_warning("You're in the wrong seat to interact with your hands."))
return
var/on_cooldown = TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK)
var/adjacent = Adjacent(target)
if(SEND_SIGNAL(src, COMSIG_MECHA_MELEE_CLICK, livinguser, target, on_cooldown, adjacent) & COMPONENT_CANCEL_MELEE_CLICK)
return
if(on_cooldown || !adjacent)
return
if(internal_damage & MECHA_INT_CONTROL_LOST)
target = pick(oview(1,src))
if(!has_charge(melee_energy_drain))
return
use_power(melee_energy_drain)
if(force)
target.mech_melee_attack(src, user)
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)
/***************** MECHA ACTIONS *****************/
/obj/vehicle/sealed/mecha/generate_action_type()
@@ -91,7 +6,6 @@
var/datum/action/vehicle/sealed/mecha/mecha = .
mecha.chassis = src
/datum/action/vehicle/sealed/mecha
icon_icon = 'icons/mob/actions/actions_mecha.dmi'
var/obj/vehicle/sealed/mecha/chassis
@@ -1,3 +1,38 @@
/*!
* # Mecha defence explanation
* Mechs focus is on a more heavy-but-slower damage approach
* For this they have the following mechanics
*
* ## Backstab
* Basically the tldr is that mechs are less flexible so we encourage good positioning, pretty simple
* ## Armor modules
* Pretty simple, adds armor, you can choose against what
* ## Internal damage
* When taking damage will force you to take some time to repair, encourages improvising in a fight
* Targetting different def zones will damage them to encurage a more strategic approach to fights
* where they target the "dangerous" modules
*/
/// returns a number for the damage multiplier for this relative angle/dir
/obj/vehicle/sealed/mecha/proc/get_armour_facing(relative_dir)
switch(relative_dir)
if(180) // BACKSTAB!
return facing_modifiers[MECHA_BACK_ARMOUR]
if(0, 45) // direct or 45 degrees off
return facing_modifiers[MECHA_FRONT_ARMOUR]
return facing_modifiers[MECHA_SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
///tries to deal internal damaget depending on the damage amount
/obj/vehicle/sealed/mecha/proc/try_deal_internal_damage(damage)
if(damage < internal_damage_threshold)
return
if(!prob(internal_damage_probability))
return
var/internal_damage_to_deal = possible_int_damage
internal_damage_to_deal &= ~mecha_flags
if(internal_damage_to_deal)
set_internal_damage(pick(bitfield_to_list(internal_damage_to_deal)))
/// tries to repair any internal damage and plays fluff for it
/obj/vehicle/sealed/mecha/proc/try_repair_int_damage(mob/user, flag_to_heal)
balloon_alert(user, get_int_repair_fluff_start(flag_to_heal))
+9 -20
View File
@@ -13,26 +13,6 @@
* where they target the "dangerous" modules
*/
/// returns a number for the damage multiplier for this relative angle/dir
/obj/vehicle/sealed/mecha/proc/get_armour_facing(relative_dir)
switch(relative_dir)
if(180) // BACKSTAB!
return facing_modifiers[MECHA_BACK_ARMOUR]
if(0, 45) // direct or 45 degrees off
return facing_modifiers[MECHA_FRONT_ARMOUR]
return facing_modifiers[MECHA_SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
///tries to deal internal damaget depending on the damage amount
/obj/vehicle/sealed/mecha/proc/try_deal_internal_damage(damage)
if(damage < internal_damage_threshold)
return
if(!prob(internal_damage_probability))
return
var/internal_damage_to_deal = possible_int_damage
internal_damage_to_deal &= ~mecha_flags
if(internal_damage_to_deal)
set_internal_damage(pick(bitfield_to_list(internal_damage_to_deal)))
/// tries to damage mech equipment depending on damage and where is being targetted
/obj/vehicle/sealed/mecha/proc/try_damage_component(damage, def_zone)
if(damage < component_damage_threshold)
@@ -194,6 +174,15 @@
log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red")
take_damage(5, BURN, 0, 1)
/obj/vehicle/sealed/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech
. = ..()
if(enclosed || mecha_flags & SILICON_PILOT)
return
for(var/mob/living/cookedalive as anything in occupants)
if(cookedalive.fire_stacks < 5)
cookedalive.adjust_fire_stacks(1)
cookedalive.ignite_mob()
/obj/vehicle/sealed/mecha/attackby_secondary(obj/item/weapon, mob/user, params)
if(istype(weapon, /obj/item/mecha_parts))
var/obj/item/mecha_parts/parts = weapon
@@ -24,3 +24,21 @@
capacitor = cap
else
capacitor = new /obj/item/stock_parts/capacitor(src)
///////////////////////
///// Power stuff /////
///////////////////////
/obj/vehicle/sealed/mecha/proc/has_charge(amount)
return (get_charge()>=amount)
/obj/vehicle/sealed/mecha/proc/get_charge()
return cell?.charge
/obj/vehicle/sealed/mecha/proc/use_power(amount)
return (get_charge() && cell.use(amount))
/obj/vehicle/sealed/mecha/proc/give_power(amount)
if(!isnull(get_charge()))
cell.give(amount)
return TRUE
return FALSE
@@ -1,3 +1,106 @@
/obj/vehicle/sealed/mecha/mob_try_enter(mob/M)
if(!ishuman(M)) // no silicons or drones in mechas.
return
if(HAS_TRAIT(M, TRAIT_PRIMITIVE)) //no lavalizards either.
to_chat(M, span_warning("The knowledge to use this device eludes you!"))
return
log_message("[M] tries to move into [src].", LOG_MECHA)
if(dna_lock && M.has_dna())
var/mob/living/carbon/entering_carbon = M
if(entering_carbon.dna.unique_enzymes != dna_lock)
to_chat(M, span_warning("Access denied. [name] is secured with a DNA lock."))
log_message("Permission denied (DNA LOCK).", LOG_MECHA)
return
if(!operation_allowed(M))
to_chat(M, span_warning("Access denied. Insufficient operation keycodes."))
log_message("Permission denied (No keycode).", LOG_MECHA)
return
. = ..()
if(.)
moved_inside(M)
/obj/vehicle/sealed/mecha/enter_checks(mob/M)
if(atom_integrity <= 0)
to_chat(M, span_warning("You cannot get in the [src], it has been destroyed!"))
return FALSE
if(M.buckled)
to_chat(M, span_warning("You can't enter the exosuit while buckled."))
log_message("Permission denied (Buckled).", LOG_MECHA)
return FALSE
if(M.has_buckled_mobs())
to_chat(M, span_warning("You can't enter the exosuit with other creatures attached to you!"))
log_message("Permission denied (Attached mobs).", LOG_MECHA)
return FALSE
return ..()
///proc called when a new non-mmi/AI mob enters this mech
/obj/vehicle/sealed/mecha/proc/moved_inside(mob/living/newoccupant)
if(!(newoccupant?.client))
return FALSE
if(ishuman(newoccupant) && !Adjacent(newoccupant))
return FALSE
add_occupant(newoccupant)
newoccupant.forceMove(src)
newoccupant.update_mouse_pointer()
add_fingerprint(newoccupant)
log_message("[newoccupant] moved in as pilot.", LOG_MECHA)
setDir(dir_in)
playsound(src, 'sound/machines/windowdoor.ogg', 50, TRUE)
set_mouse_pointer()
if(!internal_damage)
SEND_SOUND(newoccupant, sound('sound/mecha/nominal.ogg',volume=50))
return TRUE
///proc called when a new mmi mob tries to enter this mech
/obj/vehicle/sealed/mecha/proc/mmi_move_inside(obj/item/mmi/brain_obj, mob/user)
if(!(mecha_flags & MMI_COMPATIBLE))
to_chat(user, span_warning("This mecha is not compatible with MMIs!"))
return FALSE
if(!brain_obj.brain_check(user))
return FALSE
var/mob/living/brain/brain_mob = brain_obj.brainmob
if(LAZYLEN(occupants) >= max_occupants)
to_chat(user, span_warning("It's full!"))
return FALSE
if(dna_lock && (!brain_mob.stored_dna || (dna_lock != brain_mob.stored_dna.unique_enzymes)))
to_chat(user, span_warning("Access denied. [name] is secured with a DNA lock."))
return FALSE
visible_message(span_notice("[user] starts to insert an MMI into [name]."))
if(!do_after(user, 4 SECONDS, target = src))
to_chat(user, span_notice("You stop inserting the MMI."))
return FALSE
if(LAZYLEN(occupants) < max_occupants)
return mmi_moved_inside(brain_obj, user)
to_chat(user, span_warning("Maximum occupants exceeded!"))
return FALSE
///proc called when a new mmi mob enters this mech
/obj/vehicle/sealed/mecha/proc/mmi_moved_inside(obj/item/mmi/brain_obj, mob/user)
if(!(Adjacent(brain_obj) && Adjacent(user)))
return FALSE
if(!brain_obj.brain_check(user))
return FALSE
var/mob/living/brain/brain_mob = brain_obj.brainmob
if(!user.transferItemToLoc(brain_obj, src))
to_chat(user, span_warning("[brain_obj] is stuck to your hand, you cannot put it in [src]!"))
return FALSE
brain_obj.set_mecha(src)
add_occupant(brain_mob)//Note this forcemoves the brain into the mech to allow relaymove
mecha_flags |= SILICON_PILOT
brain_mob.reset_perspective(src)
brain_mob.remote_control = src
brain_mob.update_mouse_pointer()
setDir(dir_in)
log_message("[brain_obj] moved in as pilot.", LOG_MECHA)
if(!internal_damage)
SEND_SOUND(brain_obj, sound('sound/mecha/nominal.ogg',volume=50))
log_game("[key_name(user)] has put the MMI/posibrain of [key_name(brain_mob)] into [src] at [AREACOORD(src)]")
return TRUE
/obj/vehicle/sealed/mecha/mob_exit(mob/M, silent, forced)
var/atom/movable/mob_container
var/turf/newloc = get_turf(src)
@@ -78,24 +181,3 @@
else
to_chat(user, span_notice("You stop exiting the mech. Weapons are enabled again."))
is_currently_ejecting = FALSE
/obj/vehicle/sealed/mecha/mob_try_enter(mob/M)
if(!ishuman(M)) // no silicons or drones in mechas.
return
if(HAS_TRAIT(M, TRAIT_PRIMITIVE)) //no lavalizards either.
to_chat(M, span_warning("The knowledge to use this device eludes you!"))
return
log_message("[M] tries to move into [src].", LOG_MECHA)
if(dna_lock && M.has_dna())
var/mob/living/carbon/entering_carbon = M
if(entering_carbon.dna.unique_enzymes != dna_lock)
to_chat(M, span_warning("Access denied. [name] is secured with a DNA lock."))
log_message("Permission denied (DNA LOCK).", LOG_MECHA)
return
if(!operation_allowed(M))
to_chat(M, span_warning("Access denied. Insufficient operation keycodes."))
log_message("Permission denied (No keycode).", LOG_MECHA)
return
. = ..()
if(.)
moved_inside(M)
+6 -71
View File
@@ -1,3 +1,9 @@
/// Sets the direction of the mecha and all of its occcupents, required for FOV. Alternatively one could make a recursive contents registration and register topmost direction changes in the fov component
/obj/vehicle/sealed/mecha/setDir(newdir)
. = ..()
for(var/mob/living/occupant as anything in occupants)
occupant.setDir(newdir)
///Plays the mech step sound effect. Split from movement procs so that other mechs (HONK) can override this one specific part.
/obj/vehicle/sealed/mecha/proc/play_stepsound()
SIGNAL_HANDLER
@@ -141,74 +147,3 @@
var/mob/mob_obstacle = obstacle
if(mob_obstacle.move_resist <= move_force)
step(obstacle, dir)
/obj/vehicle/sealed/mecha/proc/moved_inside(mob/living/newoccupant)
if(!(newoccupant?.client))
return FALSE
if(ishuman(newoccupant) && !Adjacent(newoccupant))
return FALSE
add_occupant(newoccupant)
newoccupant.forceMove(src)
newoccupant.update_mouse_pointer()
add_fingerprint(newoccupant)
log_message("[newoccupant] moved in as pilot.", LOG_MECHA)
setDir(dir_in)
playsound(src, 'sound/machines/windowdoor.ogg', 50, TRUE)
set_mouse_pointer()
if(!internal_damage)
SEND_SOUND(newoccupant, sound('sound/mecha/nominal.ogg',volume=50))
return TRUE
/obj/vehicle/sealed/mecha/proc/mmi_move_inside(obj/item/mmi/brain_obj, mob/user)
if(!(mecha_flags & MMI_COMPATIBLE))
to_chat(user, span_warning("This mecha is not compatible with MMIs!"))
return FALSE
if(!brain_obj.brain_check(user))
return FALSE
var/mob/living/brain/brain_mob = brain_obj.brainmob
if(LAZYLEN(occupants) >= max_occupants)
to_chat(user, span_warning("It's full!"))
return FALSE
if(dna_lock && (!brain_mob.stored_dna || (dna_lock != brain_mob.stored_dna.unique_enzymes)))
to_chat(user, span_warning("Access denied. [name] is secured with a DNA lock."))
return FALSE
visible_message(span_notice("[user] starts to insert an MMI into [name]."))
if(!do_after(user, 4 SECONDS, target = src))
to_chat(user, span_notice("You stop inserting the MMI."))
return FALSE
if(LAZYLEN(occupants) < max_occupants)
return mmi_moved_inside(brain_obj, user)
to_chat(user, span_warning("Maximum occupants exceeded!"))
return FALSE
/obj/vehicle/sealed/mecha/proc/mmi_moved_inside(obj/item/mmi/brain_obj, mob/user)
if(!(Adjacent(brain_obj) && Adjacent(user)))
return FALSE
if(!brain_obj.brain_check(user))
return FALSE
var/mob/living/brain/brain_mob = brain_obj.brainmob
if(!user.transferItemToLoc(brain_obj, src))
to_chat(user, span_warning("[brain_obj] is stuck to your hand, you cannot put it in [src]!"))
return FALSE
brain_obj.set_mecha(src)
add_occupant(brain_mob)//Note this forcemoves the brain into the mech to allow relaymove
mecha_flags |= SILICON_PILOT
brain_mob.reset_perspective(src)
brain_mob.remote_control = src
brain_mob.update_mouse_pointer()
setDir(dir_in)
log_message("[brain_obj] moved in as pilot.", LOG_MECHA)
if(!internal_damage)
SEND_SOUND(brain_obj, sound('sound/mecha/nominal.ogg',volume=50))
log_game("[key_name(user)] has put the MMI/posibrain of [key_name(brain_mob)] into [src] at [AREACOORD(src)]")
return TRUE
/// Sets the direction of the mecha and all of its occcupents, required for FOV. Alternatively one could make a recursive contents registration and register topmost direction changes in the fov component
/obj/vehicle/sealed/mecha/setDir(newdir)
. = ..()
for(var/mob/living/occupant as anything in occupants)
occupant.setDir(newdir)