From b2cf8866ee947075028fb1065fe443c1d48a1503 Mon Sep 17 00:00:00 2001 From: Gandalf <9026500+Gandalf2k15@users.noreply.github.com> Date: Fri, 1 Apr 2022 01:18:03 +0100 Subject: [PATCH] Upstream merge 65375 (#12455) * Reworks & TGUIs mecha equipment (#65375) TLDR Mech UI now TGUI: https://streamable.com/ahjydy Mechs now use "slots" for equipment They can only mount 2 guns(left and right arm, left and right click to use) Tesla & Concealed bay is removed Removed mech damage deflection Full list of changes Note: weapons in this section refer to all click-using equipment such as guns/hydraulic clamp/etc Hackmd: https://hackmd.io/lgr-LetfSKyHzPP0zQUXPA Tesla has been removed (Tesla gives you effectively infinite power on station and off station(where the design direction for mechs is intended) they are useless) Concealed mech bay has been removed (Concealed mecha bay relied on selection for visibility so it doent make sense to exist when all equips are "selected", the code was bad (instead of flag or something you just used locate() everywhere) Honker no longer has snowflake UI (I'm sorry but if I have to make a third UI for this im going to go insane) Mechs now mount 2 arm weapons, and certain amount of "utility", "armor" and "power" module types The two arm weapons do not share a cooldown anymore UNLESS they are identical weapons left click to shoot left weapon right click for right weapon, this will shoot the weapon unless you click next to you with a ranged weapon it will then try to melee (This also applies to attaching the weapon to the mech) It is no longer possible to deflect or have multipliers for damage from innate or armor sources, armor will now just apply a direct armor change Since plasma generator needed to be selected to use you now need to click on the power generator with a stack of plasma to refill it Internal damage: The mech no longer needs to be low health to take internal damage Internal damage now no longer has several convoluted ways to fix each different type and is now a timed action performed in the UI Weapons no longer have an RNG chance to be damaged or immediately deleted by damage Weapons will now take damage aimed at the right and left arms respectively, this can be repaired using the new UI. NOTE: this is intended to be implemented as weapon/module disabling but I left it out of this PR to try resemble some shortness Both internal and equipment damage have minimum thresholds of damage required in a hit before they attempt to check whether the mech should take internal or equipment damage, teh threshold is lower for equipment damage You can no longer reload weapons using energy Demo Video https://streamable.com/ahjydy * Reworks & TGUIs mecha equipment * Update firefighter.dm Co-authored-by: TiviPlus <57223640+TiviPlus@users.noreply.github.com> Co-authored-by: SkyratBot --- code/__DEFINES/cooldowns.dm | 2 +- code/__DEFINES/mecha.dm | 21 +- code/modules/asset_cache/assets/mecha.dm | 5 + .../simple_animal/hostile/mecha_pilot.dm | 6 +- .../modules/research/designs/mecha_designs.dm | 18 +- code/modules/research/techweb/all_nodes.dm | 1 - code/modules/uplink/uplink_items/job.dm | 10 - code/modules/vehicles/mecha/_mecha.dm | 193 +++++--- code/modules/vehicles/mecha/combat/combat.dm | 6 +- code/modules/vehicles/mecha/combat/durand.dm | 6 +- code/modules/vehicles/mecha/combat/gygax.dm | 32 +- code/modules/vehicles/mecha/combat/honker.dm | 153 +------ .../modules/vehicles/mecha/combat/marauder.dm | 99 ++-- code/modules/vehicles/mecha/combat/phazon.dm | 8 +- .../vehicles/mecha/combat/reticence.dm | 22 +- .../vehicles/mecha/combat/savannah_ivanov.dm | 7 +- .../mecha/equipment/mecha_equipment.dm | 157 ++++--- .../mecha/equipment/tools/medical_tools.dm | 98 ++-- .../mecha/equipment/tools/mining_tools.dm | 7 +- .../mecha/equipment/tools/other_tools.dm | 252 ++++------- .../mecha/equipment/tools/weapon_bay.dm | 14 - .../mecha/equipment/tools/work_tools.dm | 81 ++-- .../mecha/equipment/weapons/weapons.dm | 110 ++--- .../vehicles/mecha/mech_melee_attack.dm | 17 +- code/modules/vehicles/mecha/mecha_actions.dm | 50 +- .../vehicles/mecha/mecha_control_console.dm | 6 +- code/modules/vehicles/mecha/mecha_defense.dm | 200 ++++---- code/modules/vehicles/mecha/mecha_parts.dm | 4 +- code/modules/vehicles/mecha/mecha_topic.dm | 428 ------------------ code/modules/vehicles/mecha/mecha_ui.dm | 319 +++++++++++++ .../vehicles/mecha/medical/odysseus.dm | 2 - code/modules/vehicles/mecha/working/clarke.dm | 30 +- code/modules/vehicles/mecha/working/ripley.dm | 128 +++--- .../modules/vehicles/mecha/working/working.dm | 3 +- icons/ui_icons/mecha/armor.dmi | Bin 0 -> 5855 bytes .../modules/firefighter/code/firefighter.dm | 7 - tgstation.dme | 4 +- .../tgui/interfaces/ExosuitControlConsole.js | 3 - .../tgui/interfaces/Mecha/AlertPane.tsx | 37 ++ .../tgui/interfaces/Mecha/ArmPane.tsx | 261 +++++++++++ .../tgui/interfaces/Mecha/ArmorPane.tsx | 40 ++ .../tgui/interfaces/Mecha/MaintMode.tsx | 258 +++++++++++ .../tgui/interfaces/Mecha/MechStatPane.tsx | 185 ++++++++ .../tgui/interfaces/Mecha/OperatorMode.tsx | 89 ++++ .../interfaces/Mecha/PowerModulesPane.tsx | 33 ++ .../tgui/interfaces/Mecha/RadioPane.tsx | 46 ++ .../interfaces/Mecha/UtilityModulesPane.tsx | 74 +++ tgui/packages/tgui/interfaces/Mecha/data.ts | 93 ++++ tgui/packages/tgui/interfaces/Mecha/index.tsx | 25 + .../tgui/styles/interfaces/Mecha.scss | 43 ++ tgui/packages/tgui/styles/main.scss | 1 + 51 files changed, 2287 insertions(+), 1407 deletions(-) create mode 100644 code/modules/asset_cache/assets/mecha.dm delete mode 100644 code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm delete mode 100644 code/modules/vehicles/mecha/mecha_topic.dm create mode 100644 code/modules/vehicles/mecha/mecha_ui.dm create mode 100644 icons/ui_icons/mecha/armor.dmi create mode 100644 tgui/packages/tgui/interfaces/Mecha/AlertPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/ArmPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/ArmorPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/MaintMode.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/MechStatPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/OperatorMode.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/PowerModulesPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/RadioPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/UtilityModulesPane.tsx create mode 100644 tgui/packages/tgui/interfaces/Mecha/data.ts create mode 100644 tgui/packages/tgui/interfaces/Mecha/index.tsx create mode 100644 tgui/packages/tgui/styles/interfaces/Mecha.scss 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 = {"
-
Sounds of HONK:
- -
- "} - 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 - . = {" -
-
Honk-ON-Systems
- -
"} - /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()] -
-
- [get_equipment_menu()] -
- - "} - -//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() - . = {" -
-
Electronics
- -
-
-
Permissions & Logging
- -
"} - - -/obj/vehicle/sealed/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu - . = {" -
-
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 0000000000000000000000000000000000000000..665e3f665ebdc7e274abb372478cd23b5d7d08ef GIT binary patch literal 5855 zcmZXYbyU>P7x$Nyl8};+mM%d`0hN*z1Vp-a3F%sw5|)sZr5lunMS3Y|7Nom7rMqkC zXTN_uzw?~){4q1?NdWJg$uTK4BKkKkLHe28Ym9j5SJMlNiRSXc}JliiXXDdf1XKKXh z=>N+sH27?d!%V13^$WE%G@(%aQ6Dmt6JuvO8Y z*9__n`C-HCpp}g;6OR3n*&-PtnXJ08chj||YRMs-f{crn&hU*Dw#tBBy#02P>fU_w z&MItwu10uznqRw;a&w)9nS($+URfDOBeI1pSA^wU`@INQ?35i>1spM&P9a^Vquntf>--MfcNFi)y-p>+Ec$4t^Fz$$cuvN9 z94i9QBc8H-O;OOd`#O~!NpZb^XkC1{#Ofi7%IE}#4p=1RD!wqsE`DG(^HZFh8EomA zp(riw+`^U1)a;vhk|k=!dLzbLN2e_ba-eL*ek@^U^YGF3eKV16d0Hrp_(#hQqDU@( zrwzZ3OD-0mV#1$zOJ5xHEtzj4yma~U`p9Ma*iGVimVr4SL&btxvzUadlX9ZfQ)KK= zh(;{#YE=8bC{~k#zc42e$|b(!(jz=Aqgpe2K@(~wvgKCdoWFqemQ!s-e7R-JR1sH; ztwM#_$MorU(f1Q0gSaRcvT3)1pALm~-2Mr`ucTmJ9%f%7n{E^y;ew>pMO#Vjtc0{b zHfO9sO>C26J`uqn2TF))+GIOFM)U29Orn<93>BYm-1@In^1S=-jU5Fpq708+Qn96F z!$?mKp0T)(ZSPIZbm}Sq=W--;0le5W{dF^I5${M;Ow>5;Mi@*QC~lT>(DeLl*nShj z38@pma|EndK{k(zKg~jK3r*8V`DCTBsEqEnWwtfMAc1tQD$ zTE7WK6*;FQFF3CJTm3aw@0bT;XD{>I=J|w}229&`;Do39jAWAhJ`Xe#(GYS4&TLWv zr?t3WjjJR%%ET3uy+XN1^8My=&yeQTtFv z$NE>{8YnjOjbbkBP8I!ut4zUW=u>XJ@{KxQJ-Rjijaa+}bN8uKB6`?G4RJCi6K#$NnV2Ilx}wlFVt>&CKn!8tu}9-_Foy zc(|-m2r^Ljq$t?+tesRou6Jx_T0>zZ7m`KOmRFxXbO!T05zW#bogXKkb%bpKKI;sS zI20B35|&^YzzIFpe-OrvOmEWLx!r}f4V2g~9dleRJOIvpom!Ti1rNO44ZJ@jAbk{L zytFn6u>Q1WzO3I_F?|NLaYUFdZGZK;Dqapq=cdrf`*k@Ihm>0xEwi70tBT9Y zkwZ3A@L8|l(&u{lLB2}g^PZAyZmIdk3ubjZu*ZM#d!j}Q4c`TOA#!l_zWc58tcD=itkPa=xZ`^i~6Fp0t9EwN#c)J z6%CHuFHbZzg$Qy+TGJlBaeiA;_64L7fdm=)^Xd}`xP&(?Nw^`zBAEB_a?_F(d;QhK zACZ|=e^_Yv)dxi*0Q@=H>h|w10aL~lN^CSM|nMDvp&m)mq)E*LwO7#HcIWfOn9d%Z9-V$iMR8n39gfbm^bObwfMPc zLh9@vF9pPA>jXRKWH=lN?HbrTX>g@ry|C)*o~@XBxGV_ozzMyA(@agO=!Q!3E8?H@ zsR*Mye1EtVCqcV_(XP8SShWRK56gSt@0$}K6ulo^GsArI>0~U){Ww9lZx!Jd)~Ygu(lq4o=Y9pgxKgp;mZ&>}M3X?(C28m3{w? zYEi~rmK2JGUKLZrfiYirdBk!QBSNFURAOqWG;_t%f_pZT2Gy(4wmQJZz^{Pkdji~u zH3TsOO~q5k+GP%^rLUYd^B3=#xrCZVm_S)H#a3)P)Ww-jQXv zH$4q65y2bNxN9ByZh~i6WlaXCfgMKvaC@_~1*sA-M_Rkw+*aM+y&IR#>|-1MG*T{~ z2is=n_nX=0NJn2)+RxPmOitSYwM5n#;mk*=*+U5$fYDGT= zWK{*ekR_f$&{8-M+U!=XyjHS%3IER@DV|) zs1vzOXzOAPFD^bgllU1de!2u~HLDc6D$@eL=91UA^0y{|jbwq^2(Oz3Ma@=~P= z6TtC*?-1As#G3SvsW*16Z8LZ&lw3k}0#~ph;Vza!rTbnX$tX#dY49O7)5d#N3KOav z>inBUP~^&lp$~02NDxOc=4af5ER=O>;lwIzgc19yxuIj?kx~puw(8(EQj$5 zWX`Tw^*GcV&1`adT)H=O-(U7!SB<6a6@c#3y-@Bsj%xn}AdOKdfW+HMfx`rRT25NU z<>s!{qSN)xANzkvlW=eLjvKW-;P2xc1UnF>m=lnA!%+W5Uj$?}QT=*gX4Dl}7EzEM zdrZ;ZBTM(Ovv2xgBdHnaX!xoWW4n#S}gf2$Z5YK1ps`fM9UE25GZ!H_qia2_j+$yl3 zemXYCkdSx}ZW!7o`%Y14nMiz(Orq-n85J02-~xZcjKg1AeM#jc+*HBp#ZsL-JE*gI z)LP5Ui3R#uD|wX}=M}YY-dlJjf`aQlgd@1f4QhQzMb%DjB>qCKjttXt^vn7-& zzzU@B(-0b>JI5R7(NPqisb%C0Q()m7OSLO5BHW@I+YTjt{mw`pMip!gu}QA5m5eA_ z1ouy~#7{|?z8`Xca!Jfq%?9mV_3+XV=T)Wgr3%O^*+im`KwFO@=$<3Q89~SG2vdwF zn6%3^T?0?3b)P6>EM0+Kk1*g*!V#+$WUvx%Xbv{b%|wcgt3p^w_9nR~pBp{ybtF%Y zc?ARo06>9%llDrCDX%g=yxoMCvW{hn>o<4) z<$jSUq*w5)bLzXG|7E(=OYjsUPqI!!^ku9)-C)uuf@KOnEnxvC@y}Th)}SMqGB9&0 zGAn&`lx~PmkG$M_YNH#kvF%ET<(PGpTCZ`$G<#YlEG?T?UkbJ^3UIp~3`4*5bjeS1 zhoq)pHJJ(EuX5D3V5J<1&L8*tv(MM;F}m#$3~o;zI&6(`U@|#O6o2#X_u!7i?ft*Y zK(nZg^o+az)Rd->P)Msiov(%TlGE$_;r4TMocc(W6O()nfw)^^j(USLDqPkXKl5h1 z1@%$Lb6iO)oN8ZVj(^;nwr7sJEf#Mz6=TMwS-LHjRys#PxPQ!@YfF!|I_Yv=1? zv9(Qk6)ob|(MVstbgei_-klO?QXR>cRiI27u5tpYLS)!LaLivCpk`^m-|9;OW^y&+{@bUIRk=>pu}-z74|+%^ z0=13wWSf`j3l}DP&FlrP_@iLYu!!>M?r4A}4Q-ijc)065*&c$rXZK_4Mx;g}y>{-* z&%tsF`QGU~AOq2$4GT;mQ3YE|=zH`daL%9tzXqb1jM6oX%F&tt9{KdoO4ZN*LRZ$9 zVG+w%L!oiZGD_7!%@WKEsNjIO2{q)hhnHbS@@^Lizty@Fxq$xDFywID!h|{J9`a_b z_`%f!+R)bNeQ-*A$mvC0Or$|IYy4UApjM;8OljJqek$W%08Xa}$6{ z+#92$QAiU!ipd;|2KRiX;Z(`w_+`9(`rJ5$#e`uxE8lJ8{7V?#HxV1Dd0L|!MfiDT zJn9gyFA$lvV)17z;P7Cg9kE^)8&TIv7KQxbS>|VE^gPD6wE9VX>!gR|-0=FvitVm6 zO9K!t=(a$ba_n0FpU1>ecW0)N42M5Rb$JAng748gr;(FQg{P2zCU(o+|B4Fn@E@C( zrP~q_2RsY-)9kBZm<-(~V*fp~FG!zq;wo{1+1pO`^Sd}69@(4@IpuMWttg}1bCeB^`bz^SiSHzRH_oJoH1MC455tR z>DMy~MekHzC?UF`2cOdZ;QLrg!CYEQu<7@eib7iQ$y$8G(5isg*$?c;D_fpN3HGX! zC%>r0eJ|K(ggLjN&CY!d^C<9RcLyIy7sE!^9)>KPn4IyELtheMyhcP3+#N!V9?3a*Ct1{XL~2QW*Wl=S?t< z`F%`vt>!xKGBk#Rz3i#=Q9~2G9b7Hsi7)-bk$H(v!QT=K0p)Q?va=OlBa5WehLq9; z0ilXwu@b0F%C&jd8$I{j$bpivu>;*g82eK_Ox_A*3u1;3_FbG|56f~PM0BZQ=z>@6 zj=DjbaeF(qcQWdzyyBngJ(EtRzQTIl$L)knY_3Kgo-DA)Pf)%Wp|okON`Wru4?8^v z7<%xL>_nnv|GF`t+MR@GcMf5BIymVDs9{-iJx&Z$#@jxjOyB&8UITJSK7%PHom%4& zI?eZ@0=lM+g?X31Mb^|D-xc^0f5hpiXP}DUu?XH4P!8pzKwTRjzoI1`{Z#UyTt*t= z-1868cJS%-3+eNQCM9d#z{b)KYk7>}Y~Qu6XuUy8mjQuYMs}5*(ZZ8T9cUIyr^3U_ zSrwI{0xuEi^Sj{M@wRVr-09FY0FIR@x|RZT z@LwiFD|_g?7NeoU$c50mqfam1GXZq0V&UD`o+pUVy$(f`>}3Dkw7BIHOc+-azExkl zoVs!o`~i1Yy-HxxUa-{vDATr0)Ij~b$sSXUZRM?!HJR*Uni{#bI`-9y&G+tPoj|G-rGczv~lO^thSvu&T3xCtV3ou6rH+hq(MN zo~W_?ab)*e056bJ$OxcX@o=^|z<56ejIr~wtnPOHKe#3iR_87Fzhn(RasU4TYoU`1 zlEz|mXbhR7{U6&?V)p0d!!KJ~H|rVtYml6DT*%^sBvB7xaQaPwT*w*-!<0y+a>+~@ zT`j`h5!L2C@ITcJJ88`B7!X!CnBf6g;Kb8qS)+V@0*D)s)v2aD71s%8?N2UdC58KI z#1A`U&uuCe@@Q%wd#R0h_l6u2k{I(xy)wq~3-pV&FJgRS`Y@R|bilw<)2apGI1$YR z5-R3YZDMPbYHLIOkQ$Lp3%x}ceyEfGc7;hPf&k>qyA190UT;!YP!w$*ixl{?5KYYGfvb>{JU?z5Y{%{9#<48!P SV8IY;fU>-rT&XPB|Nj868j2hM literal 0 HcmV?d00001 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} + + + + + + + + + + )} + + {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} + + + + + + + )} /> + + +
+ + + + + + + + +
+
+ +
+ + + + + + 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) => ( + + + + + + + + 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 ? ( + ) : ( + <> + + + ))} + + ); +}; 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');