diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm
index 11c65df87f0..deee90e4424 100644
--- a/code/__DEFINES/cooldowns.dm
+++ b/code/__DEFINES/cooldowns.dm
@@ -31,7 +31,7 @@
//Mecha cooldowns
#define COOLDOWN_MECHA_MESSAGE "mecha_message"
-#define COOLDOWN_MECHA_EQUIPMENT "mecha_equipment"
+#define COOLDOWN_MECHA_EQUIPMENT(type) ("mecha_equip_[type]")
#define COOLDOWN_MECHA_ARMOR "mecha_armor"
#define COOLDOWN_MECHA_MELEE_ATTACK "mecha_melee"
#define COOLDOWN_MECHA_SMOKE "mecha_smoke"
diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm
index 80dff1870a9..9e698604b8d 100644
--- a/code/__DEFINES/mecha.dm
+++ b/code/__DEFINES/mecha.dm
@@ -23,11 +23,26 @@
#define MECHA_MELEE (1 << 0)
#define MECHA_RANGED (1 << 1)
-#define MECHA_FRONT_ARMOUR 1
-#define MECHA_SIDE_ARMOUR 2
-#define MECHA_BACK_ARMOUR 3
+#define MECHA_FRONT_ARMOUR "mechafront"
+#define MECHA_SIDE_ARMOUR "mechaside"
+#define MECHA_BACK_ARMOUR "mechaback"
+
+#define MECHA_WEAPON "mecha_weapon" //l and r arm weapon type
+#define MECHA_L_ARM "mecha_l_arm"
+#define MECHA_R_ARM "mecha_r_arm"
+#define MECHA_UTILITY "mecha_utility"
+#define MECHA_POWER "mecha_power"
+#define MECHA_ARMOR "mecha_armor"
#define MECHA_LOCKED 0
#define MECHA_SECURE_BOLTS 1
#define MECHA_LOOSE_BOLTS 2
#define MECHA_OPEN_HATCH 3
+
+// Some mechs must (at least for now) use snowflake handling of their UI elements, these defines are for that
+// when changing MUST update the same-named tsx file constants
+#define MECHA_SNOWFLAKE_ID_SLEEPER "sleeper_snowflake"
+#define MECHA_SNOWFLAKE_ID_SYRINGE "syringe_snowflake"
+#define MECHA_SNOWFLAKE_ID_MODE "mode_snowflake"
+#define MECHA_SNOWFLAKE_ID_EXTINGUISHER "extinguisher_snowflake"
+#define MECHA_SNOWFLAKE_ID_EJECTOR "ejector_snowflake"
diff --git a/code/modules/asset_cache/assets/mecha.dm b/code/modules/asset_cache/assets/mecha.dm
new file mode 100644
index 00000000000..ced0fcf234b
--- /dev/null
+++ b/code/modules/asset_cache/assets/mecha.dm
@@ -0,0 +1,5 @@
+/datum/asset/spritesheet/mechaarmor
+ name = "mechaarmor"
+
+/datum/asset/spritesheet/mechaarmor/create_spritesheets()
+ InsertAll("", 'icons/ui_icons/mecha/armor.dmi')
diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
index f9390fe6900..d68c5b38764 100644
--- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
@@ -74,7 +74,7 @@
targets_from = WEAKREF(M)
allow_movement_on_non_turfs = TRUE //duh
var/do_ranged = 0
- for(var/equip in mecha.equipment)
+ for(var/equip in mecha.flat_equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = equip
if(ME.range & MECHA_RANGED)
do_ranged = 1
@@ -136,7 +136,7 @@
/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/mecha_reload()
if(mecha)
- for(var/equip in mecha.equipment)
+ for(var/equip in mecha.flat_equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = equip
if(ME.needs_rearm())
ME.rearm()
@@ -145,7 +145,7 @@
/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/get_mecha_equip_by_flag(flag = MECHA_RANGED)
. = list()
if(mecha)
- for(var/equip in mecha.equipment)
+ for(var/equip in mecha.flat_equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = equip
if((ME.range & flag) && ME.action_checks(ME)) //this looks weird, but action_checks() just needs any atom, so I spoofed it here
. += ME
diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm
index 7b4eb5c8e45..0652e33e801 100644
--- a/code/modules/research/designs/mecha_designs.dm
+++ b/code/modules/research/designs/mecha_designs.dm
@@ -392,32 +392,22 @@
construction_time = 100
category = list("Exosuit Equipment")
-/datum/design/mech_energy_relay
- name = "Exosuit Module (Tesla Energy Relay)"
- desc = "Tesla Energy Relay"
- id = "mech_energy_relay"
- build_type = MECHFAB
- build_path = /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
- materials = list(/datum/material/iron=10000,/datum/material/glass = 2000,/datum/material/gold=2000,/datum/material/silver=3000)
- construction_time = 100
- category = list("Exosuit Equipment")
-
/datum/design/mech_ccw_armor
name = "Exosuit Module (Reactive Armor Booster Module)"
- desc = "Exosuit-mounted armor booster."
+ desc = "Exosuit-mounted melee armor booster."
id = "mech_ccw_armor"
build_type = MECHFAB
- build_path = /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster
+ build_path = /obj/item/mecha_parts/mecha_equipment/armor/anticcw_armor_booster
materials = list(/datum/material/iron=20000,/datum/material/silver=5000)
construction_time = 100
category = list("Exosuit Equipment")
/datum/design/mech_proj_armor
name = "Exosuit Module (Reflective Armor Booster Module)"
- desc = "Exosuit-mounted armor booster."
+ desc = "Exosuit-mounted ranged armor booster."
id = "mech_proj_armor"
build_type = MECHFAB
- build_path = /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
+ build_path = /obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster
materials = list(/datum/material/iron=20000,/datum/material/gold=5000)
construction_time = 100
category = list("Exosuit Equipment")
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index bfadc98b247..25c8633a06a 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -1804,7 +1804,6 @@
prereq_ids = list("adv_mecha", "bluespace_power")
design_ids = list(
"mech_ccw_armor",
- "mech_energy_relay",
"mech_proj_armor",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm
index 45df56e2379..364594955e8 100644
--- a/code/modules/uplink/uplink_items/job.dm
+++ b/code/modules/uplink/uplink_items/job.dm
@@ -241,16 +241,6 @@
cost = 15
restricted_roles = list(JOB_CLOWN)
-/datum/uplink_item/role_restricted/concealed_weapon_bay
- name = "Concealed Weapon Bay"
- desc = "A modification for non-combat mechas that allows them to equip one piece of equipment designed for combat mechs. \
- It also hides the equipped weapon from plain sight. \
- Only one can fit on a mecha."
- progression_minimum = 30 MINUTES
- item = /obj/item/mecha_parts/concealed_weapon_bay
- cost = 3
- restricted_roles = list(JOB_ROBOTICIST, JOB_RESEARCH_DIRECTOR)
-
/datum/uplink_item/role_restricted/clowncar
name = "Clown Car"
desc = "The Clown Car is the ultimate transportation method for any worthy clown! \
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index 29269963665..fe14aaf1988 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -33,6 +33,7 @@
light_on = FALSE
light_range = 8
generic_canpass = FALSE
+ hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD)
///What direction will the mech face when entered/powered on? Defaults to 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.
@@ -43,10 +44,8 @@
var/melee_energy_drain = 15
///The minimum amount of energy charge consumed by leg overload
var/overload_step_energy_drain_min = 100
- ///chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act.
- var/deflect_chance = 10
- ///Modifiers for directional armor
- var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 1.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 0.5)
+ ///Modifiers for directional damage reduction
+ var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 0.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 1.5)
///if we cant use our equipment(such as due to EMP)
var/equipment_disabled = FALSE
/// Keeps track of the mech's cell
@@ -89,10 +88,17 @@
var/list/trackers = list()
var/max_temperature = 25000
- ///health percentage below which internal damage is possible
- var/internal_damage_threshold = 50
+
///Bitflags for internal damage
var/internal_damage = NONE
+ /// damage amount above which we can take internal damages
+ var/internal_damage_threshold = 15
+ /// % chance for internal damage to occur
+ var/internal_damage_probability = 20
+ /// list of possibly dealt internal damage for this mech type
+ var/possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_INT_TANK_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT
+ /// damage threshold above which we take component damage
+ var/component_damage_threshold = 10
///required access level for mecha operation
var/list/operation_req_access = list()
@@ -102,11 +108,22 @@
///Typepath for the wreckage it spawns when destroyed
var/wreckage
- var/list/equipment = list()
- ///Current active equipment
- var/obj/item/mecha_parts/mecha_equipment/selected
- ///Maximum amount of equipment we can have
- var/max_equip = 3
+ ///assoc list: key-typepathlist before init, key-equipmentlist after
+ var/list/equip_by_category = list(
+ MECHA_L_ARM = null,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
+ ///assoc list: max equips for non-arm modules key-count
+ var/list/max_equip_by_category = list(
+ MECHA_UTILITY = 0,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 0,
+ )
+ ///flat equipment for iteration
+ var/list/flat_equipment
///Whether our steps are silent due to no gravity
var/step_silent = FALSE
@@ -167,14 +184,19 @@
///Bool for whether this mech can only be used on lavaland
var/lavaland_only = FALSE
-
- hud_possible = list (DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD)
+ /// Ui size, so you can make the UI bigger if you let it load a lot of stuff
+ var/ui_x = 1100
+ /// Ui size, so you can make the UI bigger if you let it load a lot of stuff
+ var/ui_y = 600
+ /// ref to screen object that displays in the middle of the UI
+ var/atom/movable/screen/mech_view/ui_view
/obj/item/radio/mech //this has to go somewhere
subspace_transmission = TRUE
/obj/vehicle/sealed/mecha/Initialize(mapload)
. = ..()
+ ui_view = new(null, src)
if(enclosed)
internal_tank = new (src)
RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE , .proc/disconnect_air)
@@ -215,19 +237,31 @@
AddElement(/datum/element/atmos_sensitive, mapload)
become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT)
ADD_TRAIT(src, TRAIT_ASHSTORM_IMMUNE, ROUNDSTART_TRAIT) //protects pilots from ashstorms.
+ for(var/key in equip_by_category)
+ if(key == MECHA_L_ARM || key == MECHA_R_ARM)
+ var/path = equip_by_category[key]
+ if(!path)
+ continue
+ var/obj/item/mecha_parts/mecha_equipment/thing = new path
+ thing.attach(src, key == MECHA_R_ARM)
+ continue
+ for(var/path in equip_by_category[key])
+ var/obj/item/mecha_parts/mecha_equipment/thing = new path
+ thing.attach(src, FALSE)
+ equip_by_category[key] -= path
/obj/vehicle/sealed/mecha/Destroy()
for(var/ejectee in occupants)
mob_exit(ejectee, TRUE, TRUE)
- if(LAZYLEN(equipment))
- for(var/obj/item/mecha_parts/mecha_equipment/equip as anything in equipment)
+ if(LAZYLEN(flat_equipment))
+ for(var/obj/item/mecha_parts/mecha_equipment/equip as anything in flat_equipment)
equip.detach(loc)
qdel(equip)
radio = null
STOP_PROCESSING(SSobj, src)
- LAZYCLEARLIST(equipment)
+ LAZYCLEARLIST(flat_equipment)
QDEL_NULL(cell)
QDEL_NULL(scanmod)
@@ -236,6 +270,7 @@
QDEL_NULL(cabin_air)
QDEL_NULL(spark_system)
QDEL_NULL(smoke_system)
+ QDEL_NULL(ui_view)
GLOB.mechas_list -= src //global mech list
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
@@ -361,12 +396,9 @@
. += "It's heavily damaged."
else
. += "It's falling apart."
- var/hide_weapon = locate(/obj/item/mecha_parts/concealed_weapon_bay) in contents
- var/hidden_weapon = hide_weapon ? (locate(/obj/item/mecha_parts/mecha_equipment/weapon) in equipment) : null
- var/list/visible_equipment = equipment - hidden_weapon
- if(length(visible_equipment))
+ if(LAZYLEN(flat_equipment))
. += "It's equipped with:"
- for(var/obj/item/mecha_parts/mecha_equipment/ME in visible_equipment)
+ for(var/obj/item/mecha_parts/mecha_equipment/ME as anything in flat_equipment)
. += "[icon2html(ME, user)] \A [ME]."
if(enclosed)
return
@@ -548,26 +580,32 @@
if(internal_damage & MECHA_INT_CONTROL_LOST)
target = pick(view(3,target))
var/mob/living/livinguser = user
- if(selected)
- if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)))
- balloon_alert(user, "wrong seat for equipment!")
+ 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(!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)
+ if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, livinguser, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK)
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)
+ 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
@@ -750,23 +788,53 @@
//////// Internal damage ////////
///////////////////////////////////
-/obj/vehicle/sealed/mecha/proc/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null)
- if(!islist(possible_int_damage) || !length(possible_int_damage))
+/// 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))
+ log_message("[key_name(user)] starting internal damage repair for flag [flag_to_heal]", LOG_MECHA)
+ if(!do_after(user, 10 SECONDS, src))
+ balloon_alert(user, get_int_repair_fluff_fail(flag_to_heal))
+ log_message("Internal damage repair for flag [flag_to_heal] failed.", LOG_MECHA, color="red")
return
- if(prob(20))
- if(ignore_threshold || atom_integrity*100/max_integrity < internal_damage_threshold)
- for(var/T in possible_int_damage)
- if(internal_damage & T)
- possible_int_damage -= T
- if (length(possible_int_damage))
- var/int_dam_flag = pick(possible_int_damage)
- if(int_dam_flag)
- set_internal_damage(int_dam_flag)
- if(prob(5))
- if(ignore_threshold || atom_integrity*100/max_integrity < internal_damage_threshold)
- if(LAZYLEN(equipment))
- var/obj/item/mecha_parts/mecha_equipment/ME = pick(equipment)
- qdel(ME)
+ clear_internal_damage(flag_to_heal)
+ balloon_alert(user, get_int_repair_fluff_end(flag_to_heal))
+ log_message("Finished internal damage repair for flag [flag_to_heal]", LOG_MECHA)
+
+///gets the starting balloon alert flufftext
+/obj/vehicle/sealed/mecha/proc/get_int_repair_fluff_start(flag)
+ switch(flag)
+ if(MECHA_INT_FIRE)
+ return "activating internal fire supression..."
+ if(MECHA_INT_TEMP_CONTROL)
+ return "resetting temperature module..."
+ if(MECHA_INT_TANK_BREACH)
+ return "activating tank sealant..."
+ if(MECHA_INT_CONTROL_LOST)
+ return "recalibrating coordination system..."
+
+///gets the successful finish balloon alert flufftext
+/obj/vehicle/sealed/mecha/proc/get_int_repair_fluff_end(flag)
+ switch(flag)
+ if(MECHA_INT_FIRE)
+ return "internal fire supressed"
+ if(MECHA_INT_TEMP_CONTROL)
+ return "temperature chip reactivated"
+ if(MECHA_INT_TANK_BREACH)
+ return "air tank sealed"
+ if(MECHA_INT_CONTROL_LOST)
+ return "coordination re-established"
+
+///gets the on-fail balloon alert flufftext
+/obj/vehicle/sealed/mecha/proc/get_int_repair_fluff_fail(flag)
+ switch(flag)
+ if(MECHA_INT_FIRE)
+ return "fire supression canceled"
+ if(MECHA_INT_TEMP_CONTROL)
+ return "reset aborted"
+ if(MECHA_INT_TANK_BREACH)
+ return "sealant deactivated"
+ if(MECHA_INT_CONTROL_LOST)
+ return "recalibration failed"
/obj/vehicle/sealed/mecha/proc/set_internal_damage(int_dam_flag)
internal_damage |= int_dam_flag
@@ -966,7 +1034,6 @@
/obj/vehicle/sealed/mecha/generate_actions()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals, VEHICLE_CONTROL_SETTINGS)
- initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip, VEHICLE_CONTROL_EQUIPMENT)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/strafe, VEHICLE_CONTROL_DRIVE)
@@ -1089,8 +1156,7 @@
mecha_flags &= ~SILICON_PILOT
mob_container.forceMove(newloc)//ejecting mob container
log_message("[mob_container] moved out.", LOG_MECHA)
- ejector << browse(null, "window=exosuit")
-
+ SStgui.close_user_uis(M, src)
if(istype(mob_container, /obj/item/mmi))
var/obj/item/mmi/mmi = mob_container
if(mmi.brainmob)
@@ -1148,17 +1214,10 @@
return (get_charge()>=amount)
/obj/vehicle/sealed/mecha/proc/get_charge()
- for(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/R in equipment)
- var/relay_charge = R.get_charge()
- if(relay_charge)
- return relay_charge
- if(cell)
- return max(0, cell.charge)
+ return cell?.charge
/obj/vehicle/sealed/mecha/proc/use_power(amount)
- if(get_charge() && cell.use(amount))
- return TRUE
- return FALSE
+ return (get_charge() && cell.use(amount))
/obj/vehicle/sealed/mecha/proc/give_power(amount)
if(!isnull(get_charge()))
@@ -1208,7 +1267,7 @@
return FALSE
var/ammo_needed
var/found_gun
- for(var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun in equipment)
+ for(var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun in flat_equipment)
ammo_needed = 0
if(!istype(gun, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic) && gun.ammo_type == A.ammo_type)
diff --git a/code/modules/vehicles/mecha/combat/combat.dm b/code/modules/vehicles/mecha/combat/combat.dm
index 6e4cf7a8d58..7f6265fd714 100644
--- a/code/modules/vehicles/mecha/combat/combat.dm
+++ b/code/modules/vehicles/mecha/combat/combat.dm
@@ -1,7 +1,6 @@
/obj/vehicle/sealed/mecha/combat
force = 30
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY)
- internal_damage_threshold = 50
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
@@ -11,9 +10,8 @@
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi'
return ..()
-
/obj/vehicle/sealed/mecha/combat/proc/max_ammo() //Max the ammo stored for Nuke Ops mechs, or anyone else that calls this
- for(var/obj/item/I in equipment)
- if(istype(I, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/))
+ for(var/obj/item/I as anything in flat_equipment)
+ if(istype(I, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic))
var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun = I
gun.projectiles_cache = gun.projectiles_cache_max
diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm
index fb0b34ae2aa..862f4fcdb8c 100644
--- a/code/modules/vehicles/mecha/combat/durand.dm
+++ b/code/modules/vehicles/mecha/combat/durand.dm
@@ -6,11 +6,15 @@
movedelay = 4
dir_in = 1 //Facing North.
max_integrity = 400
- deflect_chance = 20
armor = list(MELEE = 40, BULLET = 35, LASER = 15, ENERGY = 10, BOMB = 20, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 30000
force = 40
wreckage = /obj/structure/mecha_wreckage/durand
+ max_equip_by_category = list(
+ MECHA_UTILITY = 1,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 3,
+ )
var/obj/durand_shield/shield
diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm
index e9fa0c1a24e..43824350ee0 100644
--- a/code/modules/vehicles/mecha/combat/gygax.dm
+++ b/code/modules/vehicles/mecha/combat/gygax.dm
@@ -7,14 +7,16 @@
movedelay = 3
dir_in = 1 //Facing North.
max_integrity = 250
- deflect_chance = 5
armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 25000
leg_overload_coeff = 80
force = 25
wreckage = /obj/structure/mecha_wreckage/gygax
- internal_damage_threshold = 35
- max_equip = 3
+ max_equip_by_category = list(
+ MECHA_UTILITY = 1,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 2,
+ )
step_energy_drain = 3
/obj/vehicle/sealed/mecha/combat/gygax/generate_actions()
@@ -50,7 +52,6 @@
icon_state = "darkgygax"
base_icon_state = "darkgygax"
max_integrity = 300
- deflect_chance = 20
armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 35, BOMB = 20, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 35000
leg_overload_coeff = 70
@@ -58,21 +59,22 @@
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/gygax/dark
- max_equip = 5
+ max_equip_by_category = list(
+ MECHA_UTILITY = 2,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 3,
+ )
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/thrusters/ion),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/anticcw_armor_booster, /obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster),
+ )
destruction_sleep_duration = 20
/obj/vehicle/sealed/mecha/combat/gygax/dark/loaded/Initialize(mapload)
. = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
- ME.attach(src)
max_ammo()
/obj/vehicle/sealed/mecha/combat/gygax/dark/add_cell(obj/item/stock_parts/cell/C=null)
diff --git a/code/modules/vehicles/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm
index 3f94eebfcef..b3b5aa3bc9d 100644
--- a/code/modules/vehicles/mecha/combat/honker.dm
+++ b/code/modules/vehicles/mecha/combat/honker.dm
@@ -5,140 +5,24 @@
base_icon_state = "honker"
movedelay = 3
max_integrity = 140
- deflect_chance = 60
- internal_damage_threshold = 60
armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 25000
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_THEATRE)
wreckage = /obj/structure/mecha_wreckage/honker
mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE
- max_equip = 3
+ max_equip_by_category = list(
+ MECHA_UTILITY = 2,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 0,
+ )
var/squeak = TRUE
-/obj/vehicle/sealed/mecha/combat/honker/get_stats_part(mob/user)
- var/integrity = atom_integrity/max_integrity*100
- var/cell_charge = get_charge()
- var/datum/gas_mixture/int_tank_air = internal_tank.return_air()
- var/tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
- var/tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
- var/cabin_pressure = round(return_pressure(),0.01)
- return {"[report_internal_damage()]
- [integrity<30?"DAMAGE LEVEL CRITICAL
":null]
- [internal_damage&MECHA_INT_TEMP_CONTROL?"CLOWN SUPPORT SYSTEM MALFUNCTION
":null]
- [internal_damage&MECHA_INT_TANK_BREACH?"GAS TANK HONK
":null]
- [internal_damage&MECHA_INT_CONTROL_LOST?"HONK-A-DOODLE - Recalibrate
":null]
- IntegriHONK: [integrity]%
- PowerHONK charge: [isnull(cell_charge)?"No power cell installed":"[cell.percent()]%"]
- Air source: [use_internal_tank?"Internal Airtank":"Environment"]
- AirHONK pressure: [tank_pressure]kPa
- AirHONK temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
- HONK pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- HONK temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
- Lights: [(mecha_flags & LIGHTS_ON)?"on":"off"]
- [dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":null]
- "}
-
-/obj/vehicle/sealed/mecha/combat/honker/get_ssticker_function()
- . = {"
- function SSticker() {
- setInterval(function(){
- window.location='byond://?src=[REF(src)]&update_content=1';
- document.body.style.color = get_rand_color_string();
- document.body.style.background = get_rand_color_string();
- }, 1000);
- }
-
- function get_rand_color_string() {
- var color = new Array;
- for(var i=0;i<3;i++){
- color.push(Math.floor(Math.random()*255));
- }
- return "rgb("+color.toString()+")";
- }
- "}
-
-/obj/vehicle/sealed/mecha/combat/honker/get_commands()
- var/output = {"
- "}
- output += ..()
- return output
-
-
-/obj/vehicle/sealed/mecha/combat/honker/get_equipment_list()
- if(!LAZYLEN(equipment))
- return
- var/output = "Honk-ON-Systems:"
- for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment)
- output += "
[MT.get_equip_info()]
"
- output += "
"
- return output
-
-/obj/vehicle/sealed/mecha/combat/honker/get_equipment_menu() //outputs mecha html equipment menu
- . = {"
-
-
-
"}
- for(var/e in equipment)
- var/obj/item/mecha_parts/mecha_equipment/equipment = e
- . += "[equipment.name] [equipment.detachable ? "
Detach" : "\[Non-removable\]
"]"
- . += {"
Available HONK slots: [max_equip-LAZYLEN(equipment)]
-
-
"}
-
/obj/vehicle/sealed/mecha/combat/honker/play_stepsound()
if(squeak)
playsound(src, SFX_CLOWN_STEP, 70, 1)
squeak = !squeak
-/obj/vehicle/sealed/mecha/combat/honker/Topic(href, href_list)
- ..()
- if (href_list["play_sound"])
- switch(href_list["play_sound"])
- if("sadtrombone")
- playsound(src, 'sound/misc/sadtrombone.ogg', 50)
- if("bikehorn")
- playsound(src, 'sound/items/bikehorn.ogg', 50)
- if("airhorn2")
- playsound(src, 'sound/items/airhorn2.ogg', 40) //soundfile has higher than average volume
- if("carhorn")
- playsound(src, 'sound/items/carhorn.ogg', 80) //soundfile has lower than average volume
- if("party_horn")
- playsound(src, 'sound/items/party_horn.ogg', 50)
- if("reee")
- playsound(src, 'sound/effects/reee.ogg', 50)
- if("weeoo1")
- playsound(src, 'sound/items/weeoo1.ogg', 50)
- if("hiss1")
- playsound(src, 'sound/voice/hiss1.ogg', 50)
- if("armbomb")
- playsound(src, 'sound/weapons/armbomb.ogg', 50)
- if("saberon")
- playsound(src, 'sound/weapons/saberon.ogg', 50)
- if("airlock_alien_prying")
- playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50)
- if("lightningbolt")
- playsound(src, 'sound/magic/lightningbolt.ogg', 50)
- if("explosionfar")
- playsound(src, 'sound/effects/explosionfar.ogg', 50)
-
//DARK H.O.N.K.
@@ -147,13 +31,25 @@
name = "\improper Dark H.O.N.K"
icon_state = "darkhonker"
max_integrity = 300
- deflect_chance = 15
armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 35, BOMB = 20, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 35000
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/honker/dark
- max_equip = 4
+ max_equip_by_category = list(
+ MECHA_UTILITY = 1,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 3,
+ )
+
+/obj/vehicle/sealed/mecha/combat/honker/dark/loaded
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/honker,
+ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/thrusters/ion),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
/obj/vehicle/sealed/mecha/combat/honker/dark/add_cell(obj/item/stock_parts/cell/C)
if(C)
@@ -162,17 +58,6 @@
return
cell = new /obj/item/stock_parts/cell/hyper(src)
-/obj/vehicle/sealed/mecha/combat/honker/dark/loaded/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/honker()
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana()//Needed more offensive weapons.
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache()//The mousetrap mortar was not up-to-snuff.
- ME.attach(src)
-
/obj/structure/mecha_wreckage/honker/dark
name = "\improper Dark H.O.N.K wreckage"
icon_state = "darkhonker-broken"
diff --git a/code/modules/vehicles/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm
index 5d0f4da0a62..b0cfd022e0c 100644
--- a/code/modules/vehicles/mecha/combat/marauder.dm
+++ b/code/modules/vehicles/mecha/combat/marauder.dm
@@ -5,7 +5,6 @@
base_icon_state = "marauder"
movedelay = 5
max_integrity = 500
- deflect_chance = 25
armor = list(MELEE = 50, BULLET = 55, LASER = 40, ENERGY = 30, BOMB = 30, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 60000
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
@@ -13,9 +12,12 @@
internals_req_access = list(ACCESS_CENT_SPECOPS)
wreckage = /obj/structure/mecha_wreckage/marauder
mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE
- internal_damage_threshold = 25
force = 45
- max_equip = 5
+ max_equip_by_category = list(
+ MECHA_UTILITY = 3,
+ MECHA_POWER = 2,
+ MECHA_ARMOR = 3,
+ )
bumpsmash = TRUE
/obj/vehicle/sealed/mecha/combat/marauder/generate_actions()
@@ -23,19 +25,14 @@
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_smoke)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_zoom)
-/obj/vehicle/sealed/mecha/combat/marauder/loaded/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
- ME.attach(src)
- max_ammo()
+/obj/vehicle/sealed/mecha/combat/marauder/loaded
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse,
+ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/thrusters/ion),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster),
+ )
/obj/vehicle/sealed/mecha/combat/marauder/add_cell(obj/item/stock_parts/cell/C=null)
if(C)
@@ -84,25 +81,19 @@
movedelay = 3
max_integrity = 550
wreckage = /obj/structure/mecha_wreckage/seraph
- internal_damage_threshold = 20
force = 55
- max_equip = 6
-
-/obj/vehicle/sealed/mecha/combat/marauder/seraph/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/teleporter(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
- ME.attach(src)
- max_ammo()
+ max_equip_by_category = list(
+ MECHA_UTILITY = 3,
+ MECHA_POWER = 2,
+ MECHA_ARMOR = 3,
+ )
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse,
+ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/thrusters/ion),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster),
+ )
/obj/vehicle/sealed/mecha/combat/marauder/mauler
desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model."
@@ -112,26 +103,26 @@
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/mauler
- max_equip = 6
+ max_equip_by_category = list(
+ MECHA_UTILITY = 3,
+ MECHA_POWER = 2,
+ MECHA_ARMOR = 4,
+ )
+ equip_by_category = list(
+ MECHA_L_ARM = null,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/thrusters/ion),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
destruction_sleep_duration = 20
-/obj/vehicle/sealed/mecha/combat/marauder/mauler/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
- ME.attach(src)
-
-/obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
- ME.attach(src)
- max_ammo()
-
+/obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg,
+ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/thrusters/ion),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster),
+ )
diff --git a/code/modules/vehicles/mecha/combat/phazon.dm b/code/modules/vehicles/mecha/combat/phazon.dm
index 16c83ec730d..16dc0ce3555 100644
--- a/code/modules/vehicles/mecha/combat/phazon.dm
+++ b/code/modules/vehicles/mecha/combat/phazon.dm
@@ -7,13 +7,15 @@
dir_in = 2 //Facing South.
step_energy_drain = 3
max_integrity = 200
- deflect_chance = 30
armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 25000
wreckage = /obj/structure/mecha_wreckage/phazon
- internal_damage_threshold = 25
force = 15
- max_equip = 3
+ max_equip_by_category = list(
+ MECHA_UTILITY = 1,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 2,
+ )
phase_state = "phazon-phase"
/obj/vehicle/sealed/mecha/combat/phazon/generate_actions()
diff --git a/code/modules/vehicles/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm
index b838d1296bb..afb91667b31 100644
--- a/code/modules/vehicles/mecha/combat/reticence.dm
+++ b/code/modules/vehicles/mecha/combat/reticence.dm
@@ -6,21 +6,25 @@
movedelay = 2
dir_in = 1 //Facing North.
max_integrity = 100
- deflect_chance = 3
armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 15000
wreckage = /obj/structure/mecha_wreckage/reticence
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_THEATRE)
mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS | QUIET_STEPS | QUIET_TURNS | MMI_COMPATIBLE
- internal_damage_threshold = 25
- max_equip = 2
+ max_equip_by_category = list(
+ MECHA_UTILITY = 1,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 1,
+ )
step_energy_drain = 3
color = "#87878715"
-/obj/vehicle/sealed/mecha/combat/reticence/loaded/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced
- ME.attach(src)
- ME = new /obj/item/mecha_parts/mecha_equipment/rcd //HAHA IT MAKES WALLS GET IT
- ME.attach(src)
+/obj/vehicle/sealed/mecha/combat/reticence/loaded
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced,
+ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/rcd,
+ MECHA_UTILITY = list(),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
diff --git a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm
index 7a3152b593c..c50314d7a60 100644
--- a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm
+++ b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm
@@ -22,12 +22,15 @@
mecha_flags = ADDING_ACCESS_POSSIBLE | CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS
movedelay = 3
max_integrity = 450 //really tanky, like damn
- deflect_chance = 25
armor = list(MELEE = 45, BULLET = 40, LASER = 30, ENERGY = 30, BOMB = 40, BIO = 0, FIRE = 100, ACID = 100)
max_temperature = 30000
wreckage = /obj/structure/mecha_wreckage/savannah_ivanov
- internal_damage_threshold = 25
max_occupants = 2
+ max_equip_by_category = list(
+ MECHA_UTILITY = 1,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 3,
+ )
//no tax on flying, since the power cost is in the leap itself.
phasing_energy_drain = 0
diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
index 8da111ec7d1..a25178ca6c7 100644
--- a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
+++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
@@ -8,6 +8,8 @@
icon_state = "mecha_equip"
force = 5
max_integrity = 300
+ /// Determines what "slot" this attachment will try to attach to on a mech
+ var/equipment_slot = MECHA_WEAPON
///Cooldown in ticks required between activations of the equipment
var/equip_cooldown = 0
///used for equipment that can be turned on/off, boolean
@@ -29,58 +31,43 @@
///Sound file: Sound to play when this equipment is destroyed while still attached to the mech
var/destroy_sound = 'sound/mecha/critdestr.ogg'
-///Updates chassis equipment list html menu
-/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page()
- SHOULD_CALL_PARENT(TRUE)
- send_byjax(chassis.occupants,"exosuit.browser","eq_list", chassis.get_equipment_list())
- send_byjax(chassis.occupants,"exosuit.browser","equipment_menu", chassis.get_equipment_menu(),"dropdowns")
- return TRUE
-
-///Updates chassis equipment list html menu with custom data
-/obj/item/mecha_parts/mecha_equipment/proc/update_equip_info()
- if(!chassis)
- return
- send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",get_equip_info())
- return TRUE
-
/obj/item/mecha_parts/mecha_equipment/Destroy()
if(chassis)
- LAZYREMOVE(chassis.equipment, src)
- if(chassis.selected == src)
- chassis.selected = null
- update_chassis_page()
+ detach(get_turf(src))
log_message("[src] is destroyed.", LOG_MECHA)
if(LAZYLEN(chassis.occupants))
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_danger("[src] is destroyed!")]")
playsound(chassis, destroy_sound, 50)
- if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in.
- chassis.max_equip--
chassis = null
return ..()
-/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/vehicle/sealed/mecha/mech)
- if(!can_attach(mech))
- to_chat(user, span_warning("You are unable to attach [src] to [mech]!"))
- return FALSE
- if(!user.temporarilyRemoveItemFromInventory(src))
- return FALSE
- attach(mech)
- user.visible_message(span_notice("[user] attaches [src] to [mech]."), span_notice("You attach [src] to [mech]."))
- return TRUE
+/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE)
+ if(can_attach(M, attach_right))
+ if(!user.temporarilyRemoveItemFromInventory(src))
+ return FALSE
+ attach(M, attach_right)
+ user.visible_message(span_notice("[user] attaches [src] to [M]."), span_notice("You attach [src] to [M]."))
+ return TRUE
+ to_chat(user, span_warning("You are unable to attach [src] to [M]!"))
+ return FALSE
-///fetches and returns a html formatted string with equippability status
-/obj/item/mecha_parts/mecha_equipment/proc/get_equip_info()
- if(!chassis)
- return
- var/txt = "* "
- if(chassis.selected == src)
- txt += "[src]"
- else if(selectable)
- txt += "[src]"
- else
- txt += "[src]"
-
- return txt
+/obj/item/mecha_parts/mecha_equipment/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ switch(action)
+ if("detach")
+ detach(get_turf(src))
+ return TRUE
+ if("toggle")
+ activated = !activated
+ return TRUE
+ if("repair")
+ ui.close() // allow watching for baddies and the ingame effects
+ chassis.balloon_alert(usr, "starting repair")
+ while(do_after(usr, 1 SECONDS, chassis) && get_integrity() < max_integrity)
+ repair_damage(30)
+ if(get_integrity() == max_integrity)
+ balloon_alert(usr, "repair complete")
+ return FALSE
/**
* Checks whether this mecha equipment can be activated
@@ -95,20 +82,19 @@
return FALSE
if(!activated)
return FALSE
- if(energy_drain && !chassis.has_charge(energy_drain))
+ if(energy_drain && !chassis?.has_charge(energy_drain))
return FALSE
if(chassis.is_currently_ejecting)
return FALSE
if(chassis.equipment_disabled)
to_chat(chassis.occupants, span_warning("Error -- Equipment control unit is unresponsive."))
return FALSE
- if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT))
+ if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT(type)))
return FALSE
return TRUE
/obj/item/mecha_parts/mecha_equipment/proc/action(mob/source, atom/target, list/modifiers)
- TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_EQUIPMENT, equip_cooldown)//Cooldown is on the MECH so people dont bypass it by switching equipment
- send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]", get_equip_info())
+ TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_EQUIPMENT(type), equip_cooldown)//Cooldown is on the MECH so people dont bypass it by switching equipment
chassis.use_power(energy_drain)
return TRUE
@@ -125,7 +111,7 @@
return
chassis.use_power(energy_drain)
. = do_after(user, equip_cooldown, target=target, interaction_key = interaction_key)
- if(!chassis || src != chassis.selected || !(get_dir(chassis, target) & chassis.dir))
+ if(!chassis || !(get_dir(chassis, target) & chassis.dir))
return FALSE
///Do after wrapper for mecha equipment
@@ -133,45 +119,72 @@
if(!chassis)
return
. = do_after(user, delay, target=target)
- if(!chassis || src != chassis.selected || !(get_dir(chassis, target) & chassis.dir))
+ if(!chassis || !(get_dir(chassis, target)&chassis.dir))
return FALSE
-///Returns TRUE if equipment should be allowed to attach to the targetted necha
-/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/vehicle/sealed/mecha/M)
- return LAZYLEN(M.equipment) < M.max_equip
+/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
+ return default_can_attach(M, attach_right)
-///Attaches equipment and updates relevant equipment trackers
-/obj/item/mecha_parts/mecha_equipment/proc/attach(obj/vehicle/sealed/mecha/M)
- LAZYADD(M.equipment, src)
+/obj/item/mecha_parts/mecha_equipment/proc/default_can_attach(obj/vehicle/sealed/mecha/mech, attach_right = FALSE)
+ if(equipment_slot == MECHA_WEAPON)
+ if(attach_right)
+ if(mech.equip_by_category[MECHA_R_ARM])
+ return FALSE
+ else
+ if(mech.equip_by_category[MECHA_L_ARM])
+ return FALSE
+ return TRUE
+ return length(mech.equip_by_category[equipment_slot]) < mech.max_equip_by_category[equipment_slot]
+
+/obj/item/mecha_parts/mecha_equipment/proc/attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
+ LAZYADD(M.flat_equipment, src)
+ var/to_equip_slot = equipment_slot
+ if(equipment_slot == MECHA_WEAPON)
+ if(attach_right)
+ to_equip_slot = MECHA_R_ARM
+ else
+ to_equip_slot = MECHA_L_ARM
+ if(islist(M.equip_by_category[to_equip_slot]))
+ M.equip_by_category[to_equip_slot] += src
+ else
+ M.equip_by_category[to_equip_slot] = src
chassis = M
forceMove(M)
- log_message("[src] attached.", LOG_MECHA)
- update_chassis_page()
+ log_message("[src] initialized.", LOG_MECHA)
-///Detaches equipment and updates relevant equipment trackers. Optional argument of atom to forcemove to once detached
/obj/item/mecha_parts/mecha_equipment/proc/detach(atom/moveto)
- SHOULD_CALL_PARENT(TRUE)
moveto = moveto || get_turf(chassis)
- forceMove(moveto)
- LAZYREMOVE(chassis.equipment, src)
- if(chassis.selected == src)
- chassis.selected = null
- update_chassis_page()
- log_message("[src] removed from equipment.", LOG_MECHA)
- chassis = null
-
-/obj/item/mecha_parts/mecha_equipment/Topic(href,href_list)
- . = ..()
- if(.)
- return
- if(href_list["detach"])
- detach()
+ if(src.Move(moveto))
+ LAZYREMOVE(chassis.flat_equipment, src)
+ var/to_unequip_slot = equipment_slot
+ if(equipment_slot == MECHA_WEAPON)
+ if(chassis.equip_by_category[MECHA_R_ARM] == src)
+ to_unequip_slot = MECHA_R_ARM
+ else
+ to_unequip_slot = MECHA_L_ARM
+ if(islist(chassis.equip_by_category[to_unequip_slot]))
+ chassis.equip_by_category[to_unequip_slot] -= src
+ else
+ chassis.equip_by_category[to_unequip_slot] = null
+ log_message("[src] removed from equipment.", LOG_MECHA)
+ chassis = null
+ return
/obj/item/mecha_parts/mecha_equipment/log_message(message, message_type=LOG_GAME, color=null, log_globally)
if(chassis)
return chassis.log_message("ATTACHMENT: [src] [message]", message_type, color)
return ..()
+/**
+ * ## get_snowflake_data
+ * handles the returning of snowflake data required by the UI of the mecha
+ * not the prettiest of procs honeslty
+ * returns:
+ * * an assoc list
+ * * must include an list("snowflake_id" = snowflake_id)
+ */
+/obj/item/mecha_parts/mecha_equipment/proc/get_snowflake_data()
+ return list()
/**
* Proc for reloading weapons from HTML UI or by AI
diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm
index 518cbcfb5f0..27c901a55c3 100644
--- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm
@@ -11,7 +11,7 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/mecha_parts/mecha_equipment/medical/can_attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/medical/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
. = ..()
if(!ismedicalmecha(M))
return FALSE
@@ -45,6 +45,30 @@
AM.forceMove(get_turf(src))
return ..()
+/obj/item/mecha_parts/mecha_equipment/medical/sleeper/get_snowflake_data()
+ var/list/data = list("snowflake_id" = MECHA_SNOWFLAKE_ID_SLEEPER)
+ if(!patient)
+ return data
+ data["patient"] = list(
+ "patientname" = patient.name,
+ "is_dead" = patient.stat == DEAD,
+ "patient_health" = patient.health/patient.maxHealth,
+ )
+ return data
+
+/obj/item/mecha_parts/mecha_equipment/medical/sleeper/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+ switch(action)
+ if("eject")
+ go_out()
+ return TRUE
+ if("view_stats")
+ usr << browse(get_patient_stats(),"window=msleeper")
+ onclose(usr, "msleeper")
+ return FALSE
+
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/Exit(atom/movable/leaving, direction)
return FALSE //prevents them from leaving without being forcemoved I guess
@@ -60,14 +84,13 @@
chassis.visible_message(span_warning("[chassis] starts putting [target] into \the [src]."))
if(!do_after(source, equip_cooldown, target=target))
return
- if(!chassis || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir))
+ if(!chassis || !(get_dir(chassis, target) & chassis.dir))
return
if(!patient_insertion_check(target, source))
return
target.forceMove(src)
patient = target
START_PROCESSING(SSobj, src)
- update_equip_info()
to_chat(source, "[icon2html(src, source)][span_notice("[target] successfully loaded into [src]. Life support functions engaged.")]")
chassis.visible_message(span_warning("[chassis] loads [target] into [src]."))
log_message("[target] loaded. Life support functions engaged.", LOG_MECHA)
@@ -93,7 +116,6 @@
log_message("[patient] ejected. Life support functions disabled.", LOG_MECHA)
STOP_PROCESSING(SSobj, src)
patient = null
- update_equip_info()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/detach()
if(patient)
@@ -102,26 +124,12 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/mecha_parts/mecha_equipment/medical/sleeper/get_equip_info()
- var/output = ..()
- if(output)
- var/temp = ""
- if(patient)
- temp = "
\[Occupant: [patient] ([patient.stat > 1 ? "*DECEASED*" : "Health: [patient.health]%"])\]
View stats|Eject"
- return "[output] [temp]"
-
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/Topic(href,href_list)
. = ..()
if(.)
return
if(!(usr in chassis.occupants))
return
- if(href_list["eject"])
- go_out()
- if(href_list["view_stats"])
- usr << browse(get_patient_stats(),"window=msleeper")
- onclose(usr, "msleeper")
- return
if(href_list["inject"])
var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG = locate() in chassis
var/datum/reagent/R = locate(href_list["inject"]) in SG.reagents.reagent_list
@@ -203,7 +211,7 @@
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/inject_reagent(datum/reagent/R,obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG)
- if(!R || !patient || !SG || !(SG in chassis.equipment))
+ if(!R || !patient || !SG || !(SG in chassis.flat_equipment))
return
var/to_inject = min(R.volume, inject_amount)
if(to_inject && patient.reagents.get_reagent_amount(R.type) + to_inject <= inject_amount*2)
@@ -211,14 +219,6 @@
log_message("Injecting [patient] with [to_inject] units of [R.name].", LOG_MECHA)
log_combat(chassis.occupants, patient, "injected", "[name] ([R] - [to_inject] units)")
SG.reagents.trans_id_to(patient,R.type,to_inject)
- update_equip_info()
-
-/obj/item/mecha_parts/mecha_equipment/medical/sleeper/update_equip_info()
- . = ..()
- if(. && patient)
- send_byjax(chassis.occupants,"msleeper.browser","lossinfo",get_patient_dam())
- send_byjax(chassis.occupants,"msleeper.browser","reagents",get_patient_reagents())
- send_byjax(chassis.occupants,"msleeper.browser","injectwith",get_available_reagents())
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/container_resist_act(mob/living/user)
go_out()
@@ -240,7 +240,6 @@
log_message("[patient] no longer detected - Life support functions disabled.", LOG_MECHA)
STOP_PROCESSING(SSobj, src)
patient = null
- update_equip_info()
if(M.health > 0)
M.adjustOxyLoss(-0.5 * delta_time)
M.AdjustStun(-40 * delta_time)
@@ -251,7 +250,6 @@
if(M.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) < 5)
M.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5)
chassis.use_power(energy_drain)
- update_equip_info()
@@ -308,15 +306,31 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M)
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M, attach_right = FALSE)
. = ..()
if(!istype(M))
return FALSE
-/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/get_equip_info()
- var/output = ..()// no . = here to avoid obfuscation
- if(output)
- return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [LAZYLEN(syringes)]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list"
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/get_snowflake_data()
+ return list(
+ "snowflake_id" = MECHA_SNOWFLAKE_ID_SYRINGE,
+ "mode" = mode == FIRE_SYRINGE_MODE ? "Launch" : "Analyze",
+ "syringe" = LAZYLEN(syringes),
+ "max_syringe" = max_syringes,
+ "reagents" = reagents.total_volume,
+ "total_reagents" = reagents.maximum_volume,
+ )
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+ if(action == "change_mode")
+ mode = !mode
+ return TRUE
+ else if(action == "show_reagents")
+ usr << browse(get_reagents_page(),"window=msyringegun")
+ return FALSE
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/action(mob/source, atom/target, list/modifiers)
if(!action_checks(target))
@@ -348,7 +362,6 @@
..()
if (href_list["toggle_mode"])
mode = !mode
- update_equip_info()
return
if (href_list["select_reagents"])
LAZYCLEARLIST(processed_reagents)
@@ -369,11 +382,6 @@
to_chat(usr, "[icon2html(src, usr)][span_notice("Reagent processing started.")]")
log_message("Reagent processing started.", LOG_MECHA)
return
- if (href_list["show_reagents"])
- if(!(usr in chassis.occupants))
- return
- usr << browse(get_reagents_page(),"window=msyringegun")
- return
if (href_list["purge_reagent"])
var/reagent = href_list["purge_reagent"]
if(!reagent)
@@ -454,7 +462,6 @@
S.forceMove(src)
LAZYADD(syringes,S)
to_chat(user, "[icon2html(src, user)][span_notice("Syringe loaded.")]")
- update_equip_info()
return TRUE
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/analyze_reagents(atom/A, mob/user)
@@ -479,16 +486,11 @@
known_reagents[r_id] = r_name
return TRUE
-/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/update_equip_info()
- . = ..()
- if(.)
- send_byjax(chassis.occupants,"msyringegun.browser","reagents",get_current_reagents())
- send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form())
-
/// Updates the equipment info list when the reagents change. Eats signal args.
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/on_reagent_change(datum/reagents/holder, ...)
SIGNAL_HANDLER
- update_equip_info()
+ send_byjax(chassis.occupants,"msyringegun.browser","reagents",get_current_reagents())
+ send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form())
return NONE
diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm
index c80147b51a9..70ea103f73f 100644
--- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm
@@ -102,11 +102,11 @@
/obj/item/mecha_parts/mecha_equipment/drill/proc/move_ores()
- if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.equipment && istype(chassis, /obj/vehicle/sealed/mecha/working/ripley))
+ if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.flat_equipment && istype(chassis, /obj/vehicle/sealed/mecha/working/ripley))
var/obj/vehicle/sealed/mecha/working/ripley/R = chassis //we could assume that it's a ripley because it has a clamp, but that's ~unsafe~ and ~bad practice~
R.collect_ore()
-/obj/item/mecha_parts/mecha_equipment/drill/can_attach(obj/vehicle/sealed/mecha/M as obj)
+/obj/item/mecha_parts/mecha_equipment/drill/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
if(..())
if(istype(M, /obj/vehicle/sealed/mecha/working) || istype(M, /obj/vehicle/sealed/mecha/combat))
return TRUE
@@ -166,6 +166,7 @@
icon_state = "mecha_analyzer"
selectable = 0
equip_cooldown = 15
+ equipment_slot = MECHA_UTILITY
var/scanning_time = 0
mech_flags = EXOSUIT_MODULE_WORKING
@@ -173,7 +174,7 @@
. = ..()
START_PROCESSING(SSfastprocess, src)
-/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/vehicle/sealed/mecha/M as obj)
+/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
if(..())
if(istype(M, /obj/vehicle/sealed/mecha/working))
return TRUE
diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
index d069da3366d..b4a51c52ff7 100644
--- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
@@ -97,19 +97,16 @@
return
movable_target = target
to_chat(source, "[icon2html(src, source)][span_notice("locked on [target].")]")
- send_byjax(source,"exosuit.browser","[REF(src)]", get_equip_info())
else if(target!=movable_target)
if(movable_target in view(chassis))
var/turf/targ = get_turf(target)
var/turf/orig = get_turf(movable_target)
movable_target.throw_at(target, 14, 1.5)
movable_target = null
- send_byjax(source,"exosuit.browser","[REF(src)]", get_equip_info())
log_game("[key_name(source)] used a Gravitational Catapult to throw [movable_target] (From [AREACOORD(orig)]) at [target] ([AREACOORD(targ)]).")
return ..()
movable_target = null
to_chat(source, "[icon2html(src, source)][span_notice("Lock on [movable_target] disengaged.")]")
- send_byjax(source,"exosuit.browser","[REF(src)]", get_equip_info())
if(GRAVPUSH_MODE)
var/list/atomstothrow = list()
@@ -134,57 +131,62 @@
var/delay = 2
SSmove_manager.move_away(scatter, target, delay = delay, timeout = delay * dist, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY)
-/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info()
- return "[..()] [mode==1?"([movable_target||"Nothing"])":null] \[S|P\]"
-
-/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list)
- ..()
- if(href_list["mode"])
- mode = text2num(href_list["mode"])
- send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
+/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_snowflake_data()
+ return list(
+ "snowflake_id" = MECHA_SNOWFLAKE_ID_MODE,
+ "name" = "Gravity catapult",
+ "mode" = mode == GRAVPUSH_MODE ? "Push" : "Sling",
+ )
+/obj/item/mecha_parts/mecha_equipment/gravcatapult/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+ if(action == "change_mode")
+ mode++
+ if(mode > GRAVPUSH_MODE)
+ mode = GRAVSLING_MODE
+ return TRUE
#undef GRAVSLING_MODE
#undef GRAVPUSH_MODE
//////////////////////////// ARMOR BOOSTER MODULES //////////////////////////////////////////////////////////
+/obj/item/mecha_parts/mecha_equipment/armor
+ equipment_slot = MECHA_ARMOR
+ ///short protection name to display in the UI
+ var/protect_name = "you're mome"
+ ///icon in armor.dmi that shows in the UI
+ var/iconstate_name
+ //how much the armor of the mech is modified by
+ var/list/armor_mod = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
+/obj/item/mecha_parts/mecha_equipment/armor/attach(obj/vehicle/sealed/mecha/M, attach_right)
+ . = ..()
+ chassis.armor.modifyRating(arglist(armor_mod))
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants.
+/obj/item/mecha_parts/mecha_equipment/armor/detach(atom/moveto)
+ var/list/removed_armor = armor_mod.Copy()
+ for(var/armor_type in removed_armor)
+ removed_armor[armor_type] = -removed_armor[armor_type]
+ chassis.armor.modifyRating(arglist(removed_armor))
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/armor/anticcw_armor_booster
name = "armor booster module (Close Combat Weaponry)"
- desc = "Boosts exosuit armor against armed melee attacks. Requires energy to operate."
+ desc = "Boosts exosuit armor against melee attacks"
icon_state = "mecha_abooster_ccw"
- equip_cooldown = 10
- energy_drain = 50
- range = 0
- var/deflect_coeff = 1.15
- var/damage_coeff = 0.8
- selectable = FALSE
+ iconstate_name = "melee"
+ protect_name = "Melee Armor"
+ armor = list(MELEE = 15, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/attack_react()
- if(energy_drain && !chassis.has_charge(energy_drain))
- return FALSE
- TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_ARMOR, equip_cooldown)
- return TRUE
-
-
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
+/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster
name = "armor booster module (Ranged Weaponry)"
- desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots. Requires energy to operate."
+ desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots."
icon_state = "mecha_abooster_proj"
- equip_cooldown = 10
- energy_drain = 50
- range = 0
- var/deflect_coeff = 1.15
- var/damage_coeff = 0.8
- selectable = FALSE
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/projectile_react()
- if(energy_drain && !chassis.has_charge(energy_drain))
- return FALSE
- TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_ARMOR, equip_cooldown)
- return TRUE
+ iconstate_name = "range"
+ protect_name = "Ranged Armor"
+ armor = list(MELEE = 0, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
////////////////////////////////// REPAIR DROID //////////////////////////////////////////////////
@@ -196,7 +198,8 @@
icon_state = "repair_droid"
energy_drain = 50
range = 0
-
+ activated = FALSE
+ equipment_slot = MECHA_UTILITY
/// Repaired health per second
var/health_boost = 0.5
var/icon/droid_overlay
@@ -208,7 +211,7 @@
chassis?.cut_overlay(droid_overlay)
return ..()
-/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
. = ..()
droid_overlay = new(src.icon, icon_state = "repair_droid")
M.add_overlay(droid_overlay)
@@ -218,27 +221,20 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info()
- return "* [src] - [activated?"Deactivate":"Activate"]"
-
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list)
- ..()
- if(!href_list["toggle_repairs"])
+/obj/item/mecha_parts/mecha_equipment/repair_droid/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(action != "toggle")
return
chassis.cut_overlay(droid_overlay)
- activated = !activated //now set to FALSE and active, so update the UI
- update_equip_info()
if(activated)
START_PROCESSING(SSobj, src)
- droid_overlay = new(icon, icon_state = "repair_droid_a")
+ droid_overlay = new(src.icon, icon_state = "repair_droid_a")
log_message("Activated.", LOG_MECHA)
else
STOP_PROCESSING(SSobj, src)
- droid_overlay = new(icon, icon_state = "repair_droid")
+ droid_overlay = new(src.icon, icon_state = "repair_droid")
log_message("Deactivated.", LOG_MECHA)
chassis.add_overlay(droid_overlay)
- send_byjax(chassis.occupants,"exosuit.browser", "[REF(src)]", get_equip_info())
/obj/item/mecha_parts/mecha_equipment/repair_droid/process(delta_time)
@@ -260,100 +256,26 @@
repaired = TRUE
if(repaired)
if(!chassis.use_power(energy_drain))
+ activated = FALSE
return PROCESS_KILL
else //no repair needed, we turn off
chassis.cut_overlay(droid_overlay)
droid_overlay = new(src.icon, icon_state = "repair_droid")
chassis.add_overlay(droid_overlay)
+ activated = FALSE
return PROCESS_KILL
-
-
-/////////////////////////////////// TESLA ENERGY RELAY ////////////////////////////////////////////////
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
- name = "exosuit energy relay"
- desc = "An exosuit module that wirelessly drains energy from any available power channel in area. The performance index is quite low."
- icon_state = "tesla"
- energy_drain = 0
- range = 0
- var/coeff = 100
- var/list/use_channels = list(AREA_USAGE_EQUIP,AREA_USAGE_ENVIRON,AREA_USAGE_LIGHT)
- selectable = FALSE
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy()
- STOP_PROCESSING(SSobj, src)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach()
- STOP_PROCESSING(SSobj, src)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_charge()
- if(activated) //disabled
- return
- var/pow_chan = get_chassis_area_power(get_area(chassis))
- if(pow_chan)
- return 1000 //making magic
-
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_chassis_area_power(area/A)
- if(!A)
- return
- var/pow_chan = 0
- for(var/c in use_channels)
- if(!A.powered(c))
- continue
- pow_chan = c
- break
- return pow_chan
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list)
- ..()
- if(href_list["toggle_relay"])
- activated = !activated //now set to FALSE and active, so update the UI
- update_equip_info()
- if(activated) //inactive
- START_PROCESSING(SSobj, src)
- log_message("Activated.", LOG_MECHA)
- else
- STOP_PROCESSING(SSobj, src)
- log_message("Deactivated.", LOG_MECHA)
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info()
- if(!chassis)
- return
- return "* [src.name] - [activated?"Deactivate":"Activate"]"
-
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/process(delta_time)
- if(!chassis || chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT)
- return PROCESS_KILL
- var/cur_charge = chassis.get_charge()
- if(isnull(cur_charge) || !chassis.cell)
- to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("No power cell detected.")]")
- return PROCESS_KILL
- if(cur_charge >= chassis.cell.maxcharge)
- return
- var/area/A = get_area(chassis)
- var/pow_chan = get_chassis_area_power(A)
- if(pow_chan)
- var/delta = min(10 * delta_time, chassis.cell.maxcharge-cur_charge)
- chassis.give_power(delta)
- A.use_power(delta*coeff, pow_chan)
-
-
-
-
/////////////////////////////////////////// GENERATOR /////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/generator
- name = "exosuit plasma converter"
+ name = "plasma engine"
desc = "An exosuit module that generates power using solid plasma as fuel. Pollutes the environment."
icon_state = "tesla"
range = MECHA_MELEE
+ equipment_slot = MECHA_POWER
+ activated = FALSE
var/coeff = 100
var/obj/item/stack/sheet/fuel
var/max_fuel = 150000
@@ -377,31 +299,31 @@
/obj/item/mecha_parts/mecha_equipment/generator/detach()
STOP_PROCESSING(SSobj, src)
+ activated = FALSE
return ..()
-/obj/item/mecha_parts/mecha_equipment/generator/Topic(href, href_list)
- ..()
- if(href_list["toggle"])
- activated = !activated //now set to FALSE and active, so update the UI
- update_equip_info()
- if(activated) //inactive
+/obj/item/mecha_parts/mecha_equipment/generator/get_snowflake_data()
+ return list(
+ "active" = activated,
+ "fuel" = fuel.amount,
+ )
+
+/obj/item/mecha_parts/mecha_equipment/generator/ui_act(action, list/params)
+ . = ..()
+ if(action == "toggle")
+ if(activated)
+ to_chat(usr, "[icon2html(src, usr)][span_warning("Power generation enabled.")]")
START_PROCESSING(SSobj, src)
log_message("Activated.", LOG_MECHA)
else
+ to_chat(usr, "[icon2html(src, usr)][span_warning("Power generation disabled.")]")
STOP_PROCESSING(SSobj, src)
log_message("Deactivated.", LOG_MECHA)
+ return TRUE
-/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
- var/output = ..()
- if(output)
- return "[output] \[[fuel]: [round(fuel.amount*MINERAL_MATERIAL_AMOUNT,0.1)] cm3\] - [activated?"Deactivate":"Activate"]"
-
-/obj/item/mecha_parts/mecha_equipment/generator/action(mob/source, atom/movable/target, list/modifiers)
- if(!chassis)
- return
- if(load_fuel(target, source))
- send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
- return ..()
+/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon, mob/user, params)
+ . = ..()
+ load_fuel(weapon, user)
/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(obj/item/stack/sheet/P, mob/user)
if(P.type == fuel.type && P.amount > 0)
@@ -424,13 +346,16 @@
/obj/item/mecha_parts/mecha_equipment/generator/process(delta_time)
if(!chassis)
+ activated = FALSE
return PROCESS_KILL
if(fuel.amount<=0)
+ activated = FALSE
log_message("Deactivated - no fuel.", LOG_MECHA)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Fuel reserves depleted.")]")
return PROCESS_KILL
var/cur_charge = chassis.get_charge()
if(isnull(cur_charge))
+ activated = FALSE
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("No power cell detected.")]")
log_message("Deactivated.", LOG_MECHA)
return PROCESS_KILL
@@ -439,7 +364,6 @@
use_fuel = fuelrate_active
chassis.give_power(rechargerate * delta_time)
fuel.amount -= min(delta_time * use_fuel / MINERAL_MATERIAL_AMOUNT, fuel.amount)
- update_equip_info()
/////////////////////////////////////////// THRUSTERS /////////////////////////////////////////////
@@ -448,16 +372,17 @@
desc = "A generic set of thrusters, from an unknown source. Uses not-understood methods to propel exosuits seemingly for free."
icon_state = "thrusters"
selectable = FALSE
+ equipment_slot = MECHA_UTILITY
var/effect_type = /obj/effect/particle_effect/sparks
-/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
- for(var/obj/item/I in M.equipment)
+/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right)
+ for(var/obj/item/I in M.equip_by_category[MECHA_UTILITY])
if(istype(I, src))
to_chat(user, span_warning("[M] already has this thruster package!"))
return FALSE
return ..()
-/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
M.active_thrusters = src //Enable by default
return ..()
@@ -471,11 +396,9 @@
chassis.active_thrusters = null
return ..()
-/obj/item/mecha_parts/mecha_equipment/thrusters/Topic(href,href_list)
- ..()
- if(href_list["toggle"])
- activated = !activated //now set to FALSE and active, so update the UI
- update_equip_info()
+/obj/item/mecha_parts/mecha_equipment/thrusters/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(params["toggle"])
if(activated) //inactive
START_PROCESSING(SSobj, src)
enable()
@@ -497,11 +420,6 @@
chassis.active_thrusters = null
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("[src] disabled.")]")
-/obj/item/mecha_parts/mecha_equipment/thrusters/get_equip_info()
- var/output = ..()
- if(output)
- return "[output] [activated?"Deactivate":"Activate"]"
-
/obj/item/mecha_parts/mecha_equipment/thrusters/proc/thrust(movement_dir)
if(!chassis)
return FALSE
@@ -521,7 +439,7 @@
effect_type = /obj/effect/particle_effect/smoke
var/move_cost = 20 //moles per step
-/obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE)
if(!M.internal_tank)
to_chat(user, span_warning("[M] does not have an internal tank and cannot support this upgrade!"))
return FALSE
@@ -539,8 +457,6 @@
generate_effect(movement_dir)
return TRUE
-
-
/obj/item/mecha_parts/mecha_equipment/thrusters/ion //for mechs with built-in thrusters, should never really exist un-attached to a mech
name = "Ion thruster package"
desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments."
diff --git a/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm b/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm
deleted file mode 100644
index 87c5b949d26..00000000000
--- a/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-/obj/item/mecha_parts/concealed_weapon_bay
- name = "concealed weapon bay"
- desc = "A compartment that allows a non-combat mecha to equip one weapon while hiding the weapon from plain sight."
- icon = 'icons/mecha/mecha_equipment.dmi'
- icon_state = "mecha_weapon_bay"
-
-/obj/item/mecha_parts/concealed_weapon_bay/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
- if(istype(M, /obj/vehicle/sealed/mecha/combat))
- to_chat(user, span_warning("[M] can already hold weapons!"))
- return
- if(locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents)
- to_chat(user, span_warning("[M] already has a concealed weapon bay!"))
- return
- return ..()
diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
index 248661a6ceb..b7aa0d438b4 100644
--- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
@@ -24,7 +24,7 @@
///Audio for using the hydraulic clamp
var/clampsound = 'sound/mecha/hydraulic.ogg'
-/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
. = ..()
if(!.)
return
@@ -215,10 +215,14 @@
return
extinguish(source.target)
-/obj/item/mecha_parts/mecha_equipment/extinguisher/get_equip_info()
- return "[..()] \[[src.reagents.total_volume]\]"
+/obj/item/mecha_parts/mecha_equipment/extinguisher/get_snowflake_data()
+ return list(
+ "snowflake_id" = MECHA_SNOWFLAKE_ID_EXTINGUISHER,
+ "reagents" = reagents.total_volume,
+ "total_reagents" = reagents.maximum_volume,
+ )
-/obj/item/mecha_parts/mecha_equipment/extinguisher/can_attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/extinguisher/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
. = ..()
if(!.)
return
@@ -249,6 +253,45 @@
GLOB.rcd_list -= src
return ..()
+/obj/item/mecha_parts/mecha_equipment/rcd/get_snowflake_data()
+ return list(
+ "snowflake_id" = MECHA_SNOWFLAKE_ID_MODE,
+ "name" = "RCD control",
+ "mode" = get_mode_name(),
+ )
+
+/// fetches the mode name to display in the UI
+/obj/item/mecha_parts/mecha_equipment/rcd/proc/get_mode_name()
+ switch(mode)
+ if(MODE_DECONSTRUCT)
+ return "Deconstruct"
+ if(MODE_WALL)
+ return "Build wall"
+ if(MODE_AIRLOCK)
+ return "Build Airlock"
+ else
+ return "Someone didnt set this"
+
+/obj/item/mecha_parts/mecha_equipment/rcd/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+ if(action == "change_mode")
+ mode++
+ if(mode > MODE_AIRLOCK)
+ mode = MODE_DECONSTRUCT
+ switch(mode)
+ if(MODE_DECONSTRUCT)
+ to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Switched RCD to Deconstruct.")]")
+ energy_drain = initial(energy_drain)
+ if(MODE_WALL)
+ to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Switched RCD to Construct Walls and Flooring.")]")
+ energy_drain = 2*initial(energy_drain)
+ if(MODE_AIRLOCK)
+ to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Switched RCD to Construct Airlock.")]")
+ energy_drain = 2*initial(energy_drain)
+ return TRUE
+
/obj/item/mecha_parts/mecha_equipment/rcd/action(mob/source, atom/target, list/modifiers)
if(!isturf(target) && !istype(target, /obj/machinery/door/airlock))
target = get_turf(target)
@@ -298,24 +341,6 @@
playsound(target, 'sound/items/deconstruct.ogg', 50, TRUE)
return ..()
-/obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list)
- ..()
- if(href_list["mode"])
- mode = text2num(href_list["mode"])
- switch(mode)
- if(MODE_DECONSTRUCT)
- to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Switched RCD to Deconstruct.")]")
- energy_drain = initial(energy_drain)
- if(MODE_WALL)
- to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Switched RCD to Construct Walls and Flooring.")]")
- energy_drain = 2*initial(energy_drain)
- if(MODE_AIRLOCK)
- to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("Switched RCD to Construct Airlock.")]")
- energy_drain = 2*initial(energy_drain)
-
-/obj/item/mecha_parts/mecha_equipment/rcd/get_equip_info()
- return "[..()] \[D|C|A\]"
-
#undef MODE_DECONSTRUCT
#undef MODE_WALL
#undef MODE_AIRLOCK
@@ -327,7 +352,7 @@
icon_state = "ripleyupgrade"
mech_flags = EXOSUIT_MODULE_RIPLEY
-/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/vehicle/sealed/mecha/working/ripley/M)
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/vehicle/sealed/mecha/working/ripley/M, attach_right = FALSE)
if(M.type != /obj/vehicle/sealed/mecha/working/ripley)
to_chat(loc, span_warning("This conversion kit can only be applied to APLU MK-I models."))
return FALSE
@@ -345,7 +370,7 @@
return FALSE
return TRUE
-/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/vehicle/sealed/mecha/markone)
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/vehicle/sealed/mecha/markone, attach_right = FALSE)
var/obj/vehicle/sealed/mecha/working/ripley/mk2/marktwo = new (get_turf(markone),1)
if(!marktwo)
return
@@ -365,12 +390,10 @@
markone.capacitor.forceMove(marktwo)
markone.capacitor = null
marktwo.update_part_values()
- for(var/obj/item/mecha_parts/equipment in markone.contents)
- if(istype(equipment, /obj/item/mecha_parts/concealed_weapon_bay)) //why is the bay not just a variable change who did this
- equipment.forceMove(marktwo)
- for(var/obj/item/mecha_parts/mecha_equipment/equipment in markone.equipment) //Move the equipment over...
+ for(var/obj/item/mecha_parts/mecha_equipment/equipment in markone.flat_equipment) //Move the equipment over...
+ var/righthandgun = markone.equip_by_category[MECHA_R_ARM] == equipment
equipment.detach(marktwo)
- equipment.attach(marktwo)
+ equipment.attach(marktwo, righthandgun)
marktwo.dna_lock = markone.dna_lock
marktwo.mecha_flags = markone.mecha_flags
marktwo.strafe = markone.strafe
diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
index 5221b479266..4e622482877 100644
--- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
+++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
@@ -1,6 +1,7 @@
/obj/item/mecha_parts/mecha_equipment/weapon
name = "mecha weapon"
range = MECHA_RANGED
+ equipment_slot = MECHA_WEAPON
destroy_sound = 'sound/mecha/weapdestr.ogg'
var/projectile
var/fire_sound
@@ -12,13 +13,11 @@
var/kickback = TRUE //Will using this weapon in no grav push mecha back.
mech_flags = EXOSUIT_MODULE_COMBAT
-/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
if(!..())
return FALSE
if(istype(M, /obj/vehicle/sealed/mecha/combat))
return TRUE
- if((locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents) && !(locate(/obj/item/mecha_parts/mecha_equipment/weapon) in M.equipment))
- return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/action(mob/source, atom/target, list/modifiers)
@@ -128,10 +127,10 @@
fire_sound = 'sound/weapons/plasma_cutter.ogg'
harmful = TRUE
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
if(..()) //combat mech
return TRUE
- else if(LAZYLEN(M.equipment) < M.max_equip)
+ else if(default_can_attach(M, attach_right))
return TRUE
return FALSE
@@ -147,11 +146,11 @@
harmful = TRUE
//attachable to all mechas, like the plasma cutter
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/mecha_kineticgun/can_attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/mecha_kineticgun/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
. = ..()
if(.) //combat mech
return
- if(LAZYLEN(M.equipment) < M.max_equip)
+ if(default_can_attach(M, attach_right))
return TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
@@ -174,7 +173,7 @@
kickback = FALSE
mech_flags = EXOSUIT_MODULE_HONK
-/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/vehicle/sealed/mecha/mecha)
+/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/vehicle/sealed/mecha/mecha, attach_right = FALSE)
. = ..()
if(!.)
return
@@ -220,7 +219,6 @@
var/projectiles
var/projectiles_cache //ammo to be loaded in, if possible.
var/projectiles_cache_max
- var/projectile_energy_cost
var/disabledreload //For weapons with no cache (like the rockets) which are reloaded by hand
var/ammo_type
@@ -231,51 +229,35 @@
return FALSE
return TRUE
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info()
- return "[..()] \[[projectiles][projectiles_cache_max &&!projectile_energy_cost?"/[projectiles_cache]":""]\][!disabledreload &&(src.projectiles < initial(src.projectiles))?" - Rearm":null]"
-
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(action == "reload")
+ rearm()
+ return TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/rearm()
if(projectiles < initial(projectiles))
var/projectiles_to_add = initial(projectiles) - projectiles
-
- if(projectile_energy_cost)
- while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add)
- projectiles++
- projectiles_to_add--
- chassis.use_power(projectile_energy_cost)
-
+ if(!projectiles_cache)
+ return FALSE
+ if(projectiles_to_add <= projectiles_cache)
+ projectiles = projectiles + projectiles_to_add
+ projectiles_cache = projectiles_cache - projectiles_to_add
else
- if(!projectiles_cache)
- return FALSE
- if(projectiles_to_add <= projectiles_cache)
- projectiles = projectiles + projectiles_to_add
- projectiles_cache = projectiles_cache - projectiles_to_add
- else
- projectiles = projectiles + projectiles_cache
- projectiles_cache = 0
-
- send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
+ projectiles = projectiles + projectiles_cache
+ projectiles_cache = 0
log_message("Rearmed [src].", LOG_MECHA)
return TRUE
-
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/needs_rearm()
return projectiles <= 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list)
- ..()
- if (href_list["rearm"])
- rearm()
-
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(mob/source, atom/target, list/modifiers)
- if(..())
- projectiles -= projectiles_per_shot
- send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
- return ..()
-
+ . = ..()
+ if(!.)
+ return
+ projectiles -= projectiles_per_shot
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine
name = "\improper FNX-99 \"Hades\" Carbine"
@@ -297,7 +279,7 @@
equip_cooldown = 30
projectile = /obj/projectile/bullet/mime
projectiles = 6
- projectile_energy_cost = 50
+ projectiles_cache = 999
harmful = TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
@@ -419,11 +401,11 @@
fire_sound = 'sound/items/bikehorn.ogg'
projectiles = 15
missile_speed = 1.5
- projectile_energy_cost = 100
+ projectiles_cache = 999
equip_cooldown = 20
mech_flags = EXOSUIT_MODULE_HONK
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M, attach_right = FALSE)
if(..())
if(istype(M))
return 1
@@ -437,11 +419,11 @@
fire_sound = 'sound/items/bikehorn.ogg'
projectiles = 15
missile_speed = 1.5
- projectile_energy_cost = 100
+ projectiles_cache = 999
equip_cooldown = 10
mech_flags = EXOSUIT_MODULE_HONK
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M, attach_right = FALSE)
if(..())
if(istype(M))
return 1
@@ -463,40 +445,34 @@
projectile = /obj/item/punching_glove
fire_sound = 'sound/items/bikehorn.ogg'
projectiles = 10
- projectile_energy_cost = 500
+ projectiles_cache = 999
harmful = TRUE
diags_first = TRUE
/// Damage done by the glove on contact. Also used to determine throw distance (damage / 5)
var/punch_damage = 35
- /// TRUE - Can toggle between lethal and non-lethal || FALSE - Cannot toggle
- var/can_toggle_lethal = TRUE
mech_flags = EXOSUIT_MODULE_HONK
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/vehicle/sealed/mecha/combat/honker/M, attach_right = FALSE)
if(..())
if(istype(M))
return 1
return 0
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/get_equip_info()
- if(!chassis)
- return
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/get_snowflake_data()
+ return list(
+ "snowflake_id" = MECHA_SNOWFLAKE_ID_MODE,
+ "mode" = harmful ? "LETHAL FISTING" : "Cuddles",
+ )
- if(can_toggle_lethal)
- return "[..()] [harmful?"Punch":"Pat"] mode"
- else
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/Topic(href, href_list)
- ..()
- if(href_list["lethalPunch"])
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/ui_act(action, list/params)
+ . = ..()
+ if(action == "toggle")
harmful = !harmful
- if(!chassis)
- return
if(harmful)
to_chat(usr, "[icon2html(src, usr)][span_warning("Lethal Fisting Enabled.")]")
else
to_chat(usr, "[icon2html(src, usr)][span_warning("Lethal Fisting Disabled.")]")
+ return TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(mob/source, atom/target, list/modifiers)
. = ..()
@@ -535,9 +511,9 @@
icon_state = "mecha_bananamrtr"
projectile = /obj/item/grown/bananapeel/bombanana
projectiles = 8
- projectile_energy_cost = 1000
+ projectiles_cache = 999
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana/can_attach(obj/vehicle/sealed/mecha/combat/honker/M, attach_right = FALSE)
if(..())
if(istype(M))
return TRUE
@@ -551,11 +527,11 @@
fire_sound = 'sound/weapons/gun/general/grenade_launch.ogg'
projectiles = 6
missile_speed = 1.5
- projectile_energy_cost = 800
+ projectiles_cache = 999
equip_cooldown = 60
det_time = 20
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache/can_attach(obj/vehicle/sealed/mecha/combat/honker/M, attach_right = FALSE)
if(..())
if(istype(M))
return TRUE
diff --git a/code/modules/vehicles/mecha/mech_melee_attack.dm b/code/modules/vehicles/mecha/mech_melee_attack.dm
index ffd9b6b3662..7b1261b6f4a 100644
--- a/code/modules/vehicles/mecha/mech_melee_attack.dm
+++ b/code/modules/vehicles/mecha/mech_melee_attack.dm
@@ -9,18 +9,12 @@
*/
/atom/proc/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/living/user)
SHOULD_CALL_PARENT(TRUE)
- var/mech_damtype = mecha_attacker.damtype
- if(mecha_attacker.selected)
- mech_damtype = mecha_attacker.selected.damtype
- log_combat(user, src, "attacked", mecha_attacker, "(COMBAT MODE: [uppertext(user.combat_mode)] (DAMTYPE: [uppertext(mech_damtype)])")
+ log_combat(user, src, "attacked", mecha_attacker, "(COMBAT MODE: [uppertext(user.combat_mode)] (DAMTYPE: [uppertext(mecha_attacker.damtype)])")
return 0
/turf/closed/wall/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/living/user)
mecha_attacker.do_attack_animation(src)
- var/mech_damtype = mecha_attacker.damtype
- if(mecha_attacker.selected)
- mech_damtype = mecha_attacker.selected.damtype
- switch(mech_damtype)
+ switch(mecha_attacker.damtype)
if(BRUTE)
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
if(BURN)
@@ -38,10 +32,7 @@
/obj/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/living/user)
mecha_attacker.do_attack_animation(src)
- var/mech_damtype = mecha_attacker.damtype
- if(mecha_attacker.selected)
- mech_damtype = mecha_attacker.selected.damtype
- switch(mech_damtype)
+ switch(mecha_attacker.damtype)
if(BRUTE)
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
if(BURN)
@@ -50,7 +41,7 @@
return 0
mecha_attacker.visible_message(span_danger("[mecha_attacker] hits [src]!"), span_danger("You hit [src]!"), null, COMBAT_MESSAGE_RANGE)
..()
- return take_damage(mecha_attacker.force * 3, mech_damtype, "melee", mecha_attacker.selected, get_dir(src, mecha_attacker)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs.
+ return take_damage(mecha_attacker.force * 3, mecha_attacker.damtype, "melee", FALSE, get_dir(src, mecha_attacker)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs.
/obj/structure/window/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/living/user)
if(!can_be_reached())
diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm
index a96baa0f5ac..266a84a51f9 100644
--- a/code/modules/vehicles/mecha/mecha_actions.dm
+++ b/code/modules/vehicles/mecha/mecha_actions.dm
@@ -40,52 +40,6 @@
chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA)
UpdateButtonIcon()
-/datum/action/vehicle/sealed/mecha/mech_cycle_equip
- name = "Cycle Equipment"
- button_icon_state = "mech_cycle_equip_off"
-
-/datum/action/vehicle/sealed/mecha/mech_cycle_equip/Trigger(trigger_flags)
- if(!owner || !chassis || !(owner in chassis.occupants))
- return
-
- var/list/available_equipment = list()
- for(var/e in chassis.equipment)
- var/obj/item/mecha_parts/mecha_equipment/equipment = e
- if(equipment.selectable)
- available_equipment += equipment
-
- if(available_equipment.len == 0)
- chassis.balloon_alert(owner, "no equipment available")
- playsound(chassis,'sound/machines/terminal_error.ogg', 40, FALSE)
- return
- if(!chassis.selected)
- chassis.selected = available_equipment[1]
- chassis.balloon_alert(owner, "[chassis.selected] selected")
- send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
- button_icon_state = "mech_cycle_equip_on"
- playsound(chassis,'sound/machines/piston_raise.ogg', 40, TRUE)
- UpdateButtonIcon()
- return
- var/number = 0
- for(var/equipment in available_equipment)
- number++
- if(equipment != chassis.selected)
- continue
- if(available_equipment.len == number)
- chassis.selected = null
- chassis.balloon_alert(owner, "switched to no equipment")
- button_icon_state = "mech_cycle_equip_off"
- playsound(chassis,'sound/machines/piston_lower.ogg', 40, TRUE)
- else
- chassis.selected = available_equipment[number+1]
- chassis.balloon_alert(owner, "switched to [chassis.selected]")
- button_icon_state = "mech_cycle_equip_on"
- playsound(chassis,'sound/machines/piston_raise.ogg', 40, TRUE)
- send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
- UpdateButtonIcon()
- return
-
-
/datum/action/vehicle/sealed/mecha/mech_toggle_lights
name = "Toggle Lights"
button_icon_state = "mech_lights_off"
@@ -116,9 +70,7 @@
if(!owner || !chassis || !(owner in chassis.occupants))
return
- var/datum/browser/popup = new(owner , "exosuit")
- popup.set_content(chassis.get_stats_html(owner))
- popup.open()
+ chassis.ui_interact(owner)
/datum/action/vehicle/sealed/mecha/strafe
diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm
index e5e70fb47e8..b52cd69a879 100644
--- a/code/modules/vehicles/mecha/mecha_control_console.dm
+++ b/code/modules/vehicles/mecha/mecha_control_console.dm
@@ -31,7 +31,6 @@
airtank = M.internal_tank ? M.return_pressure() : null,
pilot = M.return_drivers(),
location = get_area_name(M, TRUE),
- active_equipment = M.selected,
emp_recharging = MT.recharging,
tracker_ref = REF(MT)
)
@@ -98,8 +97,7 @@
Cell Charge: [isnull(cell_charge) ? "Not Found":"[chassis.cell.percent()]%"]
Airtank: [chassis.internal_tank ? "[round(chassis.return_pressure(), 0.01)]" : "Not Equipped"] kPa
Pilot: [chassis.return_drivers() || "None"]
- Location: [get_area_name(chassis, TRUE) || "Unknown"]
- Active Equipment: [chassis.selected || "None"]"}
+ Location: [get_area_name(chassis, TRUE) || "Unknown"]"}
if(istype(chassis, /obj/vehicle/sealed/mecha/working/ripley))
var/obj/vehicle/sealed/mecha/working/ripley/RM = chassis
answer += "
Used Cargo Space: [round((LAZYLEN(RM.cargo) / RM.cargo_capacity * 100), 0.01)]%"
@@ -118,7 +116,7 @@
chassis = null
return ..()
-/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE)
if(!..())
return
M.trackers += src
diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm
index c0c32b3c5d4..61411b077cd 100644
--- a/code/modules/vehicles/mecha/mecha_defense.dm
+++ b/code/modules/vehicles/mecha/mecha_defense.dm
@@ -1,3 +1,19 @@
+/*!
+ * # 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!
@@ -6,50 +22,52 @@
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)
+ return
+ var/obj/item/mecha_parts/mecha_equipment/gear
+ switch(def_zone)
+ if(BODY_ZONE_L_ARM)
+ gear = equip_by_category[MECHA_L_ARM]
+ if(BODY_ZONE_R_ARM)
+ gear = equip_by_category[MECHA_R_ARM]
+ if(!gear)
+ return
+ var/brokenstatus = gear.get_integrity()
+ // always leave at least 1 health
+ brokenstatus--
+ var/damage_to_deal = min(brokenstatus, damage)
+ if(!damage_to_deal)
+ return
+ gear.take_damage(damage_to_deal)
+
/obj/vehicle/sealed/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(. && atom_integrity > 0)
spark_system.start()
- switch(damage_flag)
- if(FIRE)
- check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL))
- if(MELEE)
- check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
- else
- check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT))
+ try_deal_internal_damage(.)
if(. >= 5 || prob(33))
to_chat(occupants, "[icon2html(src, occupants)][span_userdanger("Taking damage!")]")
- log_message("Took [damage_amount] points of damage. Damage type: [damage_type]", LOG_MECHA)
+ log_message("Took [.] points of damage. Damage type: [damage_type]", LOG_MECHA)
-/obj/vehicle/sealed/mecha/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
+/obj/vehicle/sealed/mecha/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penentration)
. = ..()
- if(!damage_amount)
- return 0
- var/booster_deflection_modifier = 1
- var/booster_damage_modifier = 1
- if(damage_flag == BULLET || damage_flag == LASER || damage_flag == ENERGY)
- for(var/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/B in equipment)
- if(B.projectile_react())
- booster_deflection_modifier = B.deflect_coeff
- booster_damage_modifier = B.damage_coeff
- break
- else if(damage_flag == MELEE)
- for(var/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/B in equipment)
- if(B.attack_react())
- booster_deflection_modifier *= B.deflect_coeff
- booster_damage_modifier *= B.damage_coeff
- break
-
if(attack_dir)
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
- booster_damage_modifier /= facing_modifier
- booster_deflection_modifier *= facing_modifier
- if(prob(deflect_chance * booster_deflection_modifier))
- visible_message(span_danger("[src]'s armour deflects the attack!"))
- log_message("Armor saved.", LOG_MECHA)
- return 0
- if(.)
- . *= booster_damage_modifier
+ if(.)
+ . *= facing_modifier
/obj/vehicle/sealed/mecha/attack_hand(mob/living/user, list/modifiers)
. = ..()
@@ -58,15 +76,15 @@
user.changeNext_move(CLICK_CD_MELEE) // Ugh. Ideally we shouldn't be setting cooldowns outside of click code.
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
playsound(loc, 'sound/weapons/tap.ogg', 40, TRUE, -1)
- user.visible_message(span_danger("[user] hits [name]. Nothing happens."), null, null, COMBAT_MESSAGE_RANGE)
- log_message("Attack by hand/paw. Attacker - [user].", LOG_MECHA, color="red")
+ user.visible_message(span_danger("[user] hits [src]. Nothing happens."), null, null, COMBAT_MESSAGE_RANGE)
+ log_message("Attack by hand/paw (no damage). Attacker - [user].", LOG_MECHA, color="red")
/obj/vehicle/sealed/mecha/attack_paw(mob/user, list/modifiers)
return attack_hand(user, modifiers)
/obj/vehicle/sealed/mecha/attack_alien(mob/living/user, list/modifiers)
log_message("Attack by alien. Attacker - [user].", LOG_MECHA, color="red")
- playsound(src.loc, 'sound/weapons/slash.ogg', 100, TRUE)
+ playsound(loc, 'sound/weapons/slash.ogg', 100, TRUE)
attack_generic(user, rand(user.melee_damage_lower, user.melee_damage_upper), BRUTE, MELEE, 0)
/obj/vehicle/sealed/mecha/attack_animal(mob/living/simple_animal/user, list/modifiers)
@@ -106,22 +124,20 @@
/obj/vehicle/sealed/mecha/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) //wrapper
log_message("Hit by [AM].", LOG_MECHA, color="red")
- . = ..()
+ return ..()
-/obj/vehicle/sealed/mecha/bullet_act(obj/projectile/Proj) //wrapper
- if(!enclosed && LAZYLEN(occupants) && !(mecha_flags & SILICON_PILOT) && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs
- for(var/m in occupants)
- var/mob/living/hitmob = m
- hitmob.bullet_act(Proj) //If the sides are open, the occupant can be hit
+/obj/vehicle/sealed/mecha/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit) //wrapper
+ if(!enclosed && LAZYLEN(occupants) && !(mecha_flags & SILICON_PILOT) && (hitting_projectile.def_zone == BODY_ZONE_HEAD || hitting_projectile.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs
+ for(var/mob/living/hitmob as anything in occupants)
+ hitmob.bullet_act(hitting_projectile, def_zone, piercing_hit) //If the sides are open, the occupant can be hit
return BULLET_ACT_HIT
- log_message("Hit by projectile. Type: [Proj.name]([Proj.armor_flag]).", LOG_MECHA, color="red")
- . = ..()
+ log_message("Hit by projectile. Type: [hitting_projectile]([hitting_projectile.damage_type]).", LOG_MECHA, color="red")
+ // yes we *have* to run the armor calc proc here I love tg projectile code too
+ try_damage_component(run_atom_armor(hitting_projectile.damage, hitting_projectile.damage_type, hitting_projectile.damage_type, 0, REVERSE_DIR(hitting_projectile.dir), hitting_projectile.armour_penetration), hitting_projectile.def_zone)
+ return ..()
/obj/vehicle/sealed/mecha/ex_act(severity, target)
log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red")
- if(prob(deflect_chance))
- severity--
- log_message("Armor saved, changing severity to [severity]", LOG_MECHA)
return ..()
/obj/vehicle/sealed/mecha/contents_explosion(severity, target)
@@ -129,29 +145,29 @@
switch(severity)
if(EXPLODE_DEVASTATE)
- if(equipment)
- SSexplosions.high_mov_atom += equipment
+ if(flat_equipment)
+ SSexplosions.high_mov_atom += flat_equipment
if(trackers)
SSexplosions.high_mov_atom += trackers
if(occupants)
SSexplosions.high_mov_atom += occupants
if(EXPLODE_HEAVY)
- if(equipment)
- SSexplosions.med_mov_atom += equipment
+ if(flat_equipment)
+ SSexplosions.med_mov_atom += flat_equipment
if(trackers)
SSexplosions.med_mov_atom += trackers
if(occupants)
SSexplosions.med_mov_atom += occupants
if(EXPLODE_LIGHT)
- if(equipment)
- SSexplosions.low_mov_atom += equipment
+ if(flat_equipment)
+ SSexplosions.low_mov_atom += flat_equipment
if(trackers)
SSexplosions.low_mov_atom += trackers
if(occupants)
SSexplosions.low_mov_atom += occupants
/obj/vehicle/sealed/mecha/handle_atom_del(atom/A)
- if(A in occupants)
+ if(A in occupants) //todo does not work and in wrong file
LAZYREMOVE(occupants, A)
icon_state = initial(icon_state)+"-open"
setDir(dir_in)
@@ -165,15 +181,15 @@
take_damage(30 / severity, BURN, ENERGY, 1)
log_message("EMP detected", LOG_MECHA, color="red")
- if(istype(src, /obj/vehicle/sealed/mecha/combat))
+ 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
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)
- equipment_disabled = 1
+ addtimer(CALLBACK(src, /obj/vehicle/sealed/mecha.proc/restore_equipment), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
+ equipment_disabled = TRUE
/obj/vehicle/sealed/mecha/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return exposed_temperature > max_temperature
@@ -182,8 +198,14 @@
log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red")
take_damage(5, BURN, 0, 1)
-/obj/vehicle/sealed/mecha/attackby(obj/item/W, mob/user, params)
+/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
+ parts.try_attach_part(user, src, TRUE)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ return ..()
+/obj/vehicle/sealed/mecha/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/mmi))
if(mmi_move_inside(W,user))
to_chat(user, span_notice("[src]-[W] interface initialized successfully."))
@@ -198,13 +220,7 @@
if(W.GetID())
if((mecha_flags & ADDING_ACCESS_POSSIBLE) || (mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE))
if(internals_access_allowed(user))
- var/obj/item/card/id/id_card
- if(istype(W, /obj/item/card/id))
- id_card = W
- else
- var/obj/item/pda/pda = W
- id_card = pda.id
- output_maintenance_dialog(id_card, user)
+ ui_interact(user)
return
to_chat(user, span_warning("Invalid ID: Access denied."))
return
@@ -253,22 +269,15 @@
to_chat(user, span_warning("There's already a capacitor installed!"))
return
- if(istype(W, /obj/item/stack/cable_coil))
- if(construction_state == MECHA_OPEN_HATCH && (internal_damage & MECHA_INT_SHORT_CIRCUIT))
- var/obj/item/stack/cable_coil/CC = W
- if(CC.use(2))
- clear_internal_damage(MECHA_INT_SHORT_CIRCUIT)
- to_chat(user, span_notice("You replace the fused wires."))
- else
- to_chat(user, span_warning("You need two lengths of cable to fix this mech!"))
- return
-
if(istype(W, /obj/item/mecha_parts))
var/obj/item/mecha_parts/P = W
- P.try_attach_part(user, src)
+ P.try_attach_part(user, src, FALSE)
return
- log_message("Attacked by [W]. Attacker - [user]", LOG_MECHA)
- return ..()
+ . = ..()
+ log_message("Attacked by [W]. Attacker - [user], Damage - [.]", LOG_MECHA)
+ if(isliving(user))
+ var/mob/living/living_user = user
+ try_damage_component(., living_user.zone_selected)
/obj/vehicle/sealed/mecha/wrench_act(mob/living/user, obj/item/I)
..()
@@ -292,25 +301,11 @@
construction_state = MECHA_LOOSE_BOLTS
to_chat(user, span_notice("You close the hatch to the power unit."))
-/obj/vehicle/sealed/mecha/screwdriver_act(mob/living/user, obj/item/I)
- ..()
- . = TRUE
- if(internal_damage & MECHA_INT_TEMP_CONTROL)
- clear_internal_damage(MECHA_INT_TEMP_CONTROL)
- to_chat(user, span_notice("You repair the damaged temperature controller."))
- return
-
/obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W)
. = ..()
if(user.combat_mode)
return
. = TRUE
- if(internal_damage & MECHA_INT_TANK_BREACH)
- if(!W.use_tool(src, user, 0, volume=50, amount=1))
- return
- clear_internal_damage(MECHA_INT_TANK_BREACH)
- to_chat(user, span_notice("You repair the damaged gas tank."))
- return
if(atom_integrity < max_integrity)
if(!W.use_tool(src, user, 0, volume=50, amount=1))
return
@@ -319,7 +314,7 @@
if(atom_integrity == max_integrity)
to_chat(user, span_notice("It looks to be fully repaired now."))
return
- to_chat(user, span_warning("The [name] is at full integrity!"))
+ to_chat(user, span_warning("[src] is at full integrity!"))
/obj/vehicle/sealed/mecha/proc/full_repair(charge_cell)
atom_integrity = max_integrity
@@ -340,15 +335,12 @@
emp_act(EMP_HEAVY)
/obj/vehicle/sealed/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
- if(!no_effect)
- if(selected)
- used_item = selected
- else if(!visual_effect_icon)
- visual_effect_icon = ATTACK_EFFECT_SMASH
- if(damtype == BURN)
- visual_effect_icon = ATTACK_EFFECT_MECHFIRE
- else if(damtype == TOX)
- visual_effect_icon = ATTACK_EFFECT_MECHTOXIN
+ if(!no_effect && !visual_effect_icon)
+ visual_effect_icon = ATTACK_EFFECT_SMASH
+ if(damtype == BURN)
+ visual_effect_icon = ATTACK_EFFECT_MECHFIRE
+ else if(damtype == TOX)
+ visual_effect_icon = ATTACK_EFFECT_MECHTOXIN
..()
/obj/vehicle/sealed/mecha/atom_destruction()
@@ -362,7 +354,7 @@
continue
AI = crew
var/obj/structure/mecha_wreckage/WR = new wreckage(loc, AI)
- for(var/obj/item/mecha_parts/mecha_equipment/E in equipment)
+ for(var/obj/item/mecha_parts/mecha_equipment/E in flat_equipment)
if(E.detachable && prob(30))
WR.crowbar_salvage += E
E.detach(WR) //detaches from src into WR
diff --git a/code/modules/vehicles/mecha/mecha_parts.dm b/code/modules/vehicles/mecha/mecha_parts.dm
index b2282065cf3..9950e78311b 100644
--- a/code/modules/vehicles/mecha/mecha_parts.dm
+++ b/code/modules/vehicles/mecha/mecha_parts.dm
@@ -9,14 +9,14 @@
w_class = WEIGHT_CLASS_GIGANTIC
flags_1 = CONDUCT_1
-/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) //For attaching parts to a finished mech
+/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE) //For attaching parts to a finished mech
if(!user.transferItemToLoc(src, M))
to_chat(user, span_warning("\The [src] is stuck to your hand, you cannot put it in \the [M]!"))
return FALSE
user.visible_message(span_notice("[user] attaches [src] to [M]."), span_notice("You attach [src] to [M]."))
return TRUE
-/obj/item/mecha_parts/part/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/part/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE)
return
/obj/item/mecha_parts/chassis
diff --git a/code/modules/vehicles/mecha/mecha_topic.dm b/code/modules/vehicles/mecha/mecha_topic.dm
deleted file mode 100644
index 3039d2b8f49..00000000000
--- a/code/modules/vehicles/mecha/mecha_topic.dm
+++ /dev/null
@@ -1,428 +0,0 @@
-
-////////////////////////////////////
-///// Rendering stats window ///////
-////////////////////////////////////
-
-/obj/vehicle/sealed/mecha/proc/get_stats_html(mob/user)
- . = {"
-
-
- [name] data
-
-
-
-
-
- [get_stats_part(user)]
-
-
- [get_equipment_list()]
-
-
-
- [get_commands()]
-
-
-
- "}
-
-//Returns the autoupdate javascript script functions for the mecha ui.
-/obj/vehicle/sealed/mecha/proc/get_ssticker_function()
- . = {"
- function SSticker() {
- setInterval(function(){
- window.location='byond://?src=[REF(src)]&update_content=1';
- }, 1000);
- }
- "}
-
-///Returns the status of the mech.
-/obj/vehicle/sealed/mecha/proc/get_stats_part(mob/user)
- var/integrity = atom_integrity/max_integrity*100
- var/cell_charge = get_charge()
- var/datum/gas_mixture/int_tank_air = 0
- var/tank_pressure = 0
- var/tank_temperature = 0
- var/cabin_pressure = 0
- if (internal_tank)
- int_tank_air = internal_tank.return_air()
- tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
- tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
- cabin_pressure = round(return_pressure(),0.01)
- . = {"[report_internal_damage()]
- [integrity<30?"[span_userdanger("DAMAGE LEVEL CRITICAL")]
":null]
- Integrity: [integrity]%
- Power cell charge: [isnull(cell_charge)?"No power cell installed":"[cell.percent()]%"]
- Air source: [internal_tank?"[use_internal_tank?"Internal Airtank":"Environment"]":"Environment"]
- Airtank pressure: [internal_tank?"[tank_pressure]kPa":"N/A"]
- Airtank temperature: [internal_tank?"[tank_temperature]°K|[tank_temperature - T0C]°C":"N/A"]
- Cabin pressure: [internal_tank?"[cabin_pressure>WARNING_HIGH_PRESSURE ? span_danger("[cabin_pressure]"): cabin_pressure]kPa":"N/A"]
- Cabin temperature: [internal_tank?"[return_temperature()]°K|[return_temperature() - T0C]°C":"N/A"]
- [dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":""]
"}
- . += "[get_actions(user)]
"
-
-///Returns HTML for mech actions. Ideally, this proc would be empty for the base mecha. Segmented for easy refactoring.
-/obj/vehicle/sealed/mecha/proc/get_actions(mob/user)
- . = ""
- . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_defense_mode) ? "Defense Mode: [defense_mode ? "Enabled" : "Disabled"]
" : ""]"
- . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_overload_mode) ? "Leg Actuators Overload: [leg_overload_mode ? "Enabled" : "Disabled"]
" : ""]"
- . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_smoke) ? "Smoke Charges remaining: [smoke_charges]
" : ""]"
- . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_zoom) ? "Zoom: [zoom_mode ? "Enabled" : "Disabled"]
" : ""]"
- . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_switch_damtype) ? "Damtype: [damtype]
" : ""]"
- . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_toggle_phasing) ? "Phase Modulator: [phasing ? "Enabled" : "Disabled"]
" : ""]"
-
-///HTML for internal damage.
-/obj/vehicle/sealed/mecha/proc/report_internal_damage()
- . = ""
- var/list/dam_reports = list(
- "[MECHA_INT_FIRE]" = span_userdanger("INTERNAL FIRE"),
- "[MECHA_INT_TEMP_CONTROL]" = span_userdanger("LIFE SUPPORT SYSTEM MALFUNCTION"),
- "[MECHA_INT_TANK_BREACH]" = span_userdanger("GAS TANK BREACH"),
- "[MECHA_INT_CONTROL_LOST]" = "[span_userdanger("COORDINATION SYSTEM CALIBRATION FAILURE")] - Recalibrate",
- "[MECHA_INT_SHORT_CIRCUIT]" = span_userdanger("SHORT CIRCUIT")
- )
- for(var/tflag in dam_reports)
- var/intdamflag = text2num(tflag)
- if(internal_damage & intdamflag)
- . += dam_reports[tflag]
- . += "
"
- if(return_pressure() > WARNING_HIGH_PRESSURE)
- . += "[span_userdanger("DANGEROUSLY HIGH CABIN PRESSURE")]
"
-
-///HTML for list of equipment.
-/obj/vehicle/sealed/mecha/proc/get_equipment_list() //outputs mecha equipment list in html
- if(!LAZYLEN(equipment))
- return
- . = "Equipment:"
- for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment)
- . += "
[MT.get_equip_info()]
"
- . += "
"
-
-///HTML for commands.
-/obj/vehicle/sealed/mecha/proc/get_commands()
- . = {"
-
- "}
-
-
-/obj/vehicle/sealed/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu
- . = {"
-
-
-
"}
- for(var/e in equipment)
- var/obj/item/mecha_parts/mecha_equipment/equipment = e
- . += "[equipment.name] [equipment.detachable ? "
Detach" : "\[Non-removable\]
"]"
- . += {"
Available equipment slots: [max_equip-LAZYLEN(equipment)]
-
-
"}
-
-/obj/vehicle/sealed/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user)
- if(!id_card || !user)
- return
- . = {"
-
-
-
-
-
- Following keycodes are present in this system:
"}
- for(var/a in operation_req_access)
- . += "[SSid_access.get_access_desc(a)] - Delete
"
- . += "
Following keycodes were detected on portable device:
"
- for(var/a in id_card.access)
- if(a in operation_req_access)
- continue
- var/a_name = SSid_access.get_access_desc(a)
- if(!a_name)
- continue //there's some strange access without a name
- . += "[a_name] - Add
"
- . +={"
Lock ID panel
- [span_danger("(Warning! The ID upload panel can be unlocked only through Exosuit Interface.)")]
-
- "}
- user << browse(., "window=exosuit_add_access")
- onclose(user, "exosuit_add_access")
-
-
-/obj/vehicle/sealed/mecha/proc/output_maintenance_dialog(obj/item/card/id/id_card,mob/user)
- if(!id_card || !user)
- return
- . = {"
-
-
-
-
-
- [(mecha_flags & ADDING_ACCESS_POSSIBLE)?"Edit operation keycodes":null]
- [(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"[(construction_state > MECHA_LOCKED) ? "Terminate" : "Initiate"] maintenance protocol":null]
- [(construction_state == MECHA_OPEN_HATCH) ?"--------------------":null]
- [(construction_state == MECHA_OPEN_HATCH) ?"[cell?"Drop power cell":"No cell installed"]":null]
- [(construction_state == MECHA_OPEN_HATCH) ?"[scanmod?"Drop scanning module":"No scanning module installed"]":null]
- [(construction_state == MECHA_OPEN_HATCH) ?"[capacitor?"Drop capacitor":"No capacitor installed"]":null]
- [(construction_state == MECHA_OPEN_HATCH) ?"--------------------":null]
- [(construction_state > MECHA_LOCKED) ?"Set Cabin Air Pressure":null]
-
- "}
- user << browse(., "window=exosuit_maint_console")
- onclose(user, "exosuit_maint_console")
-
-
-
-
-/////////////////
-///// Topic /////
-/////////////////
-
-/obj/vehicle/sealed/mecha/Topic(href, href_list)
- ..()
-
- if(!usr)
- return
-
- if(href_list["close"])
- return
-
- if(usr.incapacitated())
- return
-
- if(in_range(src, usr))
- //Start of ID requirements.
- if(href_list["id_card"])
- var/obj/item/card/id/id_card
- id_card = locate(href_list["id_card"])
- if(!istype(id_card))
- return
-
- if(href_list["req_access"])
- if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
- return
- output_access_dialog(id_card,usr)
- return
-
- if(href_list["maint_access"])
- if(!(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE))
- return
- if(construction_state == MECHA_LOCKED)
- construction_state = MECHA_SECURE_BOLTS
- to_chat(usr, span_notice("The securing bolts are now exposed."))
- else if(construction_state == MECHA_SECURE_BOLTS)
- construction_state = MECHA_LOCKED
- to_chat(usr, span_notice("The securing bolts are now hidden."))
- output_maintenance_dialog(id_card,usr)
- return
- if(href_list["drop_cell"])
- if(construction_state == MECHA_OPEN_HATCH)
- cell.forceMove(get_turf(src))
- cell = null
- output_maintenance_dialog(id_card,usr)
- return
- if(href_list["drop_scanmod"])
- if(construction_state == MECHA_OPEN_HATCH)
- scanmod.forceMove(get_turf(src))
- scanmod = null
- output_maintenance_dialog(id_card,usr)
- return
- if(href_list["drop_cap"])
- if(construction_state == MECHA_OPEN_HATCH)
- capacitor.forceMove(get_turf(src))
- capacitor = null
- output_maintenance_dialog(id_card,usr)
- return
-
- if(href_list["add_req_access"])
- if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
- return
- operation_req_access += text2num(href_list["add_req_access"])
- output_access_dialog(id_card,usr)
- return
-
- if(href_list["del_req_access"])
- if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
- return
- operation_req_access -= text2num(href_list["del_req_access"])
- output_access_dialog(id_card, usr)
- return
- return //Here end everything requiring an ID.
-
- //Here ID access stuff goes to die.
- if(href_list["finish_req_access"])
- mecha_flags &= ~ADDING_ACCESS_POSSIBLE
- usr << browse(null,"window=exosuit_add_access")
- return
-
- //Set pressure.
- if(href_list["set_internal_tank_valve"] && construction_state)
- var/new_pressure = input(usr,"Input new output pressure","Pressure setting",internal_tank_valve) as num|null
- if(isnull(new_pressure) || usr.incapacitated() || !construction_state)
- return
- internal_tank_valve = new_pressure
- to_chat(usr, span_notice("The internal pressure valve has been set to [internal_tank_valve]kPa."))
- return
-
- //Start of all internal topic stuff.
- if(!locate(usr) in occupants)
- return
-
- if(href_list["update_content"])
- send_byjax(usr,"exosuit.browser","content", get_stats_part())
- return
-
- //Selects the mech equipment/weapon.
- if(href_list["select_equip"])
- var/obj/item/mecha_parts/mecha_equipment/equip = locate(href_list["select_equip"]) in src
- if(!equip || !equip.selectable)
- return
- selected = equip
- to_chat(occupants, "[icon2html(src, occupants)][span_notice("You switch to [equip].")]")
- visible_message(span_notice("[src] raises [equip]."))
- send_byjax(usr, "exosuit.browser", "eq_list", get_equipment_list())
- playsound(src,'sound/machines/piston_raise.ogg', 40, TRUE)
- return
-
- //Toggles radio broadcasting
- if(href_list["rmictoggle"])
- radio.set_broadcasting(!radio.get_broadcasting())
- send_byjax(usr,"exosuit.browser","rmicstate",(radio.get_broadcasting()?"Engaged":"Disengaged"))
- return
-
- //Toggles radio listening
- if(href_list["rspktoggle"])
- radio.set_listening(!radio.get_listening())
- send_byjax(usr,"exosuit.browser","rspkstate",(radio.get_listening()?"Engaged":"Disengaged"))
- return
-
- //Changes radio freqency.
- if(href_list["rfreq"])
- var/new_frequency = radio.get_frequency() + text2num(href_list["rfreq"])
- radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange))
- send_byjax(usr,"exosuit.browser","rfreq","[format_frequency(radio.get_frequency())]")
- return
-
- //Changes the exosuit name.
- if(href_list["change_name"])
- var/userinput = tgui_input_text(usr, "Choose a new exosuit name", "Rename exosuit", max_length = MAX_NAME_LEN)
- if(!userinput || !locate(usr) in occupants || usr.incapacitated())
- return
- name = userinput
- return
-
- //Toggles ID upload.
- if (href_list["toggle_id_upload"])
- mecha_flags ^= ADDING_ACCESS_POSSIBLE
- send_byjax(usr,"exosuit.browser","t_id_upload","[(mecha_flags & ADDING_ACCESS_POSSIBLE)?"L":"Unl"]ock ID upload panel")
- return
-
- //Toggles main access.
- if(href_list["toggle_maint_access"])
- if(construction_state)
- to_chat(occupants, "[icon2html(src, occupants)][span_danger("Maintenance protocols in effect")]")
- return
- mecha_flags ^= ADDING_MAINT_ACCESS_POSSIBLE
- send_byjax(usr,"exosuit.browser","t_maint_access","[(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"Forbid":"Permit"] maintenance protocols")
- return
-
- //Toggles connection port.
- if (href_list["toggle_port_connection"])
- if(internal_tank.connected_port)
- if(internal_tank.disconnect())
- to_chat(occupants, "[icon2html(src, occupants)][span_notice("Disconnected from the air system port.")]")
- log_message("Disconnected from gas port.", LOG_MECHA)
- else
- to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to disconnect from the air system port!")]")
- return
- else
- var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate() in loc
- if(internal_tank.connect(possible_port))
- to_chat(occupants, "[icon2html(src, occupants)][span_notice("Connected to the air system port.")]")
- log_message("Connected to gas port.", LOG_MECHA)
- else
- to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to connect with air system port!")]")
- return
- send_byjax(occupants,"exosuit.browser","t_port_connection","[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port")
- return
-
- //Turns on the DNA lock
- if(href_list["dna_lock"])
- var/mob/living/carbon/user = usr
- if(!istype(user) || !user.dna)
- to_chat(user, "[icon2html(src, occupants)][span_notice("You can't create a DNA lock with no DNA!.")]")
- return
- dna_lock = user.dna.unique_enzymes
- to_chat(user, "[icon2html(src, occupants)][span_notice("You feel a prick as the needle takes your DNA sample.")]")
- return
-
- //Resets the DNA lock
- if(href_list["reset_dna"])
- dna_lock = null
- return
-
- //Repairs internal damage
- if(href_list["repair_int_control_lost"])
- to_chat(occupants, "[icon2html(src, occupants)][span_notice("Recalibrating coordination system...")]")
- log_message("Recalibration of coordination system started.", LOG_MECHA)
- addtimer(CALLBACK(src, .proc/stationary_repair, loc), 100, TIMER_UNIQUE)
-
-///Repairs internal damage if the mech hasn't moved.
-/obj/vehicle/sealed/mecha/proc/stationary_repair(location)
- if(location == loc)
- clear_internal_damage(MECHA_INT_CONTROL_LOST)
- to_chat(occupants, "[icon2html(src, occupants)][span_notice("Recalibration successful.")]")
- log_message("Recalibration of coordination system finished with 0 errors.", LOG_MECHA)
- else
- to_chat(occupants, "[icon2html(src, occupants)][span_warning("Recalibration failed!")]")
- log_message("Recalibration of coordination system failed with 1 error.", LOG_MECHA, color="red")
diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm
new file mode 100644
index 00000000000..85530636130
--- /dev/null
+++ b/code/modules/vehicles/mecha/mecha_ui.dm
@@ -0,0 +1,319 @@
+/// A preview of the mech for the UI
+/atom/movable/screen/mech_view
+ name = "mechview"
+ del_on_map_removal = FALSE
+ layer = OBJ_LAYER
+ plane = GAME_PLANE
+
+ /// The body that is displayed
+ var/obj/vehicle/sealed/mecha/owner
+ ///list of plane masters to apply to owners
+ var/list/plane_masters = list()
+
+/atom/movable/screen/mech_view/Initialize(mapload, obj/vehicle/sealed/mecha/newowner)
+ . = ..()
+ owner = newowner
+ assigned_map = "mech_view_[REF(owner)]"
+ set_position(1, 1)
+ for(var/plane_master_type in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness)
+ var/atom/movable/screen/plane_master/plane_master = new plane_master_type()
+ plane_master.screen_loc = "[assigned_map]:CENTER"
+ plane_masters += plane_master
+
+/atom/movable/screen/mech_view/Destroy()
+ QDEL_LIST(plane_masters)
+ owner = null
+ return ..()
+
+/obj/vehicle/sealed/mecha/ui_close(mob/user)
+ . = ..()
+ user.client?.screen -= ui_view.plane_masters
+ user.client?.clear_map(ui_view.assigned_map)
+
+/obj/vehicle/sealed/mecha/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Mecha", name, ui_x, ui_y)
+ ui.open()
+ user.client?.screen |= ui_view.plane_masters
+ user.client?.register_map_obj(ui_view)
+
+/obj/vehicle/sealed/mecha/ui_status(mob/user)
+ if(contains(user))
+ return UI_INTERACTIVE
+ return min(
+ ui_status_user_is_abled(user, src),
+ ui_status_user_has_free_hands(user, src),
+ ui_status_user_is_advanced_tool_user(user),
+ ui_status_only_living(user),
+ max(
+ ui_status_user_is_adjacent(user, src),
+ ui_status_silicon_has_access(user, src),
+ )
+ )
+
+/obj/vehicle/sealed/mecha/ui_assets(mob/user)
+ return list(get_asset_datum(/datum/asset/spritesheet/mechaarmor))
+
+/obj/vehicle/sealed/mecha/ui_static_data(mob/user)
+ var/list/data = list()
+ data["cabin_dangerous_highpressure"] = WARNING_HIGH_PRESSURE
+ data["mineral_material_amount"] = MINERAL_MATERIAL_AMOUNT
+ //map of relevant flags to check tgui side, not every flag needs to be here
+ data["mechflag_keys"] = list(
+ "ADDING_ACCESS_POSSIBLE" = ADDING_ACCESS_POSSIBLE,
+ "ADDING_MAINT_ACCESS_POSSIBLE" = ADDING_MAINT_ACCESS_POSSIBLE,
+ "LIGHTS_ON" = LIGHTS_ON,
+ "HAS_LIGHTS" = HAS_LIGHTS,
+ )
+ data["internal_damage_keys"] = list(
+ "MECHA_INT_FIRE" = MECHA_INT_FIRE,
+ "MECHA_INT_TEMP_CONTROL" = MECHA_INT_TEMP_CONTROL,
+ "MECHA_INT_TANK_BREACH" = MECHA_INT_TANK_BREACH,
+ "MECHA_INT_CONTROL_LOST" = MECHA_INT_CONTROL_LOST,
+ )
+ data["mech_electronics"] = list(
+ "minfreq" = MIN_FREE_FREQ,
+ "maxfreq" = MAX_FREE_FREQ,
+ )
+ return data
+
+/obj/vehicle/sealed/mecha/ui_data(mob/user)
+ var/list/data = list()
+ var/isoperator = (user.loc == src) //maintenance mode outside of mech
+ data["isoperator"] = isoperator
+ if(!isoperator)
+ data["name"] = name
+ data["mecha_flags"] = mecha_flags
+ data["internal_tank_valve"] = internal_tank_valve
+ data["cell"] = cell?.name
+ data["scanning"] = scanmod?.name
+ data["capacitor"] = capacitor?.name
+ data["operation_req_access"] = list()
+ data["idcard_access"] = list()
+ for(var/code in operation_req_access)
+ data["operation_req_access"] += list(list("name" = SSid_access.get_access_desc(code), "number" = code))
+ if(!isliving(user))
+ return data
+ var/mob/living/living_user = user
+ var/obj/item/card/id/card = living_user.get_idcard(TRUE)
+ if(!card)
+ return data
+ for(var/idcode in card.access)
+ if(idcode in operation_req_access)
+ continue
+ var/accessname = SSid_access.get_access_desc(idcode)
+ if(!accessname)
+ continue //there's some strange access without a name
+ data["idcard_access"] += list(list("name" = accessname, "number" = idcode))
+ return data
+ ui_view.appearance = appearance
+ var/datum/gas_mixture/int_tank_air= internal_tank?.return_air()
+ data["name"] = name
+ data["integrity"] = atom_integrity/max_integrity
+ data["power_level"] = cell?.charge
+ data["power_max"] = cell?.maxcharge
+ data["mecha_flags"] = mecha_flags
+ data["internal_damage"] = internal_damage
+ data["air_source"] = use_internal_tank ? "Internal Airtank" : "Environment"
+ data["airtank_pressure"] = int_tank_air ? round(int_tank_air.return_pressure(), 0.01) : null
+ data["airtank_temp"] = int_tank_air?.temperature
+ data["port_connected"] = internal_tank?.connected_port ? TRUE : FALSE
+ data["cabin_pressure"] = round(return_pressure(), 0.01)
+ data["cabin_temp"] = return_temperature()
+ data["dna_lock"] = dna_lock
+ data["mech_view"] = ui_view.assigned_map
+ if(radio)
+ data["mech_electronics"] = list(
+ "microphone" = radio.get_broadcasting(),
+ "speaker" = radio.get_listening(),
+ "frequency" = radio.get_frequency(),
+ )
+ if(equip_by_category[MECHA_L_ARM])
+ var/obj/item/mecha_parts/mecha_equipment/l_gun = equip_by_category[MECHA_L_ARM]
+ var/isballisticweapon = istype(l_gun, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic)
+ data["left_arm_weapon"] = list(
+ "name" = l_gun.name,
+ "desc" = l_gun.desc,
+ "ref" = REF(l_gun),
+ "integrity" = (l_gun.get_integrity()/l_gun.max_integrity),
+ "isballisticweapon" = isballisticweapon,
+ "energy_per_use" = l_gun.energy_drain,
+ "snowflake" = l_gun.get_snowflake_data(),
+ )
+ if(isballisticweapon)
+ var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/weapon = l_gun
+ data["left_arm_weapon"] += list(
+ "projectiles" = weapon.projectiles,
+ "max_magazine" = initial(weapon.projectiles),
+ "projectiles_cache" = weapon.projectiles_cache,
+ "projectiles_cache_max" = weapon.projectiles_cache_max,
+ "disabledreload" = weapon.disabledreload,
+ "ammo_type" = weapon.ammo_type,
+ )
+ if(equip_by_category[MECHA_R_ARM])
+ var/obj/item/mecha_parts/mecha_equipment/r_gun = equip_by_category[MECHA_R_ARM]
+ var/isballisticweapon = istype(r_gun, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic)
+ data["right_arm_weapon"] = list(
+ "name" = r_gun.name,
+ "desc" = r_gun.desc,
+ "ref" = REF(r_gun),
+ "integrity" = (r_gun.get_integrity()/r_gun.max_integrity),
+ "isballisticweapon" = isballisticweapon,
+ "energy_per_use" = r_gun.energy_drain,
+ "snowflake" = r_gun.get_snowflake_data(),
+ )
+ if(isballisticweapon)
+ var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/weapon = r_gun
+ data["right_arm_weapon"] += list(
+ "projectiles" = weapon.projectiles,
+ "max_magazine" = initial(weapon.projectiles),
+ "projectiles_cache" = weapon.projectiles_cache,
+ "projectiles_cache_max" = weapon.projectiles_cache_max,
+ "disabledreload" = weapon.disabledreload,
+ "ammo_type" = weapon.ammo_type,
+ )
+ data["mech_equipment"] = list("utility" = list(), "power" = list(), "armor" = list())
+ for(var/obj/item/mecha_parts/mecha_equipment/utility as anything in equip_by_category[MECHA_UTILITY])
+ data["mech_equipment"]["utility"] += list(list(
+ "name" = utility.name,
+ "activated" = utility.activated,
+ "snowflake" = utility.get_snowflake_data(),
+ "ref" = REF(utility),
+ ))
+ for(var/obj/item/mecha_parts/mecha_equipment/power as anything in equip_by_category[MECHA_POWER])
+ data["mech_equipment"]["power"] += list(list(
+ "name" = power.name,
+ "activated" = power.activated,
+ "snowflake" = power.get_snowflake_data(),
+ "ref" = REF(power),
+ ))
+ for(var/obj/item/mecha_parts/mecha_equipment/armor/armor as anything in equip_by_category[MECHA_ARMOR])
+ data["mech_equipment"]["armor"] += list(list(
+ "protect_name" = armor.protect_name,
+ "iconstate_name" = armor.iconstate_name,
+ "ref" = REF(armor),
+ ))
+ return data
+
+/obj/vehicle/sealed/mecha/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+ if(usr.loc != src)
+ switch(action)
+ if("stopmaint")
+ mecha_flags &= ~ADDING_MAINT_ACCESS_POSSIBLE
+ ui.close()
+ return FALSE
+ if("togglemaint")
+ if(!(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE))
+ return FALSE
+ if(construction_state == MECHA_LOCKED)
+ construction_state = MECHA_SECURE_BOLTS
+ to_chat(usr, span_notice("The securing bolts are now exposed."))
+ else if(construction_state == MECHA_SECURE_BOLTS)
+ construction_state = MECHA_LOCKED
+ to_chat(usr, span_notice("The securing bolts are now hidden."))
+ if("drop_cell")
+ if(construction_state != MECHA_OPEN_HATCH)
+ return
+ cell.forceMove(get_turf(src))
+ cell = null
+ if("drop_scanning")
+ if(construction_state == MECHA_OPEN_HATCH)
+ return
+ scanmod.forceMove(get_turf(src))
+ scanmod = null
+ if("drop_capacitor")
+ if(construction_state == MECHA_OPEN_HATCH)
+ return
+ capacitor.forceMove(get_turf(src))
+ capacitor = null
+ if("set_pressure")
+ var/new_pressure = tgui_input_number(usr, "Enter new pressure", "Cabin pressure change", internal_tank_valve)
+ if(isnull(new_pressure) || !construction_state)
+ return
+ internal_tank_valve = new_pressure
+ to_chat(usr, span_notice("The internal pressure valve has been set to [internal_tank_valve]kPa."))
+ if("add_req_access")
+ if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
+ return
+ if(!(params["added_access"] == "all"))
+ operation_req_access += params["added_access"]
+ else
+ var/mob/living/living_user = usr
+ var/obj/item/card/id/card = living_user.get_idcard(TRUE)
+ operation_req_access += card.access
+ if("del_req_access")
+ if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
+ return
+ if(!(params["removed_access"] == "all"))
+ operation_req_access -= params["removed_access"]
+ else
+ operation_req_access = list()
+ if("lock_req_edit")
+ mecha_flags &= ~ADDING_ACCESS_POSSIBLE
+ return TRUE
+ if(!(usr in occupants))
+ return
+ switch(action)
+ if("changename")
+ var/userinput = tgui_input_text(usr, "Choose a new exosuit name", "Rename exosuit", max_length = MAX_NAME_LEN)
+ if(!userinput)
+ return
+ if(is_ic_filtered(userinput) || is_soft_ic_filtered(userinput))
+ tgui_alert(usr, "You cannot set a name that contains a word prohibited in IC chat!")
+ return
+ name = userinput
+ if("dna_lock")
+ var/mob/living/carbon/user = usr
+ if(!istype(user) || !user.dna)
+ to_chat(user, "[icon2html(src, occupants)][span_notice("You can't create a DNA lock with no DNA!.")]")
+ return
+ dna_lock = user.dna.unique_enzymes
+ to_chat(user, "[icon2html(src, occupants)][span_notice("You feel a prick as the needle takes your DNA sample.")]")
+ if("reset_dna")
+ dna_lock = null
+ if("view_dna")
+ tgui_alert(usr, "Enzymes detected: " + dna_lock)
+ return FALSE
+ if("toggle_airsource")
+ use_internal_tank = !use_internal_tank
+ balloon_alert(usr, "taking air from [use_internal_tank ? "internal airtank" : "environment"]")
+ log_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].", LOG_MECHA)
+ if("toggle_port")
+ if(internal_tank.connected_port)
+ if(internal_tank.disconnect())
+ to_chat(occupants, "[icon2html(src, occupants)][span_notice("Disconnected from the air system port.")]")
+ log_message("Disconnected from gas port.", LOG_MECHA)
+ return TRUE
+ to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to disconnect from the air system port!")]")
+ return
+ var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate() in loc
+ if(internal_tank.connect(possible_port))
+ to_chat(occupants, "[icon2html(src, occupants)][span_notice("Connected to the air system port.")]")
+ log_message("Connected to gas port.", LOG_MECHA)
+ return TRUE
+ to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to connect with air system port!")]")
+ if("toggle_maintenance")
+ if(construction_state)
+ to_chat(occupants, "[icon2html(src, occupants)][span_danger("Maintenance protocols in effect")]")
+ return
+ mecha_flags ^= ADDING_MAINT_ACCESS_POSSIBLE
+ if("toggle_id_panel")
+ mecha_flags ^= ADDING_ACCESS_POSSIBLE
+ if("toggle_microphone")
+ radio.set_broadcasting(!radio.get_broadcasting())
+ if("toggle_speaker")
+ radio.set_listening(!radio.get_listening())
+ if("set_frequency")
+ radio.set_frequency(sanitize_frequency(params["new_frequency"], radio.freerange))
+ if("repair_int_damage")
+ ui.close() //if doing this you're likely want to watch for bad people so close the UI
+ try_repair_int_damage(usr, params["flag"])
+ return FALSE
+ if("equip_act")
+ var/obj/item/mecha_parts/mecha_equipment/gear = locate(params["ref"]) in flat_equipment
+ return gear?.ui_act(params["gear_action"], params, ui, state)
+ return TRUE
diff --git a/code/modules/vehicles/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm
index 11629500afa..fbf4960e6c9 100644
--- a/code/modules/vehicles/mecha/medical/odysseus.dm
+++ b/code/modules/vehicles/mecha/medical/odysseus.dm
@@ -8,8 +8,6 @@
max_temperature = 15000
max_integrity = 120
wreckage = /obj/structure/mecha_wreckage/odysseus
- internal_damage_threshold = 35
- deflect_chance = 15
step_energy_drain = 6
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_MEDICAL)
diff --git a/code/modules/vehicles/mecha/working/clarke.dm b/code/modules/vehicles/mecha/working/clarke.dm
index ba901f0f2ed..49454ce7402 100644
--- a/code/modules/vehicles/mecha/working/clarke.dm
+++ b/code/modules/vehicles/mecha/working/clarke.dm
@@ -9,10 +9,20 @@
movedelay = 1.25
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
lights_power = 7
- deflect_chance = 10
step_energy_drain = 15 //slightly higher energy drain since you movin those wheels FAST
armor = list(MELEE = 20, BULLET = 10, LASER = 20, ENERGY = 10, BOMB = 60, BIO = 0, FIRE = 100, ACID = 100) //low armor to compensate for fire protection and speed
- max_equip = 7
+ equip_by_category = list(
+ MECHA_L_ARM = null,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/orebox_manager),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
+ max_equip_by_category = list(
+ MECHA_UTILITY = 3,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 1,
+ )
wreckage = /obj/structure/mecha_wreckage/clarke
enter_delay = 40
mecha_flags = ADDING_ACCESS_POSSIBLE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE | OMNIDIRECTIONAL_ATTACKS
@@ -21,8 +31,6 @@
/obj/vehicle/sealed/mecha/working/clarke/Initialize(mapload)
. = ..()
box = new(src)
- var/obj/item/mecha_parts/mecha_equipment/orebox_manager/ME = new(src)
- ME.attach(src)
/obj/vehicle/sealed/mecha/working/clarke/Destroy()
INVOKE_ASYNC(box, /obj/structure/ore_box/proc/dump_box_contents)
@@ -40,12 +48,13 @@
desc = "An automated ore box management device."
icon = 'icons/obj/mining.dmi'
icon_state = "bin"
+ equipment_slot = MECHA_UTILITY
selectable = FALSE
detachable = FALSE
/// Var to avoid istype checking every time the topic button is pressed. This will only work inside Clarke mechs.
var/obj/vehicle/sealed/mecha/working/clarke/hostmech
-/obj/item/mecha_parts/mecha_equipment/orebox_manager/attach(obj/vehicle/sealed/mecha/M)
+/obj/item/mecha_parts/mecha_equipment/orebox_manager/attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE)
. = ..()
if(istype(M, /obj/vehicle/sealed/mecha/working/clarke))
hostmech = M
@@ -54,14 +63,11 @@
hostmech = null //just in case
return ..()
-/obj/item/mecha_parts/mecha_equipment/orebox_manager/Topic(href,href_list)
+/obj/item/mecha_parts/mecha_equipment/orebox_manager/ui_act(action, list/params)
. = ..()
- if(!hostmech || !hostmech.box)
- return
- hostmech.box.dump_box_contents()
-
-/obj/item/mecha_parts/mecha_equipment/orebox_manager/get_equip_info()
- return "[..()] [hostmech?.box ? "Unload Cargo" : "Error"]"
+ if(action == "toggle")
+ hostmech.box?.dump_box_contents()
+ activated = TRUE
#define SEARCH_COOLDOWN 1 MINUTES
diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm
index 1b993806f60..c716ca373cc 100644
--- a/code/modules/vehicles/mecha/working/ripley.dm
+++ b/code/modules/vehicles/mecha/working/ripley.dm
@@ -5,30 +5,42 @@
base_icon_state = "ripley"
silicon_icon_state = "ripley-empty"
movedelay = 1.5 //Move speed, lower is faster.
- /// How fast the mech is in low pressure
- var/fast_pressure_step_in = 1.5
- /// How fast the mech is in normal pressure
- var/slow_pressure_step_in = 2
max_temperature = 20000
max_integrity = 200
+ ui_x = 1200
lights_power = 7
- deflect_chance = 15
armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, FIRE = 100, ACID = 100)
- max_equip = 6
+ max_equip_by_category = list(
+ MECHA_UTILITY = 2,
+ MECHA_POWER = 1,
+ MECHA_ARMOR = 1,
+ )
wreckage = /obj/structure/mecha_wreckage/ripley
+ possible_int_damage = MECHA_INT_FIRE|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT
internals_req_access = list(ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_MINING)
enclosed = FALSE //Normal ripley has an open cockpit design
enter_delay = 10 //can enter in a quarter of the time of other mechs
exit_delay = 10
+ /// Custom Ripley step and turning sounds (from TGMC)
+ stepsound = 'sound/mecha/powerloader_step.ogg'
+ turnsound = 'sound/mecha/powerloader_turn2.ogg'
+ equip_by_category = list(
+ MECHA_L_ARM = null,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/ejector),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
/// Amount of Goliath hides attached to the mech
var/hides = 0
/// List of all things in Ripley's Cargo Compartment
var/list/cargo
/// How much things Ripley can carry in their Cargo Compartment
var/cargo_capacity = 15
- /// Custom Ripley step and turning sounds (from TGMC)
- stepsound = 'sound/mecha/powerloader_step.ogg'
- turnsound = 'sound/mecha/powerloader_turn2.ogg'
+ /// How fast the mech is in low pressure
+ var/fast_pressure_step_in = 1.5
+ /// How fast the mech is in normal pressure
+ var/slow_pressure_step_in = 2
/obj/vehicle/sealed/mecha/working/ripley/Move()
. = ..()
@@ -36,16 +48,10 @@
/obj/vehicle/sealed/mecha/working/ripley/generate_actions() //isnt allowed to have internal air
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject)
- initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe)
-/obj/vehicle/sealed/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage, ignore_threshold = FALSE)
- if(!enclosed) //if we don't even have an air tank, these two doesn't make a ton of sense.
- possible_int_damage -= (MECHA_INT_TEMP_CONTROL + MECHA_INT_TANK_BREACH)
- return ..()
-
/obj/vehicle/sealed/mecha/working/ripley/Initialize(mapload)
. = ..()
AddComponent(/datum/component/armor_plate,3,/obj/item/stack/sheet/animalhide/goliath_hide,list(MELEE = 10, BULLET = 5, LASER = 5))
@@ -68,6 +74,7 @@
movedelay = 3 //SKYRAT EDIT - Movedelay is now 3, from 4.
max_temperature = 30000
max_integrity = 250
+ possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_INT_TANK_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT
armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, FIRE = 100, ACID = 100)
wreckage = /obj/structure/mecha_wreckage/ripley/mk2
enclosed = TRUE
@@ -77,7 +84,6 @@
/obj/vehicle/sealed/mecha/working/ripley/mk2/generate_actions()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals)
- initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe)
@@ -96,23 +102,23 @@
enclosed = TRUE
enter_delay = 40
silicon_icon_state = null
-
-/obj/vehicle/sealed/mecha/working/ripley/deathripley/Initialize(mapload)
- . = ..()
- var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/fake/clamper = new(loc)
- clamper.attach(src)
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/fake,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/ejector),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
/obj/vehicle/sealed/mecha/working/ripley/deathripley/real
desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE. FOR REAL"
-
-/obj/vehicle/sealed/mecha/working/ripley/deathripley/real/Initialize(mapload)
- . = ..()
- for(var/obj/item/mecha_parts/mecha_equipment/E in equipment)
- E.detach()
- qdel(E)
- LAZYCLEARLIST(equipment)
- var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/clamper = new(loc)
- clamper.attach(src)
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill,
+ MECHA_R_ARM = null,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/ejector),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(),
+ )
/obj/vehicle/sealed/mecha/working/ripley/mining
desc = "An old, dusty mining Ripley."
@@ -140,7 +146,7 @@
//Attach hydraulic clamp
var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new
- HC.attach(src)
+ HC.attach(src, TRUE)
var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new
scanner.attach(src)
@@ -149,7 +155,6 @@
name = "\improper APLU \"Big Bess\""
icon_state = "hauler"
base_icon_state = "hauler"
- max_equip = 2
max_integrity = 100 //Has half the health of a normal RIPLEY mech, so it's harder to use as a weapon.
/obj/vehicle/sealed/mecha/working/ripley/cargo/Initialize(mapload)
@@ -168,19 +173,6 @@
return FALSE
return ..()
-/obj/vehicle/sealed/mecha/working/ripley/Topic(href, href_list)
- ..()
- if(href_list["drop_from_cargo"])
- var/obj/cargoobj = locate(href_list["drop_from_cargo"]) in cargo
- if(cargoobj)
- to_chat(occupants, "[icon2html(src, occupants)][span_notice("You unload [cargoobj].")]")
- cargoobj.forceMove(drop_location())
- LAZYREMOVE(cargo, cargoobj)
- if(cargoobj == box)
- box = null
- log_message("Unloaded [cargoobj]. Cargo compartment capacity: [cargo_capacity - LAZYLEN(cargo)]", LOG_MECHA)
-
-
/obj/vehicle/sealed/mecha/working/ripley/contents_explosion(severity, target)
for(var/i in cargo)
var/obj/cargoobj = i
@@ -189,16 +181,38 @@
cargoobj.forceMove(drop_location())
return ..()
-/obj/vehicle/sealed/mecha/working/ripley/get_stats_part()
- var/output = ..()
- output += "Cargo Compartment Contents:"
- if(LAZYLEN(cargo))
- for(var/obj/O in cargo)
- output += "
Unload : [O]
"
- else
- output += "Nothing"
- output += "
"
- return output
+/obj/item/mecha_parts/mecha_equipment/ejector
+ name = "Cargo compartment"
+ equipment_slot = MECHA_UTILITY
+ detachable = FALSE
+
+/obj/item/mecha_parts/mecha_equipment/ejector/get_snowflake_data()
+ var/list/data = list("snowflake_id" = MECHA_SNOWFLAKE_ID_EJECTOR, "cargo" = list())
+ var/obj/vehicle/sealed/mecha/working/ripley/miner = chassis
+ for(var/obj/crate in miner.cargo)
+ data["cargo"] += list(list(
+ "name" = crate.name,
+ "ref" = REF(crate),
+ ))
+ return data
+
+/obj/item/mecha_parts/mecha_equipment/ejector/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return TRUE
+ if(action == "eject")
+ var/obj/vehicle/sealed/mecha/working/ripley/miner = chassis
+ var/obj/crate = locate(params["cargoref"]) in miner.cargo
+ if(!crate)
+ return FALSE
+ to_chat(miner.occupants, "[icon2html(src, miner.occupants)][span_notice("You unload [crate].")]")
+ crate.forceMove(drop_location())
+ LAZYREMOVE(miner.cargo, crate)
+ if(crate == miner.box)
+ miner.box = null
+ log_message("Unloaded [crate]. Cargo compartment capacity: [miner.cargo_capacity - LAZYLEN(miner.cargo)]", LOG_MECHA)
+ return TRUE
+
/obj/vehicle/sealed/mecha/working/ripley/relay_container_resist_act(mob/living/user, obj/O)
to_chat(user, span_notice("You lean on the back of [O] and start pushing so it falls out of [src]."))
@@ -222,10 +236,10 @@
if(lavaland_equipment_pressure_check(T))
movedelay = fast_pressure_step_in
- for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment)
+ for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in flat_equipment)
drill.equip_cooldown = initial(drill.equip_cooldown) * 0.5
else
movedelay = slow_pressure_step_in
- for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment)
+ for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in flat_equipment)
drill.equip_cooldown = initial(drill.equip_cooldown)
diff --git a/code/modules/vehicles/mecha/working/working.dm b/code/modules/vehicles/mecha/working/working.dm
index 8e630c91a58..3138fc0121c 100644
--- a/code/modules/vehicles/mecha/working/working.dm
+++ b/code/modules/vehicles/mecha/working/working.dm
@@ -1,5 +1,4 @@
/obj/vehicle/sealed/mecha/working
- internal_damage_threshold = 60
allow_diagonal_movement = TRUE
/// Handles an internal ore box for working mechs
var/obj/structure/ore_box/box
@@ -21,7 +20,7 @@
/obj/vehicle/sealed/mecha/working/proc/collect_ore()
if(!box)
return
- if(!(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in equipment) && !(locate(/obj/item/mecha_parts/mecha_equipment/orebox_manager) in equipment))
+ if(!(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in flat_equipment) && !(locate(/obj/item/mecha_parts/mecha_equipment/orebox_manager) in equip_by_category[MECHA_UTILITY]))
return
for(var/obj/item/stack/ore/ore in range(1, src))
if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) //we can reach it and it's in front of us? grab it!
diff --git a/icons/ui_icons/mecha/armor.dmi b/icons/ui_icons/mecha/armor.dmi
new file mode 100644
index 00000000000..665e3f665eb
Binary files /dev/null and b/icons/ui_icons/mecha/armor.dmi differ
diff --git a/modular_skyrat/modules/firefighter/code/firefighter.dm b/modular_skyrat/modules/firefighter/code/firefighter.dm
index c52b583a930..0b355b3d408 100644
--- a/modular_skyrat/modules/firefighter/code/firefighter.dm
+++ b/modular_skyrat/modules/firefighter/code/firefighter.dm
@@ -16,7 +16,6 @@
/obj/vehicle/sealed/mecha/working/ripley/firefighter/generate_actions()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals)
- initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe)
@@ -82,12 +81,6 @@
markone.capacitor.forceMove(mkf)
markone.capacitor = null
mkf.update_part_values()
- for(var/obj/item/mecha_parts/equipment in markone.contents)
- if(istype(equipment, /obj/item/mecha_parts/concealed_weapon_bay)) //why is the bay not just a variable change who did this
- equipment.forceMove(mkf)
- for(var/obj/item/mecha_parts/mecha_equipment/equipment in markone.equipment) //Move the equipment over...
- equipment.detach(mkf)
- equipment.attach(mkf)
mkf.dna_lock = markone.dna_lock
mkf.mecha_flags = markone.mecha_flags
mkf.strafe = markone.strafe
diff --git a/tgstation.dme b/tgstation.dme
index 50b0087aa23..6060b1485ec 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2277,6 +2277,7 @@
#include "code\modules\asset_cache\assets\language.dm"
#include "code\modules\asset_cache\assets\lobby.dm"
#include "code\modules\asset_cache\assets\mafia.dm"
+#include "code\modules\asset_cache\assets\mecha.dm"
#include "code\modules\asset_cache\assets\moods.dm"
#include "code\modules\asset_cache\assets\notes.dm"
#include "code\modules\asset_cache\assets\orbit.dm"
@@ -4233,7 +4234,7 @@
#include "code\modules\vehicles\mecha\mecha_control_console.dm"
#include "code\modules\vehicles\mecha\mecha_defense.dm"
#include "code\modules\vehicles\mecha\mecha_parts.dm"
-#include "code\modules\vehicles\mecha\mecha_topic.dm"
+#include "code\modules\vehicles\mecha\mecha_ui.dm"
#include "code\modules\vehicles\mecha\mecha_wreckage.dm"
#include "code\modules\vehicles\mecha\combat\combat.dm"
#include "code\modules\vehicles\mecha\combat\durand.dm"
@@ -4247,7 +4248,6 @@
#include "code\modules\vehicles\mecha\equipment\tools\medical_tools.dm"
#include "code\modules\vehicles\mecha\equipment\tools\mining_tools.dm"
#include "code\modules\vehicles\mecha\equipment\tools\other_tools.dm"
-#include "code\modules\vehicles\mecha\equipment\tools\weapon_bay.dm"
#include "code\modules\vehicles\mecha\equipment\tools\work_tools.dm"
#include "code\modules\vehicles\mecha\equipment\weapons\mecha_ammo.dm"
#include "code\modules\vehicles\mecha\equipment\weapons\weapons.dm"
diff --git a/tgui/packages/tgui/interfaces/ExosuitControlConsole.js b/tgui/packages/tgui/interfaces/ExosuitControlConsole.js
index 108660f86b3..8ca786f8180 100644
--- a/tgui/packages/tgui/interfaces/ExosuitControlConsole.js
+++ b/tgui/packages/tgui/interfaces/ExosuitControlConsole.js
@@ -86,9 +86,6 @@ export const ExosuitControlConsole = (props, context) => {
{mech.location || 'Unknown'}
-
- {mech.active_equipment || 'None'}
-
{mech.cargo_space >= 0 && (
{
+ const { act, data } = useBackend(context);
+ const {
+ internal_damage,
+ internal_damage_keys,
+ } = data;
+ return (
+
+ {Object.keys(internal_damage_keys).map(t => (
+
+
+
+
+ {(internal_damage & internal_damage_keys[t])
+ ?InternalDamageToDamagedDesc[t]:InternalDamageToNormalDesc[t]}
+
+
+
+
+
+
+
+ ))}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/ArmPane.tsx b/tgui/packages/tgui/interfaces/Mecha/ArmPane.tsx
new file mode 100644
index 00000000000..429da85366a
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/ArmPane.tsx
@@ -0,0 +1,261 @@
+import { toFixed } from 'common/math';
+import { useBackend } from '../../backend';
+import { Button, LabeledList, Stack, Section, ProgressBar } from '../../components';
+import { MechWeapon, OperatorData } from './data';
+
+export const ArmPane=(props:{weapon:MechWeapon}, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ name,
+ desc,
+ integrity,
+ energy_per_use,
+ } = props.weapon;
+ const {
+ power_level,
+ } = data;
+ return (
+
+
+ {name}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {energy_per_use} energy per use
+
+
+ {power_level? toFixed(power_level/energy_per_use):0} uses left
+
+
+
+
+
+
+
+
+ {desc}
+
+
+ );
+};
+
+const BallisticStats = (props: {weapon: MechWeapon}, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ isballisticweapon,
+ disabledreload,
+ projectiles,
+ max_magazine,
+ projectiles_cache,
+ projectiles_cache_max,
+ ammo_type,
+ ref,
+ } = props.weapon;
+ if (!isballisticweapon) {
+ return null;
+ } else {
+ return (
+ <>
+
+ {projectiles} / {max_magazine}
+
+ {disabledreload ? (null
+ ) : (
+ <>
+
+ {projectiles_cache} / {projectiles_cache_max}
+
+
+
+
+ >)}
+
+ {ammo_type}
+
+ >
+ );
+ }
+};
+
+const MECHA_SNOWFLAKE_ID_SLEEPER = "sleeper_snowflake";
+const MECHA_SNOWFLAKE_ID_SYRINGE = "syringe_snowflake";
+const MECHA_SNOWFLAKE_ID_MODE = "mode_snowflake";
+const MECHA_SNOWFLAKE_ID_EXTINGUISHER = "extinguisher_snowflake";
+
+// Handles all the snowflake buttons and whatever
+const Snowflake = (props: {weapon: MechWeapon}, context) => {
+ const {
+ snowflake,
+ } = props.weapon;
+ switch (snowflake["snowflake_id"]) {
+ case MECHA_SNOWFLAKE_ID_SLEEPER:
+ return ;
+ case MECHA_SNOWFLAKE_ID_SYRINGE:
+ return ;
+ case MECHA_SNOWFLAKE_ID_EXTINGUISHER:
+ return ;
+ case MECHA_SNOWFLAKE_ID_MODE:
+ return ;
+ default:
+ return null;
+ }
+};
+
+const SnowflakeSleeper = (props: {weapon: MechWeapon}, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ patient,
+ } = props.weapon.snowflake;
+ if (!patient) {
+ return null;
+ } else {
+ return (
+
+
+
+ {patient.isdead ? "DECEASED" : "ALIVE"}
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+};
+
+const SnowflakeSyringe = (props: {weapon: MechWeapon}, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ mode,
+ syringe,
+ max_syringe,
+ reagents,
+ total_reagents,
+ } = props.weapon.snowflake;
+ return (
+
+
+
+ {syringe}/{max_syringe}
+
+
+ {reagents}/{total_reagents}
+
+
+
+
+
+
+
+ );
+};
+
+const SnowflakeExtinguisher = (props: {weapon: MechWeapon}, context) => {
+ const {
+ reagents,
+ total_reagents,
+ } = props.weapon.snowflake;
+ return (
+
+
+
+ {reagents}/{total_reagents}
+
+
+
+ );
+};
+
+const SnowflakeMode = (props: {weapon: MechWeapon}, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ mode,
+ name,
+ } = props.weapon.snowflake;
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/ArmorPane.tsx b/tgui/packages/tgui/interfaces/Mecha/ArmorPane.tsx
new file mode 100644
index 00000000000..d963b656c88
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/ArmorPane.tsx
@@ -0,0 +1,40 @@
+import { useBackend } from '../../backend';
+import { Stack, Button, Box } from '../../components';
+import { OperatorData } from './data';
+import { classes } from 'common/react';
+
+export const ArmorPane = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ mech_equipment,
+ } = data;
+ return (
+
+ {mech_equipment["armor"].map((module, i) => (
+
+
+
+ {module.protect_name}
+
+
+
+
+
+
+
+
+ ))}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/MaintMode.tsx b/tgui/packages/tgui/interfaces/Mecha/MaintMode.tsx
new file mode 100644
index 00000000000..baab13da0c9
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/MaintMode.tsx
@@ -0,0 +1,258 @@
+import { MaintData } from './data';
+import { useBackend, useLocalState } from '../../backend';
+import { Stack, Button, Box } from '../../components';
+
+const MECHA_MAINT_PANELS = {
+ main: {
+ returnfluff: '',
+ component: () => MainPanel,
+ },
+ stockparts: {
+ returnfluff: 'Close stock parts panel',
+ component: () => StockPartsPanel,
+ },
+ access: {
+ returnfluff: 'Close permissions panel',
+ component: () => AccessPanel,
+ },
+};
+
+export const MaintMode = (props, context) => {
+ const [screen, setPanel] = useLocalState(context, 'screen', MECHA_MAINT_PANELS.main);
+ const Component = screen.component();
+ return (
+
+
+ {screen.returnfluff ?
+
+
+
+
+ );
+};
+
+const MainPanel = (props, context) => {
+ const { act, data } = useBackend(context);
+ const [screen, setPanel] = useLocalState(context, 'screen', MECHA_MAINT_PANELS.main);
+ const {
+ mecha_flags,
+ mechflag_keys,
+ } = data;
+ return (
+
+ {(mecha_flags & mechflag_keys["ADDING_MAINT_ACCESS_POSSIBLE"]) ? : null}
+
+ {(mecha_flags & mechflag_keys["ADDING_ACCESS_POSSIBLE"]) ?
+
+ );
+};
+
+const MaintEnabled = (props, context) => {
+ const { act, data } = useBackend(context);
+ const [screen, setPanel] = useLocalState(context, 'screen', MECHA_MAINT_PANELS.main);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+
+const StockPartsPanel = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ cell,
+ scanning,
+ capacitor,
+ } = data;
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const AccessPanel = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ idcard_access,
+ operation_req_access,
+ } = data;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {operation_req_access.map((code, i) => (
+
+
+
+
+ {code.name}
+
+
+
+
+
+ ))}
+ {idcard_access.map((code, i) => (
+
+
+
+
+ {code.name}
+
+
+
+
+
+ ))}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/MechStatPane.tsx b/tgui/packages/tgui/interfaces/Mecha/MechStatPane.tsx
new file mode 100644
index 00000000000..4d31f80935d
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/MechStatPane.tsx
@@ -0,0 +1,185 @@
+import { useBackend } from '../../backend';
+import { Stack, Button, Section, Box, ProgressBar, LabeledList } from '../../components';
+import { KelvinZeroCelcius, OperatorData } from './data';
+import { toFixed } from 'common/math';
+
+export const MechStatPane = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ name,
+ integrity,
+ air_source,
+ cabin_pressure,
+ cabin_dangerous_highpressure,
+ cabin_temp,
+ mecha_flags,
+ mechflag_keys,
+ port_connected,
+ } = data;
+ return (
+
+
+ act('changename')}>
+ Rename
+
+ )} />
+
+
+
+
+
+
+
+
+
+
+
+ cabin_dangerous_highpressure?"red":null}>
+ {cabin_pressure} kPa
+
+
+
+
+ {GetTempFormat(cabin_temp)}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const GetTempFormat = (temp) => {
+ return toFixed(temp, 1) +"°K\n"+ toFixed(temp-KelvinZeroCelcius, 1) + "°C";
+};
+
+
+const EnviromentalAir = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ airtank_pressure,
+ airtank_temp,
+ } = data;
+ if (airtank_temp === null) {
+ return (No air tank detected);
+ } else {
+ return (
+ <>
+
+ {airtank_pressure} kPa
+
+
+ {GetTempFormat(airtank_temp)}
+
+ >
+ );
+ }
+};
+
+const DNABody = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ dna_lock,
+ } = data;
+ if (dna_lock === null) {
+ return (
+
+
+
+
+
+ );
+ } else {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+};
+
+const PowerBar = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ power_level,
+ power_max,
+ } = data;
+ if (power_max === null) {
+ return ();
+ } else {
+ return (
+
+ );
+ }
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/OperatorMode.tsx b/tgui/packages/tgui/interfaces/Mecha/OperatorMode.tsx
new file mode 100644
index 00000000000..2bb5a0b164a
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/OperatorMode.tsx
@@ -0,0 +1,89 @@
+import { useBackend } from '../../backend';
+import { ByondUi, Stack, Section } from '../../components';
+import { OperatorData } from './data';
+import { RadioPane } from './RadioPane';
+import { AlertPane } from './AlertPane';
+import { MechStatPane } from './MechStatPane';
+import { ArmorPane } from './ArmorPane';
+import { UtilityModulesPane } from './UtilityModulesPane';
+import { PowerModulesPane } from './PowerModulesPane';
+import { ArmPane } from './ArmPane';
+
+export const OperatorMode = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ left_arm_weapon,
+ right_arm_weapon,
+ mech_view,
+ } = data;
+ return (
+
+
+
+
+
+ {left_arm_weapon ? : null}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {right_arm_weapon ? : null}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/PowerModulesPane.tsx b/tgui/packages/tgui/interfaces/Mecha/PowerModulesPane.tsx
new file mode 100644
index 00000000000..8e4181dc6c7
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/PowerModulesPane.tsx
@@ -0,0 +1,33 @@
+import { useBackend } from '../../backend';
+import { Button, LabeledList } from '../../components';
+import { OperatorData } from './data';
+import { toFixed } from 'common/math';
+
+export const PowerModulesPane = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ mech_equipment,
+ mineral_material_amount,
+ } = data;
+ return (
+
+ {mech_equipment["power"].map((module, i) => (
+
+
+ ))}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/RadioPane.tsx b/tgui/packages/tgui/interfaces/Mecha/RadioPane.tsx
new file mode 100644
index 00000000000..50cfa59b05b
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/RadioPane.tsx
@@ -0,0 +1,46 @@
+import { useBackend } from '../../backend';
+import { Button, NumberInput, LabeledList } from '../../components';
+import { OperatorData } from './data';
+import { toFixed } from 'common/math';
+
+export const RadioPane = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ microphone,
+ speaker,
+ minfreq,
+ maxfreq,
+ frequency,
+ } = data.mech_electronics;
+ return (
+
+
+ act('toggle_microphone')} selected={microphone} icon={microphone ? 'microphone' : 'microphone-slash'}>
+ {(microphone ? "En" : "Dis") + "abled"}
+
+
+
+ act('toggle_speaker')} selected={speaker} icon={speaker ? 'volume-up' : 'volume-mute'}>
+ {(speaker ? "En" : "Dis") + "abled"}
+
+
+
+ toFixed(value, 1)}
+ width="80px"
+ onDrag={(e, value) => act('set_frequency', {
+ new_frequency: value,
+ })} />
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/UtilityModulesPane.tsx b/tgui/packages/tgui/interfaces/Mecha/UtilityModulesPane.tsx
new file mode 100644
index 00000000000..8a3451cbb04
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/UtilityModulesPane.tsx
@@ -0,0 +1,74 @@
+import { useBackend } from '../../backend';
+import { Button, LabeledList } from '../../components';
+import { OperatorData, MechaUtility } from './data';
+
+export const UtilityModulesPane = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ mech_equipment,
+ } = data;
+ return (
+
+ {mech_equipment["utility"].map((module, i) => (
+
+ {module.snowflake.snowflake_id ? (
+ ) : (
+ <>
+ act('equip_act', {
+ ref: module.ref,
+ gear_action: "toggle",
+ })}
+ selected={module.activated} />
+ act('equip_act', {
+ ref: module.ref,
+ gear_action: "detach",
+ })} />
+ >
+ )}
+
+ ))}
+
+ );
+};
+
+const MECHA_SNOWFLAKE_ID_EJECTOR = "ejector_snowflake";
+
+// Handles all the snowflake buttons and whatever
+const Snowflake = (props: {module: MechaUtility}, context) => {
+ const {
+ snowflake,
+ } = props.module;
+ switch (snowflake["snowflake_id"]) {
+ case MECHA_SNOWFLAKE_ID_EJECTOR:
+ return ;
+ default:
+ return null;
+ }
+};
+
+const SnowflakeEjector = (props: {module: MechaUtility}, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ cargo,
+ } = props.module.snowflake;
+ return (
+
+ {cargo.map((item, i) => (
+
+ act('equip_act', {
+ ref: props.module.ref,
+ cargoref: item.ref,
+ gear_action: "eject",
+ })}>
+ {"Eject"}
+
+
+ ))}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Mecha/data.ts b/tgui/packages/tgui/interfaces/Mecha/data.ts
new file mode 100644
index 00000000000..fb47ded5013
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/data.ts
@@ -0,0 +1,93 @@
+export const KelvinZeroCelcius = 273.15;
+
+export const InternalDamageToDamagedDesc = {
+ "MECHA_INT_FIRE": "Internal fire detected",
+ "MECHA_INT_TEMP_CONTROL": "Temperature control inactive",
+ "MECHA_INT_TANK_BREACH": "Air tank breach detected",
+ "MECHA_INT_CONTROL_LOST": "Control module damaged",
+};
+
+export const InternalDamageToNormalDesc = {
+ "MECHA_INT_FIRE": "No internal fires detected",
+ "MECHA_INT_TEMP_CONTROL": "Temperature control active",
+ "MECHA_INT_TANK_BREACH": "Air tank intact",
+ "MECHA_INT_CONTROL_LOST": "Control module active",
+};
+
+export type AccessData = {
+ name: string;
+ number: number;
+}
+
+type MechElectronics = {
+ microphone: boolean;
+ speaker: boolean;
+ frequency: number;
+ minfreq: number;
+ maxfreq: number;
+}
+
+export type MechWeapon = {
+ name: string;
+ desc: string;
+ ref: string;
+ isballisticweapon: boolean;
+ integrity: number;
+ energy_per_use: number;
+ // null when not ballistic weapon
+ disabledreload: boolean | null;
+ projectiles: number | null;
+ max_magazine: number | null;
+ projectiles_cache: number | null;
+ projectiles_cache_max: number | null;
+ ammo_type: string | null;
+ // first entry is always "snowflake_id"=snowflake_id if snowflake
+ snowflake: any;
+}
+
+export type MainData = {
+ isoperator: boolean;
+};
+
+export type MaintData = {
+ name: string;
+ mecha_flags: number;
+ mechflag_keys: string[];
+ internal_tank_valve: number;
+ cell: string;
+ scanning: string;
+ capacitor: string;
+ operation_req_access: AccessData[];
+ idcard_access: AccessData[];
+};
+
+export type OperatorData = {
+ name: string;
+ integrity: number;
+ power_level: number | null;
+ power_max: number | null;
+ mecha_flags: number;
+ internal_damage: number;
+ internal_damage_keys: string[];
+ air_source: string;
+ mechflag_keys: string[];
+ cabin_dangerous_highpressure: number;
+ airtank_pressure: number | null;
+ airtank_temp: number | null;
+ port_connected: boolean | null;
+ cabin_pressure: number;
+ cabin_temp: number;
+ dna_lock: string | null;
+ mech_electronics: MechElectronics;
+ right_arm_weapon: MechWeapon | null;
+ left_arm_weapon: MechWeapon | null;
+ mech_equipment: string[];
+ mech_view: string;
+ mineral_material_amount: number;
+};
+
+export type MechaUtility = {
+ name: string;
+ ref: string;
+ snowflake: any;
+}
diff --git a/tgui/packages/tgui/interfaces/Mecha/index.tsx b/tgui/packages/tgui/interfaces/Mecha/index.tsx
new file mode 100644
index 00000000000..fdd8e9c9f11
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Mecha/index.tsx
@@ -0,0 +1,25 @@
+import { useBackend } from '../../backend';
+import { Window } from '../../layouts';
+import { MainData } from './data';
+import { MaintMode } from './MaintMode';
+import { OperatorMode } from './OperatorMode';
+
+export const Mecha = (props, context) => {
+ const { data } = useBackend(context);
+ if (data.isoperator) {
+ return (
+
+
+
+
+
+ );
+ }
+ return (
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/styles/interfaces/Mecha.scss b/tgui/packages/tgui/styles/interfaces/Mecha.scss
new file mode 100644
index 00000000000..ba910f392fb
--- /dev/null
+++ b/tgui/packages/tgui/styles/interfaces/Mecha.scss
@@ -0,0 +1,43 @@
+@use '../base.scss';
+@use '../colors.scss';
+@use '../functions.scss' as *;
+
+$color-danger: #c92020 !default;
+
+.Mecha__displayBox {
+ background-color: #002003;
+ border: 0.167em inset #E8E4C9;
+ color: #03e017;
+ font-size: 2em;
+ font-family: monospace;
+ padding: 0.25em;
+}
+
+.Mecha__displayBoxRed {
+ background-color: #002003;
+ border: 0.167em inset #E8E4C9;
+ color: #f54b4b;
+ font-size: 2em;
+ font-family: monospace;
+ padding: 0.25em;
+}
+
+.Mecha__Button {
+ outline-width: 0.25rem !important;
+ border-width: 0.65rem !important;
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+}
+
+.Mecha__ButtonDanger {
+ background-color: $color-danger !important;
+ border-color: $color-danger !important;
+ outline-width: 0.25rem !important;
+ border-width: 0.65rem !important;
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+ &:hover {
+ background-color: lighten($color-danger, 15%) !important;
+ border-color: lighten($color-danger, 15%) !important;
+ }
+}
diff --git a/tgui/packages/tgui/styles/main.scss b/tgui/packages/tgui/styles/main.scss
index 6e564433e7f..8e0afb9f8bf 100644
--- a/tgui/packages/tgui/styles/main.scss
+++ b/tgui/packages/tgui/styles/main.scss
@@ -56,6 +56,7 @@
@include meta.load-css('./interfaces/HellishRunes.scss');
@include meta.load-css('./interfaces/Hypertorus.scss');
@include meta.load-css('./interfaces/NuclearBomb.scss');
+@include meta.load-css('./interfaces/Mecha.scss');
@include meta.load-css('./interfaces/Paper.scss');
@include meta.load-css('./interfaces/PreferencesMenu.scss');
@include meta.load-css('./interfaces/Roulette.scss');