diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 1b77cee4f3ca..46d0e60bfd38 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -40,10 +40,12 @@ #define AI_DETECT_HUD "19" #define NANITE_HUD "20" #define DIAG_NANITE_FULL_HUD "21" +/// Shows mech overheating status. +#define DIAG_OVERHEAT_HUD "22" /// Displays launchpads' targeting reticle -#define DIAG_LAUNCHPAD_HUD "22" +#define DIAG_LAUNCHPAD_HUD "23" //for antag huds. these are used at the /mob level -#define ANTAG_HUD "23" +#define ANTAG_HUD "24" //by default everything in the hud_list of an atom is an image //a value in hud_list with one of these will change that behavior diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm new file mode 100644 index 000000000000..a550cefde276 --- /dev/null +++ b/code/__DEFINES/mecha.dm @@ -0,0 +1,36 @@ +#define MECHA_INT_FIRE (1<<0) +#define MECHA_INT_TEMP_CONTROL (1<<1) +#define MECHA_INT_SHORT_CIRCUIT (1<<2) +#define MECHA_INT_TANK_BREACH (1<<3) +#define MECHA_INT_CONTROL_LOST (1<<4) + +#define MECHA_MELEE (1<<0) +#define MECHA_RANGED (1<<1) + +#define FRONT_ARMOUR 1 +#define SIDE_ARMOUR 2 +#define BACK_ARMOUR 3 + +#define MECHA_MAX_COOLDOWN 30 // Prevents long cooldown equipment from messing up combat + +/// Minimum overheat to show an alert to the pilot +#define OVERHEAT_WARNING 50 +/// Minimum overheat required to cause slowdown +#define OVERHEAT_THRESHOLD 100 +/// Maximum overheat caused by EMPs, prevents permanent lockdown from ion rifles +#define OVERHEAT_EMP_MAX 130 +/// Maximum overheat level possible, causes total immobilization +#define OVERHEAT_MAXIMUM 150 +/// Amount of overheat reduced every process +#define PASSIVE_COOLING -5 +/// Amount of cooling per decisecond-tick while stationary +#define STATIONARY_COOLING -0.1 +/// Maximum cooling per second-tick from being stationary +#define STATIONARY_COOLING_MAXIMUM -10 +/// Maximum heating from being in a hot environment +#define ENVIRONMENT_HEATING 5 +/// Overheating per tile moved when overload is active +#define OVERLOAD_HEAT_COST 4 + +/// This trait is caused by overheating +#define OVERHEAT_TRAIT "overheating" diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index 2dbc9b7c68b8..1f0b590dd81f 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -7,4 +7,5 @@ // Penetration flags #define PENETRATE_OBJECTS (1<<0) -#define PENETRATE_MOBS (1<<1) +#define PENETRATE_WALLS (1<<1) +#define PENETRATE_MOBS (1<<2) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index c3d3041fd96d..fb6fa18f8cee 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -200,6 +200,7 @@ #define FIRE_PRIORITY_FIELDS 30 #define FIRE_PRIORITY_SMOOTHING 35 #define FIRE_PRIORITY_OBJ 40 +#define FIRE_PRIORITY_MECHA 40 #define FIRE_PRIORITY_ACID 40 #define FIRE_PRIORITY_BURNING 40 #define FIRE_PRIORITY_DEFAULT 50 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 107455de8b98..4b79292ae06e 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -129,4 +129,4 @@ * * THAT FILE IS FOUND INSIDE THE TRAITS FOLDER */ -///////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index c7c76c1fb03a..b26926922814 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -52,6 +52,8 @@ #define TRAIT_ALIEN_SNEAK "sneaking_alien" ///This mob can't use vehicles #define TRAIT_NOVEHICLE "no_vehicle" +/// This mech is fully disabled +#define TRAIT_MECH_DISABLED "mech_disabled" /// You can't see color! #define TRAIT_COLORBLIND "color_blind" /// This person is crying diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index fae9bfd3cfa2..69f694fac8cd 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -605,6 +605,11 @@ so as to remain in compliance with the most up-to-date laws." desc = "Mech integrity is low." icon_state = "low_mech_integrity" +/atom/movable/screen/alert/overheating + name = "Mech Overheating" + desc = "Mech internal temperature is high." + icon_state = "overheat" + //GHOSTS //TODO: expand this system to replace the pollCandidates/CheckAntagonist/"choose quickly"/etc Yes/No messages diff --git a/code/controllers/subsystem/processing/mecha.dm b/code/controllers/subsystem/processing/mecha.dm new file mode 100644 index 000000000000..460cebc43bf3 --- /dev/null +++ b/code/controllers/subsystem/processing/mecha.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(mecha) + name = "Mecha" + priority = FIRE_PRIORITY_MECHA + flags = SS_NO_INIT + wait = 0.5 SECONDS diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 4f0f1c4f0cee..2c9c02be775e 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -402,8 +402,7 @@ * We then return the protection value */ /atom/proc/emp_act(severity) - SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity) - var/protection = NONE + var/protection = SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity) if(HAS_TRAIT(src, TRAIT_EMPPROOF_CONTENTS)) protection |= EMP_PROTECT_CONTENTS if(HAS_TRAIT(src, TRAIT_EMPPROOF_SELF)) diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index ea09bab0bf20..45b6908f48f9 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -56,11 +56,11 @@ /datum/atom_hud/data/diagnostic/basic hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, \ - DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD) + DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD, DIAG_OVERHEAT_HUD) /datum/atom_hud/data/diagnostic/advanced - hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, - DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD, DIAG_PATH_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD) + hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, \ + DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD, DIAG_PATH_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD, DIAG_OVERHEAT_HUD) /datum/atom_hud/data/bot_path // This hud exists so the bot can see itself, that's all @@ -388,6 +388,13 @@ Diagnostic HUDs! holder.icon_state = "hudnobatt" set_hud_image_active(DIAG_BATT_HUD) +/obj/mecha/proc/diag_hud_set_mechoverheat() + var/image/holder = hud_list[DIAG_OVERHEAT_HUD] + var/icon/I = icon(icon, icon_state, dir) + holder.pixel_y = I.Height() - world.icon_size + holder.icon_state = "overheat[round(10 * overheat / OVERHEAT_MAXIMUM)]" + set_hud_image_active(DIAG_OVERHEAT_HUD) + /obj/mecha/proc/diag_hud_set_mechstat() var/image/holder = hud_list[DIAG_STAT_HUD] var/icon/I = icon(icon, icon_state, dir) @@ -396,6 +403,10 @@ Diagnostic HUDs! holder.icon_state = "hudwarn" set_hud_image_active(DIAG_STAT_HUD) return + else if(HAS_TRAIT(src, TRAIT_MECH_DISABLED)) + holder.icon_state = "hudoffline" + set_hud_image_inactive(DIAG_STAT_HUD) + return holder.icon_state = null set_hud_image_inactive(DIAG_STAT_HUD) diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index ef60dead2106..981ef9aeefd3 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -1,5 +1,6 @@ /obj/mecha/combat force = 25 + punch_heat_cost = 4 // stronger mechs generate more heat from punching internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY) internal_damage_threshold = 50 armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 0, BOMB = 20, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) @@ -11,8 +12,7 @@ /obj/mecha/combat/restore_equipment() mouse_pointer = 'icons/mecha/mecha_mouse.dmi' - . = ..() - + return ..() /obj/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) diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm index b2f905d802de..8e19412ba79a 100644 --- a/code/game/mecha/combat/durand.dm +++ b/code/game/mecha/combat/durand.dm @@ -13,10 +13,10 @@ force = 35 /obj/mecha/combat/durand/GrantActions(mob/living/user, human_occupant = 0) - ..() + . = ..() defence_action.Grant(user, src) /obj/mecha/combat/durand/RemoveActions(mob/living/user, human_occupant = 0) - ..() + . = ..() defence_action.Remove(user) diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index 97732c662c34..26bbaa2c30d0 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -21,7 +21,6 @@ deflect_chance = 15 armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 0, BOMB = 20, BIO = 100, RAD = 100, FIRE = 100, ACID = 100) max_temperature = 35000 - leg_overload_coeff = 100 operation_req_access = list(ACCESS_SYNDICATE) internals_req_access = list(ACCESS_SYNDICATE) max_equip = 7 diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index 288503706645..feca43536c94 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -36,7 +36,7 @@ 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 = new /obj/item/mecha_parts/mecha_equipment/armor/ranged(src) ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) @@ -68,7 +68,7 @@ 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 = new /obj/item/mecha_parts/mecha_equipment/armor/ranged(src) ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) @@ -95,7 +95,7 @@ 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 = new /obj/item/mecha_parts/mecha_equipment/armor/ranged(src) ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/melee_weapon/sword/energy_axe(src) //NOT BECAUSE IT'S USEFUL, BUT BECAUSE IT'S AWESOME ME.attach(src) diff --git a/code/game/mecha/combat/sidewinder.dm b/code/game/mecha/combat/sidewinder.dm index 249e103f7bd7..197f52e4a6dd 100644 --- a/code/game/mecha/combat/sidewinder.dm +++ b/code/game/mecha/combat/sidewinder.dm @@ -27,7 +27,7 @@ return if(user.incapacitated()) //Pilot can't move return - if(completely_disabled || is_currently_ejecting) //mech can't move + if(HAS_TRAIT(src, TRAIT_MECH_DISABLED) || is_currently_ejecting) //mech can't move return if(state) //Maintenance mode, can't move occupant_message(span_warning("Maintenance protocols in effect.")) @@ -67,6 +67,6 @@ ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/melee_weapon/sword/rapier/razerfang //Not a snake without fangs right? ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster + ME = new /obj/item/mecha_parts/mecha_equipment/armor/ranged ME.attach(src) max_ammo() diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 99f1d4c03a3a..0abe59dbd850 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -15,6 +15,10 @@ var/equip_ready = TRUE /// How much energy it drains when used or while in use var/energy_drain = 0 + /// How much this heats the mech when used + var/heat_cost = 0 + /// Whether this equipment should process along with its chassis + var/active = FALSE /// Linked Mech/Chassis var/obj/mecha/chassis = null /// Bitflag: MECHA_MELEE|MECHA_RANGED what ranges it operates at @@ -114,6 +118,8 @@ return FALSE if(energy_drain && !chassis.has_charge(energy_drain)) return FALSE + if(HAS_TRAIT(src, TRAIT_MECH_DISABLED)) + return FALSE if(chassis.is_currently_ejecting) return FALSE if(chassis.equipment_disabled) @@ -127,32 +133,45 @@ return FALSE return TRUE +/obj/item/mecha_parts/mecha_equipment/proc/on_process(delta_time) + return PROCESS_KILL + /obj/item/mecha_parts/mecha_equipment/proc/action(atom/target, mob/living/user, params) return 0 /obj/item/mecha_parts/mecha_equipment/proc/start_cooldown() + if(equip_ready) + chassis.use_power(energy_drain) + chassis.adjust_overheat(heat_cost) set_ready_state(0) - chassis.use_power(energy_drain) - addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), equip_cooldown * check_eva()) + addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), equip_cooldown * check_eva(), TIMER_UNIQUE|TIMER_OVERRIDE) /obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target) if(!chassis) + return FALSE + set_ready_state(FALSE) + . = do_after(chassis.occupant, equip_cooldown * check_eva(), target, extra_checks = CALLBACK(src, PROC_REF(do_after_checks), target, chassis.loc)) + set_ready_state(TRUE) + if(!.) return - var/C = chassis.loc - set_ready_state(0) chassis.use_power(energy_drain) - . = do_after(chassis.occupant, equip_cooldown * check_eva(), target) - set_ready_state(1) - if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) - return 0 + chassis.adjust_overheat(heat_cost) /obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, delay) if(!chassis) return - var/C = chassis.loc - . = do_after(chassis.occupant, delay, target) - if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) - return 0 + return do_after(chassis.occupant, delay * check_eva(), target, extra_checks = CALLBACK(src, PROC_REF(do_after_checks), target, chassis.loc)) + +/obj/item/mecha_parts/mecha_equipment/proc/do_after_checks(atom/target, atom/old_loc) + if(!chassis) + return FALSE + if(chassis.loc != old_loc || chassis.inertia_dir) + return FALSE + if(src != chassis.selected) + return FALSE + if(!(chassis.omnidirectional_attacks || (get_dir(chassis, target) & chassis.dir))) + return FALSE + return TRUE /obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M) if(M.equipment.len 0) - M.adjustOxyLoss(-1) - M.AdjustStun(-80) - M.AdjustKnockdown(-80) - M.AdjustParalyzed(-80) - M.AdjustImmobilized(-80) - M.AdjustUnconscious(-80) - if(M.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) < 5) - M.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5) + M.adjustOxyLoss(-0.5 * delta_time) + M.AdjustStun(-40 * delta_time) + M.AdjustKnockdown(-40 * delta_time) + M.AdjustParalyzed(-40 * delta_time) + M.AdjustImmobilized(-40 * delta_time) + M.AdjustUnconscious(-40 * delta_time) + var/existing_epi = M.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) + if(existing_epi < 5) + M.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5 - existing_epi) chassis.use_power(energy_drain) update_equip_info() @@ -368,7 +346,7 @@ m++ if(processed_reagents.len) message += " added to production" - START_PROCESSING(SSobj, src) + active = TRUE occupant_message(message) occupant_message("Reagent processing started.") log_message("Reagent processing started.", LOG_MECHA) @@ -502,18 +480,15 @@ return -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/process() - if(..()) - return +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/on_process(delta_time) if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(energy_drain)) occupant_message("Reagent processing stopped.") log_message("Reagent processing stopped.", LOG_MECHA) - STOP_PROCESSING(SSobj, src) - return - var/amount = synth_speed / processed_reagents.len + return PROCESS_KILL + var/amount = synth_speed * delta_time / processed_reagents.len for(var/reagent in processed_reagents) - reagents.add_reagent(reagent,amount) - chassis.use_power(energy_drain) + reagents.add_reagent(reagent, amount) + chassis.use_power(energy_drain * delta_time) ///////////////////////////////// Medical Beam /////////////////////////////////////////////////////////////// @@ -522,6 +497,7 @@ desc = "Equipment for medical exosuits. Generates a focused beam of medical nanites." icon_state = "mecha_medigun" energy_drain = 10 + heat_cost = 4 range = MECHA_MELEE|MECHA_RANGED equip_cooldown = 0 var/obj/item/gun/medbeam/mech/medigun @@ -531,25 +507,38 @@ . = ..() medigun = new(src) -/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/can_attach(obj/mecha/M) - . = ..() - if(locate(/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam) in M.equipment) - return FALSE - /obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/Destroy() qdel(medigun) return ..() -/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/process() - if(..()) - return - medigun.process() +/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/start_cooldown() + set_ready_state(0) + addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), equip_cooldown * check_eva()) + +/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/action_checks(atom/target) + if(!chassis) + return FALSE + if(HAS_TRAIT(src, TRAIT_MECH_DISABLED)) + return FALSE + return TRUE + +/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/on_process(delta_time) + if(!action_checks()) + medigun.LoseTarget() + return PROCESS_KILL + medigun.process(delta_time) + if(!medigun.current_target) + return PROCESS_KILL + chassis.adjust_overheat(heat_cost * delta_time) /obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/action(atom/target) - medigun.process_fire(target, loc) - + if(!action_checks()) + return FALSE + if(!medigun.process_fire(target, loc)) + return FALSE + active = TRUE + return TRUE /obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/detach() - STOP_PROCESSING(SSobj, src) medigun.LoseTarget() return ..() diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index 0a2199aaf96b..a458b459ae90 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -155,6 +155,7 @@ icon_state = "mecha_analyzer" selectable = 0 equip_cooldown = 15 + active = FALSE // this one's handled manually var/scanning_time = 0 /obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize(mapload) diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 6afacfe22572..40d3d2361fdc 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -180,43 +180,6 @@ if(get_dist(chassis, locked) > 7) set_target(null) -//////////////////////////// ARMOR BOOSTER MODULES ////////////////////////////////////////////////////////// - - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants. - name = "armor booster module (Close Combat Weaponry)" - desc = "Boosts exosuit armor against armed melee attacks. Requires energy to operate." - icon_state = "mecha_abooster_ccw" - equip_cooldown = 10 - energy_drain = 50 - range = 0 - var/deflect_coeff = 1.15 - var/damage_coeff = 0.8 - selectable = 0 - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/attack_react() - if(action_checks(src)) - start_cooldown() - return 1 - - - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster - name = "armor booster module (Ranged Weaponry)" - desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots. Requires energy to operate." - 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(action_checks(src)) - start_cooldown() - return 1 - ////////////////////////////////// REPAIR DROID ////////////////////////////////////////////////// @@ -225,16 +188,16 @@ name = "exosuit repair droid" desc = "An automated repair droid for exosuits. Scans for damage and repairs it. Can fix almost all types of external or internal damage." icon_state = "repair_droid" - energy_drain = 50 + energy_drain = 25 + heat_cost = 5 range = 0 - var/health_boost = 1 + var/health_boost = 2 var/icon/droid_overlay var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH) equip_actions = list(/datum/action/innate/mecha/equipment/toggle_repair) selectable = 0 /obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy() - STOP_PROCESSING(SSobj, src) if(chassis) chassis.cut_overlay(droid_overlay) return ..() @@ -247,23 +210,19 @@ /obj/item/mecha_parts/mecha_equipment/repair_droid/detach() chassis.cut_overlay(droid_overlay) - if(!equip_ready) - STOP_PROCESSING(SSobj, src) UnregisterSignal(chassis, COMSIG_ATOM_UPDATE_OVERLAYS) return ..() /obj/item/mecha_parts/mecha_equipment/repair_droid/proc/update_chassis_overlays(atom/source, list/overlays) overlays += droid_overlay -/obj/item/mecha_parts/mecha_equipment/repair_droid/process() +/obj/item/mecha_parts/mecha_equipment/repair_droid/on_process(delta_time) if(!chassis || chassis.wrecked) - STOP_PROCESSING(SSobj, src) - set_ready_state(1) - return - var/h_boost = health_boost + return PROCESS_KILL + var/h_boost = health_boost * delta_time var/repaired = FALSE if(chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT) - h_boost *= -2 + h_boost *= -1 else if(chassis.internal_damage && prob(15)) for(var/int_dam_flag in repairable_damage) if(chassis.internal_damage & int_dam_flag) @@ -274,13 +233,13 @@ chassis.take_damage(-h_boost) repaired = TRUE if(chassis.get_integrity() < chassis.max_integrity && h_boost > 0) - chassis.update_integrity(chassis.get_integrity() + min(h_boost, chassis.max_integrity-chassis.get_integrity())) + chassis.repair_damage(h_boost) repaired = TRUE if(repaired) - if(!chassis.use_power(energy_drain)) - STOP_PROCESSING(SSobj, src) - set_ready_state(1) + chassis.adjust_overheat(heat_cost * delta_time) + if(!chassis.use_power(energy_drain * delta_time)) chassis.update_appearance(UPDATE_OVERLAYS) + return PROCESS_KILL /datum/action/innate/mecha/equipment/toggle_repair name = "Toggle Repairs" @@ -288,18 +247,16 @@ /datum/action/innate/mecha/equipment/toggle_repair/Activate() var/obj/item/mecha_parts/mecha_equipment/repair_droid/repair_droid = equipment - if(repair_droid.equip_ready) - START_PROCESSING(SSobj, repair_droid) - repair_droid.log_message("Activated.", LOG_MECHA) - else - STOP_PROCESSING(SSobj, repair_droid) - repair_droid.log_message("Deactivated.", LOG_MECHA) - repair_droid.droid_overlay = new(repair_droid.icon, icon_state = "repair_droid[repair_droid.equip_ready ? "_a" : ""]") - button_icon_state = "mech_repair_[repair_droid.equip_ready ? "on" : "off"]" - repair_droid.set_ready_state(!repair_droid.equip_ready) + repair_droid.active = !repair_droid.active + repair_droid.log_message(repair_droid.active ? "Activated." : "Deactivated.", LOG_MECHA) + repair_droid.droid_overlay = new(repair_droid.icon, icon_state = "repair_droid[repair_droid.active ? "_a" : ""]") chassis.update_appearance(UPDATE_OVERLAYS) build_all_button_icons() +/datum/action/innate/mecha/equipment/toggle_repair/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force) + button_icon_state = "mech_repair_[equipment.active ? "on" : "off"]" + return ..() + /////////////////////////////////// TESLA ENERGY RELAY //////////////////////////////////////////////// /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay @@ -312,14 +269,9 @@ var/list/use_channels = list(AREA_USAGE_EQUIP,AREA_USAGE_ENVIRON,AREA_USAGE_LIGHT) selectable = 0 -/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 + active = FALSE + return ..() /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_charge() if(equip_ready) //disabled @@ -342,14 +294,8 @@ /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list) ..() if(href_list["toggle_relay"]) - if(equip_ready) //inactive - START_PROCESSING(SSobj, src) - set_ready_state(0) - log_message("Activated.", LOG_MECHA) - else - STOP_PROCESSING(SSobj, src) - set_ready_state(1) - log_message("Deactivated.", LOG_MECHA) + active = !active + log_message(active ? "Activated." : "Deactivated.", LOG_MECHA) /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info() if(!chassis) @@ -357,17 +303,13 @@ return "*  [src.name] - [equip_ready?"A":"Dea"]ctivate" -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/process() +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/on_process(delta_time) if(!chassis || chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT) - STOP_PROCESSING(SSobj, src) - set_ready_state(1) - return + return PROCESS_KILL var/cur_charge = chassis.get_charge() if(isnull(cur_charge) || !chassis.cell) - STOP_PROCESSING(SSobj, src) - set_ready_state(1) occupant_message("No powercell detected.") - return + return PROCESS_KILL if(cur_charge < chassis.cell.maxcharge) var/area/A = get_area(chassis) if(A) @@ -377,7 +319,7 @@ pow_chan = c break if(pow_chan) - var/delta = min(20, chassis.cell.maxcharge-cur_charge) + var/delta = min(20, chassis.cell.maxcharge-cur_charge) * delta_time chassis.give_power(delta) A.use_power(delta*coeff, pow_chan) diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index 637c7adf90e1..38cc9eecbf43 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -362,8 +362,6 @@ selectable = FALSE /// Scanning distance var/distance = 6 - /// Whether the scanning is enabled - var/scanning = FALSE /// Stored t-ray scan images var/list/t_ray_images @@ -373,11 +371,11 @@ /obj/item/mecha_parts/mecha_equipment/t_scanner/detach(atom/moveto) UnregisterSignal(chassis, COMSIG_MOVABLE_MOVED) - if(scanning) - STOP_PROCESSING(SSobj, src) + update_scan(chassis.occupant, TRUE) + active = FALSE return ..() -/obj/item/mecha_parts/mecha_equipment/t_scanner/process(delta_time) +/obj/item/mecha_parts/mecha_equipment/t_scanner/on_process(delta_time) if(!update_scan(chassis.occupant)) return PROCESS_KILL @@ -391,7 +389,7 @@ if(t_ray_images?.len) pilot.client.images.Remove(t_ray_images) QDEL_NULL(t_ray_images) - if(!scanning || force_remove) + if(!active || force_remove) return FALSE t_ray_images = list() @@ -423,15 +421,11 @@ /datum/action/innate/mecha/equipment/t_scanner/Activate() var/obj/item/mecha_parts/mecha_equipment/t_scanner/t_scan = equipment - t_scan.scanning = !t_scan.scanning + t_scan.active = !t_scan.active t_scan.update_scan(t_scan.chassis.occupant) - t_scan.chassis.occupant_message("You [t_scan.scanning ? "activate" : "deactivate"] [t_scan].") - button_icon_state = "t_scanner_[t_scan.scanning ? "on" : "off"]" + t_scan.chassis.occupant_message("You [t_scan.active ? "activate" : "deactivate"] [t_scan].") + button_icon_state = "t_scanner_[t_scan.active ? "on" : "off"]" build_all_button_icons() - if(t_scan.scanning) - START_PROCESSING(SSobj, t_scan) - else - STOP_PROCESSING(SSobj, t_scan) /obj/item/mecha_parts/mecha_equipment/mag_treads name = "magnetic treads" diff --git a/code/game/mecha/equipment/weapons/armor.dm b/code/game/mecha/equipment/weapons/armor.dm new file mode 100644 index 000000000000..604a286746b0 --- /dev/null +++ b/code/game/mecha/equipment/weapons/armor.dm @@ -0,0 +1,47 @@ +//////////////////////////// ARMOR BOOSTER MODULES ////////////////////////////////////////////////////////// + +/obj/item/mecha_parts/mecha_equipment/armor + name = "armor booster module (Bad Code)" + desc = "Boosts exosuit armor against manatee. Make a bug report if you see this." + range = NONE + selectable = FALSE + equip_ready = TRUE + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, ELECTRIC = 0) + /// Reduces the effect of cooling. + var/cooling_multiplier = 0.8 + +/obj/item/mecha_parts/mecha_equipment/armor/can_attach(obj/mecha/M) + for(var/obj/item/equip as anything in M.equipment) + if(istype(equip, type)) // absolutely NO stacking armor to become invincible + return FALSE + return ..() + +/obj/item/mecha_parts/mecha_equipment/armor/attach(obj/mecha/new_chassis) + . = ..() + if(equip_ready) + new_chassis.armor.attachArmor(armor) + +/obj/item/mecha_parts/mecha_equipment/armor/detach(atom/moveto) + if(equip_ready) + chassis.armor.detachArmor(armor) + return ..() + +/obj/item/mecha_parts/mecha_equipment/armor/set_ready_state(state) + if(equip_ready != state) + if(state) + chassis.armor.attachArmor(armor) + else + chassis.armor.detachArmor(armor) + return ..() + +/obj/item/mecha_parts/mecha_equipment/armor/melee //what is that noise? A BAWWW from TK mutants. + name = "armor booster module (Close Combat Weaponry)" + desc = "Boosts exosuit armor against armed melee attacks. Requires energy to operate." + icon_state = "mecha_abooster_ccw" + armor = list(MELEE = 20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 20, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, ELECTRIC = 0) + +/obj/item/mecha_parts/mecha_equipment/armor/ranged + name = "armor booster module (Ranged Weaponry)" + desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots. Requires energy to operate." + icon_state = "mecha_abooster_proj" + armor = list(MELEE = 0, BULLET = 15, LASER = 15, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, ELECTRIC = 0) diff --git a/code/game/mecha/equipment/weapons/melee_weapons.dm b/code/game/mecha/equipment/weapons/melee_weapons.dm index 80104fb2bc06..7f446604d529 100644 --- a/code/game/mecha/equipment/weapons/melee_weapons.dm +++ b/code/game/mecha/equipment/weapons/melee_weapons.dm @@ -5,6 +5,7 @@ destroy_sound = 'sound/mecha/weapdestr.ogg' mech_flags = EXOSUIT_MODULE_COMBAT melee_override = TRUE + obj_flags = UNIQUE_RENAME // because it's COOL var/restricted = TRUE //for our special hugbox exofabs /// If we have a longer range weapon, such as a spear or whatever capable of hitting people further away, this is how much extra range it has var/extended_range = 0 @@ -68,6 +69,7 @@ /obj/item/mecha_parts/mecha_equipment/melee_weapon/start_cooldown() set_ready_state(0) chassis.use_power(energy_drain) + chassis.adjust_overheat(heat_cost) addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), chassis.melee_cooldown * attack_speed_modifier * check_eva()) //Guns only shoot so fast, but weapons can be used as fast as the chassis can swing it! //Melee weapon attacks are a little different in that they'll override the standard melee attack @@ -179,7 +181,8 @@ /obj/item/mecha_parts/mecha_equipment/melee_weapon/sword/shortsword //Our bread-and-butter mech shortsword for both slicing and stabbing baddies name = "\improper GD6 \"Jaeger\" Shortsword" desc = "An extendable arm-mounted blade with a nasty edge. It is small and fast enough to deflect some incoming attacks." - energy_drain = 20 + energy_drain = 2 + heat_cost = 3 weapon_damage = 10 precise_weapon_damage = 15 fauna_damage_bonus = 30 //because why not @@ -269,7 +272,8 @@ desc = "An oversized, destructive-looking axe with a powered edge. While far too big for use by an individual, an exosuit might be able to wield it." icon_state = "mecha_energy_axe" precise_attacks = FALSE //This is not a weapon of precision, it is a weapon of destruction - energy_drain = 40 + energy_drain = 4 + heat_cost = 8 weapon_damage = 30 fauna_damage_bonus = 30 //If you're fighting fauna with this thing, why? I mean it works, I guess. base_armor_piercing = 40 @@ -300,7 +304,8 @@ name = "\improper HR-2 \"Ronin\" Katana" desc = "An oversized, light-weight replica of an ancient style of blade. Still woefully underpowered in D&D." icon_state = "mecha_katana" - energy_drain = 15 + energy_drain = 2 + heat_cost = 3 cleave = FALSE //small fast blade precise_weapon_damage = 10 attack_speed_modifier = 0.7 //live out your anime dreams in a mech @@ -315,7 +320,8 @@ name = "\improper AV-98 \"Ingram\" Heavy Stun Baton" desc = "A stun baton, but bigger. The tide of toolbox-armed assistants don't stand a chance." icon_state = "mecha_batong" - energy_drain = 300 + energy_drain = 30 + heat_cost = 15 attack_speed_modifier = 2 //needs to recharge structure_damage_mult = 1 precise_weapon_damage = -25 //Mostly nonlethal @@ -368,7 +374,8 @@ name = "\improper TO-4 \"Tahu\" Flaming Chainsword" //ITS ALSO A CHAINSWORD FUCK YEAH desc = "It's as ridiculous as it is badass. You feel like use of this this might be considered a war crime somewhere." icon_state = "mecha_trogdor" - energy_drain = 30 + energy_drain = 3 + heat_cost = 5 precise_weapon_damage = 5 //Gotta make space for the burninating attack_speed_modifier = 1.2 //Little unwieldy fauna_damage_bonus = 20 @@ -396,7 +403,8 @@ name = "\improper ASW-8 \"Barbatos\" Heavy Maul" desc = "A massive, unwieldy, mace-like weapon, this thing really looks like something you don't want to be hit by if you're not a fan of being concave." icon_state = "mecha_maul" - energy_drain = 40 + energy_drain = 4 + heat_cost = 8 weapon_damage = 25 //Very smashy precise_weapon_damage = 30 attack_speed_modifier = 2.5 //Very slow @@ -418,7 +426,8 @@ name = "\improper MS-15 \"Gyan\" Rapier" desc = "A remarkably thin blade for a weapon wielded by an exosuit, this rapier is the favorite of syndicate pilots that perfer finesse over brute force." icon_state = "mecha_rapier" - energy_drain = 40 + energy_drain = 4 + heat_cost = 5 cleave = FALSE base_armor_piercing = 25 //50 on precise attack deflect_bonus = 15 //Mech fencing but it parries bullets too because robot reaction time or something @@ -487,7 +496,8 @@ desc = "A pair of short, hollow blades forged of exceptionally hard metal, these weapons are capable of injecting venom into a target on a successful hit." icon_state = "mecha_razer" gender = PLURAL - energy_drain = 40 + energy_drain = 4 + heat_cost = 5 cleave = FALSE base_armor_piercing = 40 //80 on precise attack deflect_bonus = 5 //Helps, but is a bit to small to be particularly good at it @@ -600,7 +610,8 @@ name = "\improper S5-C \"White Witch\" Shortspear" desc = "A hardened, telescoping metal rod with a wicked-sharp tip. Perfect for punching holes in things normally out of reach." icon_state = "mecha_spear" - energy_drain = 30 + energy_drain = 3 + heat_cost = 5 force = 10 //I want someone to stab someone else with this by hand extended_range = 1 //Hits from a tile away precise_weapon_damage = 10 @@ -660,6 +671,7 @@ desc = "A very big mop, designed to be attached to mechanical exosuits." icon_state = "mecha_mop" energy_drain = 5 + heat_cost = 1 // get mopped nerd attack_sound = 'sound/effects/slosh.ogg' cleave = TRUE @@ -695,7 +707,7 @@ return ..() /obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/proc/on_pre_move(obj/mecha/mech, atom/newloc) - if(mech.equipment_disabled || mech.completely_disabled) + if(mech.equipment_disabled || HAS_TRAIT(mech, TRAIT_MECH_DISABLED)) return if(!auto_sweep) return @@ -743,6 +755,7 @@ desc = "A comically large flyswatter, presumably for killing comically large bugs." attack_sound = 'sound/effects/snap.ogg' icon_state = "mecha_flyswatter" + heat_cost = 2 cleave = FALSE precise_attacks = TRUE hit_effect = ATTACK_EFFECT_SMASH diff --git a/code/game/mecha/equipment/weapons/other_weapons.dm b/code/game/mecha/equipment/weapons/other_weapons.dm index f16b48e1bdef..d97cf3e51cab 100644 --- a/code/game/mecha/equipment/weapons/other_weapons.dm +++ b/code/game/mecha/equipment/weapons/other_weapons.dm @@ -1,7 +1,10 @@ /obj/item/mecha_parts/mecha_equipment/afterburner name = "\improper CL-56 \"Hardlight\" Afterburner" desc = "A powerful thruster designed for small shuttles, retrofitted for exosuits despite better judgement. Redirects power from all other equipment during use. It has a warning label against mounting to anything not secured." - icon_state = "mecha_afterburner" + icon_state = "mecha_afterburner" + equip_cooldown = 7 SECONDS + energy_drain = 100 + heat_cost = 60 // rocket engines are HOT selectable = FALSE // your mech IS the weapon var/minimum_damage = 10 var/structure_damage_mult = 4 @@ -79,7 +82,7 @@ /datum/action/cooldown/mecha_afterburner name = "Fire Afterburner" - cooldown_time = 10 SECONDS + cooldown_time = 7 SECONDS // short cooldown with severe overheating check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_IMMOBILE | AB_CHECK_CONSCIOUS button_icon = 'icons/mob/actions/actions_mecha.dmi' button_icon_state = "mech_afterburner" @@ -94,15 +97,18 @@ chassis = new_mecha if(new_equip) rocket = new_equip + cooldown_time = new_equip.equip_cooldown return ..() /datum/action/cooldown/mecha_afterburner/Activate() - if(chassis.completely_disabled) + if(HAS_TRAIT(chassis, TRAIT_MECH_DISABLED)) + return + if(!rocket.equip_ready) return chassis.pass_flags |= PASSMOB // for not getting stopped by anything that can't be knocked down chassis.movement_type |= FLYING // for doing sick jumps over chasms - chassis.completely_disabled = TRUE chassis.AddComponent(/datum/component/after_image, 0.7 SECONDS, 0.5, FALSE) + ADD_TRAIT(chassis, TRAIT_MECH_DISABLED, type) if(istype(chassis, /obj/mecha/working/clarke) && lavaland_equipment_pressure_check(get_turf(chassis))) // clarke gets bonus armor when charging on lavaland chassis.armor.modifyRating(melee = 50) bonus_lavaland_armor = TRUE @@ -117,6 +123,10 @@ FALSE, callback = CALLBACK(src, PROC_REF(charge_end)) ) + rocket.start_cooldown() + chassis.can_move = world.time // reset next step time to stop the stationary cooling bonus + if(chassis.throwing) // if it ends instantly there's no need for a failsafe + addtimer(CALLBACK(src, PROC_REF(charge_end_failsafe)), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) else // if this somehow fails then something has gone terribly wrong charge_end() CRASH("[type] failed to complete wind-up!") @@ -129,8 +139,13 @@ if(bonus_lavaland_armor) chassis.armor.modifyRating(melee = -50) bonus_lavaland_armor = FALSE - chassis.completely_disabled = FALSE + REMOVE_TRAIT(chassis, TRAIT_MECH_DISABLED, type) chassis.movement_type &= ~FLYING chassis.pass_flags &= ~PASSMOB qdel(rocket.hit_list) rocket.hit_list = list() + +/datum/action/cooldown/mecha_afterburner/proc/charge_end_failsafe() + if(!chassis.throwing) + return + REMOVE_TRAIT(chassis, TRAIT_MECH_DISABLED, type) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 1054fd1b38c0..29acedcbb49a 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -73,11 +73,13 @@ firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/energy /obj/item/mecha_parts/mecha_equipment/weapon/energy/get_shot_amount() - return min(round(chassis.cell.charge / energy_drain), projectiles_per_shot) + return min(round(chassis.cell.charge / energy_drain), round((OVERHEAT_MAXIMUM - chassis.overheat) / heat_cost), projectiles_per_shot) /obj/item/mecha_parts/mecha_equipment/weapon/energy/start_cooldown() set_ready_state(0) - chassis.use_power(energy_drain*get_shot_amount()) + var/shot_amount = get_shot_amount() + chassis.use_power(energy_drain * shot_amount) + chassis.adjust_overheat(heat_cost * shot_amount) addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), equip_cooldown) /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser @@ -85,7 +87,8 @@ name = "\improper CH-PS \"Immolator\" laser" desc = "A weapon for combat exosuits. Shoots basic lasers." icon_state = "mecha_laser" - energy_drain = 30 + energy_drain = 3 + heat_cost = 5 projectile = /obj/projectile/beam/laser fire_sound = 'sound/weapons/laser.ogg' harmful = TRUE @@ -95,7 +98,8 @@ name = "\improper CH-DS \"Peacemaker\" disabler" desc = "A weapon for combat exosuits. Shoots basic disablers." icon_state = "mecha_disabler" - energy_drain = 30 + energy_drain = 3 + heat_cost = 2 projectile = /obj/projectile/beam/disabler fire_sound = 'sound/weapons/taser2.ogg' @@ -110,7 +114,8 @@ name = "\improper CH-LC \"Solaris\" laser cannon" desc = "A weapon for combat exosuits. Shoots heavy lasers." icon_state = "mecha_laser" - energy_drain = 60 + energy_drain = 6 + heat_cost = 15 projectile = /obj/projectile/beam/laser/heavylaser/no_fire fire_sound = 'sound/weapons/lasercannonfire.ogg' @@ -119,7 +124,8 @@ name = "\improper CH-XC \"Transitum\" x-ray laser" desc = "A weapon for combat exosuits. Shoots concentrated X-ray blasts." icon_state = "mecha_xray" - energy_drain = 60 + energy_drain = 6 + heat_cost = 15 projectile = /obj/projectile/beam/xray fire_sound = 'sound/weapons/laser3.ogg' @@ -128,7 +134,8 @@ name = "\improper MKIV ion heavy cannon" desc = "A weapon for combat exosuits. Shoots technology-disabling ion beams. Don't catch yourself in the blast!" icon_state = "mecha_ion" - energy_drain = 200 + energy_drain = 20 + heat_cost = 10 projectile = /obj/projectile/ion/heavy //Big boy 2/2 EMP bolts fire_sound = 'sound/weapons/laser.ogg' @@ -137,7 +144,8 @@ name = "\improper MKI Tesla Cannon" desc = "A weapon for combat exosuits. Fires bolts of electricity similar to the experimental tesla engine." icon_state = "mecha_ion" - energy_drain = 500 + energy_drain = 50 + heat_cost = 10 projectile = /obj/projectile/energy/tesla/cannon fire_sound = 'sound/magic/lightningbolt.ogg' harmful = TRUE @@ -147,7 +155,8 @@ name = "eZ-13 MK2 heavy pulse rifle" desc = "A weapon for combat exosuits. Shoots powerful destructive blasts capable of demolishing obstacles." icon_state = "mecha_pulse" - energy_drain = 120 + energy_drain = 12 + heat_cost = 20 projectile = /obj/projectile/beam/pulse/heavy fire_sound = 'sound/weapons/marauder.ogg' harmful = TRUE @@ -161,7 +170,8 @@ item_state = "plasmacutter" lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' - energy_drain = 30 + energy_drain = 3 + heat_cost = 2 projectile = /obj/projectile/plasma/adv/mech fire_sound = 'sound/weapons/plasma_cutter.ogg' usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') @@ -195,7 +205,8 @@ name = "Exosuit Proto-kinetic Accelerator" desc = "An exosuit-mounted mining tool that does increased damage in low pressure. Drawing from an onboard power source allows it to project further than the handheld version." icon_state = "mecha_kineticgun" - energy_drain = 30 + energy_drain = 3 + heat_cost = 2 projectile = /obj/projectile/kinetic/mech fire_sound = 'sound/weapons/kenetic_accel.ogg' harmful = FALSE @@ -214,8 +225,9 @@ name = "\improper PBT \"Pacifier\" mounted taser" desc = "A weapon for combat exosuits. Shoots non-lethal stunning electrodes." icon_state = "mecha_taser" - energy_drain = 20 + energy_drain = 2 equip_cooldown = 8 + heat_cost = 5 projectile = /obj/projectile/energy/electrode fire_sound = 'sound/weapons/taser.ogg' @@ -224,8 +236,9 @@ name = "\improper HoNkER BlAsT 5000" desc = "Equipment for clown exosuits. Spreads fun and joy to everyone around. Honk!" icon_state = "mecha_honker" - energy_drain = 200 + energy_drain = 20 equip_cooldown = 150 + heat_cost = 20 range = MECHA_MELEE|MECHA_RANGED kickback = FALSE mech_flags = EXOSUIT_MODULE_HONK @@ -338,6 +351,7 @@ desc = "A weapon for combat exosuits. Shoots incendiary bullets." icon_state = "mecha_carbine" equip_cooldown = 10 + heat_cost = 4 projectile = /obj/projectile/bullet/incendiary/fnx99 projectiles = 24 projectiles_cache = 24 @@ -351,6 +365,7 @@ fire_sound = null icon_state = "mecha_mime" equip_cooldown = 30 + heat_cost = 10 projectile = /obj/projectile/bullet/mime projectiles = 6 projectile_energy_cost = 50 @@ -361,6 +376,7 @@ desc = "A weapon for combat exosuits. Shoots a spread of pellets." icon_state = "mecha_scatter" equip_cooldown = 20 + heat_cost = 8 projectile = /obj/projectile/bullet/scattershot projectiles = 72 projectiles_cache = 72 @@ -375,6 +391,7 @@ desc = "A weapon for combat exosuits. Shoots a rapid, three shot burst." icon_state = "mecha_uac2" equip_cooldown = 10 + heat_cost = 3 projectile = /obj/projectile/bullet/lmg projectiles = 300 projectiles_cache = 300 @@ -391,6 +408,7 @@ desc = "A weapon for combat exosuits. Shoots an incredibly hot beam surrounded by a field of plasma." icon_state = "mecha_laser" equip_cooldown = 2 SECONDS + heat_cost = 15 projectile = /obj/projectile/beam/bfg projectiles = 5 projectiles_cache = 0 @@ -404,6 +422,7 @@ desc = "A weapon for combat exosuits. Shoots incendiary bullets." icon_state = "mecha_venom" equip_cooldown = 10 + heat_cost = 5 fire_sound = 'sound/weapons/smgshot.ogg' projectile = /obj/projectile/bullet/c45/venom //yes the same one projectiles = 24 @@ -423,6 +442,7 @@ projectiles_cache_max = 0 disabledreload = TRUE equip_cooldown = 60 + heat_cost = 20 harmful = TRUE ammo_type = "missiles_he" @@ -437,6 +457,7 @@ projectiles_cache_max = 0 disabledreload = TRUE equip_cooldown = 60 + heat_cost = 20 harmful = TRUE ammo_type = "missiles_br" @@ -471,6 +492,7 @@ projectiles_cache_max = 24 missile_speed = 1.5 equip_cooldown = 60 + heat_cost = 10 var/det_time = 20 ammo_type = "flashbang" @@ -489,6 +511,7 @@ disabledreload = TRUE projectile = /obj/item/grenade/clusterbuster equip_cooldown = 90 + heat_cost = 20 ammo_type = "clusterbang" /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar @@ -501,6 +524,7 @@ missile_speed = 1.5 projectile_energy_cost = 100 equip_cooldown = 20 + heat_cost = 2 // honk mech_flags = EXOSUIT_MODULE_HONK /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/mecha/combat/honker/M) @@ -519,6 +543,7 @@ missile_speed = 1.5 projectile_energy_cost = 100 equip_cooldown = 10 + heat_cost = 2 mech_flags = EXOSUIT_MODULE_HONK /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M) @@ -538,6 +563,7 @@ icon_state = "mecha_punching_glove" energy_drain = 250 equip_cooldown = 20 + heat_cost = 5 range = MECHA_MELEE|MECHA_RANGED missile_range = 5 projectile = /obj/item/punching_glove diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 849b16dad26f..371711b8ffa2 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -1,18 +1,3 @@ -#define MECHA_INT_FIRE (1<<0) -#define MECHA_INT_TEMP_CONTROL (1<<1) -#define MECHA_INT_SHORT_CIRCUIT (1<<2) -#define MECHA_INT_TANK_BREACH (1<<3) -#define MECHA_INT_CONTROL_LOST (1<<4) - -#define MECHA_MELEE (1<<0) -#define MECHA_RANGED (1<<1) - -#define FRONT_ARMOUR 1 -#define SIDE_ARMOUR 2 -#define BACK_ARMOUR 3 - -#define MECHA_MAX_COOLDOWN 30 // Prevents long cooldown equipment from messing up combat - /obj/mecha name = "mecha" desc = "Exosuit" @@ -23,6 +8,7 @@ layer = BELOW_MOB_LAYER//icon draw layer infra_luminosity = 15 //byond implementation is bugged. force = 5 + var/punch_heat_cost = 2 light_system = MOVABLE_LIGHT_DIRECTIONAL light_range = 8 light_on = FALSE @@ -60,7 +46,6 @@ var/datum/effect_system/spark_spread/spark_system = new var/lights = FALSE var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference - var/completely_disabled = FALSE //stops the mech from doing anything var/omnidirectional_attacks = FALSE //lets mech shoot anywhere, not just in front of it var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it. @@ -74,6 +59,13 @@ var/obj/item/radio/mech/radio var/list/trackers = list() + /// Overheating level. This causes damage, slowdown, and eventually complete shutdown. + var/overheat = 0 + /// Multiplier for overheat gain and loss. + var/heat_modifier = 1 + /// Multiplier for cooling specifically. + var/cooling_modifier = 1 + var/max_temperature = 25000 var/internal_damage_threshold = 50 //health percentage below which internal damage is possible var/internal_damage = 0 //contains bitflags @@ -132,7 +124,6 @@ var/defence_mode = FALSE var/defence_mode_deflect_chance = 15 var/leg_overload_mode = FALSE - var/leg_overload_coeff = 100 var/zoom_mode = FALSE var/smoke = 5 var/smoke_ready = 1 @@ -150,7 +141,7 @@ var/occupant_sight_flags = 0 //sight flags to give to the occupant (e.g. mech mining scanner gives meson-like vision) var/mouse_pointer - hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD) + hud_possible = list (DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD, DIAG_OVERHEAT_HUD) /obj/item/radio/mech //this has to go somewhere @@ -169,7 +160,7 @@ add_cell() add_scanmod() add_capacitor() - START_PROCESSING(SSobj, src) + START_PROCESSING(SSmecha, src) GLOB.poi_list |= src log_message("[src.name] created.", LOG_MECHA) GLOB.mechas_list += src //global mech list @@ -179,6 +170,7 @@ diag_hud_set_mechhealth() diag_hud_set_mechcell() diag_hud_set_mechstat() + diag_hud_set_mechoverheat() RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) ADD_TRAIT(src, TRAIT_SHIELDBUSTER, INNATE_TRAIT) // previously it didn't even check shields at all, now it still doesn't but does some fun stuff in the process @@ -226,7 +218,7 @@ qdel(internal_tank) if(AI) AI.gib() //No wreck, no AI to recover - STOP_PROCESSING(SSobj, src) + STOP_PROCESSING(SSmecha, src) GLOB.poi_list.Remove(src) equipment.Cut() cell = null @@ -325,6 +317,23 @@ return TRUE return FALSE +/obj/mecha/proc/adjust_overheat(amount = 0) + if(amount > 0) + amount *= 1.2 - (scanmod.rating * 0.1) // 1.1x to 0.8x heat generation based on scanner module rating + overheat = round(clamp(overheat + (amount * heat_modifier), 0, OVERHEAT_MAXIMUM), 0.1) + if(overheat >= OVERHEAT_MAXIMUM && amount > 0) + if(overload_action) + overload_action.Activate(FALSE) // turn it off + occupant.throw_alert("mech_overheat", /atom/movable/screen/alert/overheating, 3) + ADD_TRAIT(src, TRAIT_MECH_DISABLED, OVERHEAT_TRAIT) + if(world.time > last_message + 2 SECONDS) + SEND_SOUND(occupant, sound('sound/machines/warning-buzzer.ogg',volume=50)) + occupant_message("Warning: overheating critical. Shutdown imminent.") + else if(overheat < OVERHEAT_THRESHOLD) + REMOVE_TRAIT(src, TRAIT_MECH_DISABLED, OVERHEAT_TRAIT) + infra_luminosity = initial(infra_luminosity) * (1 + overheat / OVERHEAT_THRESHOLD) // hotter mechs are more visible on infrared + diag_hud_set_mechoverheat() + /obj/mecha/CanAllowThrough(atom/movable/mover, turf/target) . = ..() // if something can go through machines it can go through mechs if(istype(mover) && (mover.pass_flags & PASSMECH)) @@ -376,8 +385,14 @@ if(href_list["list_armor"]) to_chat(usr, "[armor.show_protection_classes()]") -//processing internal damage, temperature, air regulation, alert updates, lights power use. -/obj/mecha/process() +//processing equipment, internal damage, temperature, air regulation, alert updates, lights power use. +/obj/mecha/process(delta_time) + for(var/obj/item/mecha_parts/mecha_equipment/equip as anything in equipment) + if(!equip.active) + continue + if(equip.on_process(delta_time) == PROCESS_KILL) + equip.active = FALSE + var/internal_temp_regulation = TRUE if(internal_damage) @@ -389,9 +404,9 @@ if(int_tank_air.return_pressure() > internal_tank.maximum_pressure && !(internal_damage & MECHA_INT_TANK_BREACH)) setInternalDamage(MECHA_INT_TANK_BREACH) if(int_tank_air && int_tank_air.return_volume() > 0) //heat the air_contents - int_tank_air.set_temperature(min(6000+T0C, int_tank_air.return_temperature()+rand(10,15))) + int_tank_air.set_temperature(min(6000+T0C, int_tank_air.return_temperature() + rand(5, 7) * delta_time)) if(cabin_air && cabin_air.return_volume()>0) - cabin_air.set_temperature(min(6000+T0C, cabin_air.return_temperature()+rand(10,15))) + cabin_air.set_temperature(min(6000+T0C, cabin_air.return_temperature() + rand(5, 7) * delta_time)) if(cabin_air.return_temperature() > max_temperature/2) take_damage(4/round(max_temperature/cabin_air.return_temperature(),0.1), BURN, 0, 0) @@ -405,13 +420,23 @@ if(internal_damage & MECHA_INT_SHORT_CIRCUIT) if(get_charge()) spark_system.start() - cell.charge -= min(20,cell.charge) - cell.maxcharge -= min(20,cell.maxcharge) + cell.charge -= min(delta_time SECONDS, cell.charge) + cell.maxcharge -= min(delta_time SECONDS, cell.maxcharge) + + if(world.time > can_move) + adjust_overheat(max((world.time - can_move) * STATIONARY_COOLING * delta_time, STATIONARY_COOLING_MAXIMUM)) if(internal_temp_regulation) + adjust_overheat(PASSIVE_COOLING * delta_time) + var/datum/gas_mixture/environment = loc.return_air() + if(environment?.return_temperature() > max_temperature) + adjust_overheat(min((environment.return_temperature() - max_temperature) / max_temperature, -PASSIVE_COOLING)) if(cabin_air && cabin_air.return_volume() > 0) var/delta = cabin_air.return_temperature() - T20C - cabin_air.set_temperature(cabin_air.return_temperature() - max(-10, min(10, round(delta/4,0.1)))) + cabin_air.set_temperature(cabin_air.return_temperature() - max(-0.5 * delta_time SECONDS, min(10, round(delta/4,0.1)))) + + if(overheat >= OVERHEAT_THRESHOLD) + take_damage(delta_time * (1 + 2 * (overheat - OVERHEAT_THRESHOLD) / OVERHEAT_THRESHOLD), BURN, null, FALSE) // 1 to 3 damage per second if(internal_tank) var/datum/gas_mixture/tank_air = internal_tank.return_air() @@ -458,6 +483,14 @@ occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 3) else occupant.clear_alert("mech damage") + + if(HAS_TRAIT_FROM(src, TRAIT_MECH_DISABLED, OVERHEAT_TRAIT)) + occupant.throw_alert("mech_overheat", /atom/movable/screen/alert/overheating, 3) + else if(overheat >= OVERHEAT_WARNING) + occupant.throw_alert("mech_overheat", /atom/movable/screen/alert/overheating, round(3 * (overheat - OVERHEAT_WARNING) / (OVERHEAT_MAXIMUM - OVERHEAT_WARNING))) + else + occupant.clear_alert("mech_overheat") + var/atom/checking = occupant.loc // recursive check to handle all cases regarding very nested occupants, // such as brainmob inside brainitem inside MMI inside mecha @@ -482,10 +515,11 @@ visible_message(span_warning("[occupant] tumbles out of the cockpit!")) go_out() //Maybe we should install seat belts? -//Diagnostic HUD updates + //Diagnostic HUD updates diag_hud_set_mechhealth() diag_hud_set_mechcell() diag_hud_set_mechstat() + diag_hud_set_mechoverheat() /obj/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech . = ..() @@ -494,6 +528,11 @@ occupant.adjust_fire_stacks(1) occupant.ignite_mob() +/obj/mecha/extinguish() // can be ignited, so should be extinguished as well + . = ..() + if(occupant && !enclosed && !silicon_pilot) + occupant.extinguish_mob() + /obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. return @@ -519,7 +558,7 @@ return if(!locate(/turf) in list(target,target.loc)) // Prevents inventory from being drilled return - if(completely_disabled) + if(HAS_TRAIT(src, TRAIT_MECH_DISABLED)) return if(is_currently_ejecting) return @@ -563,8 +602,8 @@ return target.mech_melee_attack(src, force, TRUE) melee_can_hit = FALSE - spawn(melee_cooldown) - melee_can_hit = TRUE + adjust_overheat(punch_heat_cost) + addtimer(VARSET_CALLBACK(src, melee_can_hit, TRUE), melee_cooldown) /obj/mecha/proc/range_action(atom/target) @@ -599,7 +638,7 @@ /obj/mecha/relaymove(mob/user,direction) if(wrecked) // for any AIs still stuck inside return - if(completely_disabled) + if(HAS_TRAIT(src, TRAIT_MECH_DISABLED)) return if(!direction) return @@ -654,19 +693,23 @@ var/move_result = 0 var/oldloc = loc + var/step_time = step_in * check_eva() + if(overheat > OVERHEAT_THRESHOLD) + can_move += (min(overheat, OVERHEAT_MAXIMUM) - OVERHEAT_THRESHOLD) / OVERHEAT_THRESHOLD // up to 0.5 slower based on overheating + if(internal_damage & MECHA_INT_CONTROL_LOST) - set_glide_size(DELAY_TO_GLIDE_SIZE(step_in * check_eva())) + set_glide_size(DELAY_TO_GLIDE_SIZE(step_time)) move_result = mechsteprand() else if(dir != direction && (!strafe || occupant?.client?.keys_held["Alt"])) move_result = mechturn(direction) else - set_glide_size(DELAY_TO_GLIDE_SIZE(step_in * check_eva())) + set_glide_size(DELAY_TO_GLIDE_SIZE(step_time)) move_result = mechstep(direction) if(move_result || loc != oldloc)// halfway done diagonal move still returns false use_power(step_energy_drain) if(leg_overload_mode) - take_damage(2, BRUTE) - can_move = world.time + step_in * check_eva() + adjust_overheat(OVERLOAD_HEAT_COST) + can_move = world.time + step_time return TRUE return FALSE @@ -1143,6 +1186,7 @@ var/is_ai_user = FALSE occupant.clear_alert("charge") occupant.clear_alert("mech damage") + occupant.clear_alert("mech_overheat") if(ishuman(occupant)) mob_container = occupant RemoveActions(occupant, human_occupant=1) @@ -1256,12 +1300,14 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? amount *= (2.5 - (scanmod.rating / 2)) // 0-5: 2.5x, 2x, 1.5x, 1x, 0.5x if(get_charge()) cell.use(amount) + diag_hud_set_mechcell(amount) return TRUE return FALSE /obj/mecha/proc/give_power(amount) if(!isnull(get_charge())) cell.give(amount) + diag_hud_set_mechcell(amount) return TRUE return FALSE diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm index 522c3eb85cc1..9200ef4c0934 100644 --- a/code/game/mecha/mecha_actions.dm +++ b/code/game/mecha/mecha_actions.dm @@ -199,13 +199,11 @@ chassis.leg_overload_mode = 1 chassis.bumpsmash = 1 chassis.step_in = min(1, round(chassis.step_in/2)) - chassis.step_energy_drain = max(chassis.overload_step_energy_drain_min,chassis.step_energy_drain*chassis.leg_overload_coeff) chassis.occupant_message(span_danger("You enable leg actuators overload.")) else chassis.leg_overload_mode = 0 chassis.bumpsmash = initial(chassis.bumpsmash) chassis.step_in = initial(chassis.step_in) - chassis.step_energy_drain = chassis.normal_step_energy_drain chassis.occupant_message(span_notice("You disable leg actuators overload.")) build_all_button_icons() diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index 6b6a6679afd8..09e75fd6d1b2 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -20,30 +20,29 @@ if(. >= 5 || prob(33)) occupant_message(span_userdanger("Taking damage!")) log_message("Took [damage_amount] points of damage. Damage type: [damage_type]", LOG_MECHA) + diag_hud_set_mechhealth() + +/obj/mecha/repair_damage(amount) + . = ..() + diag_hud_set_mechhealth() /obj/mecha/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) . = ..() if(!damage_amount) return 0 - var/booster_deflection_modifier = 1 - var/booster_damage_modifier = 1 + var/deflection_modifier = 1 + var/damage_modifier = 1 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(dir2angle(attack_dir) - dir2angle(dir)) - booster_damage_modifier /= facing_modifier - booster_deflection_modifier *= facing_modifier - if(prob(deflect_chance * booster_deflection_modifier)) + damage_modifier /= facing_modifier + deflection_modifier *= facing_modifier + if(prob(deflect_chance * deflection_modifier)) visible_message(span_danger("[src]'s armour deflects the attack!")) log_message("Armor saved.", LOG_MECHA) return 0 if(.) - . *= booster_damage_modifier + . *= damage_modifier /obj/mecha/attack_hand(mob/living/user) @@ -107,38 +106,33 @@ . = ..() -/obj/mecha/bullet_act(obj/projectile/Proj) //wrapper - if ((!enclosed || istype(Proj, /obj/projectile/bullet/shotgun/slug/uranium))&& occupant && !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 - occupant.bullet_act(Proj) //If the sides are open, the occupant can be hit - return BULLET_ACT_HIT - if(istype(Proj, /obj/projectile/ion)) +/obj/mecha/bullet_act(obj/projectile/incoming) + if((!enclosed || incoming.penetration_flags & PENETRATE_OBJECTS) && occupant && !silicon_pilot && !incoming.force_hit && (incoming.def_zone == BODY_ZONE_HEAD || incoming.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs + occupant.bullet_act(incoming) //If the sides are open, the occupant can be hit + if(istype(incoming, /obj/projectile/ion)) return ..() - var/booster_deflection_modifier = 1 - var/booster_damage_modifier = 1 - var/attack_dir = get_dir(src, Proj) - 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 + var/deflection_modifier = 1 + var/damage_modifier = 1 + var/attack_dir = get_dir(src, incoming) if(attack_dir) var/facing_modifier = get_armour_facing(dir2angle(attack_dir) - dir2angle(dir)) - booster_damage_modifier /= facing_modifier - booster_deflection_modifier *= facing_modifier - if(prob(deflect_chance * booster_deflection_modifier)) + damage_modifier /= facing_modifier + deflection_modifier *= facing_modifier + if(prob(deflect_chance * deflection_modifier)) visible_message(span_danger("[src]'s armour deflects the attack!")) if(super_deflects) - Proj.firer = src - Proj.setAngle(rand(0, 360)) //PTING + incoming.firer = src + incoming.setAngle(rand(0, 360)) //PTING return BULLET_ACT_FORCE_PIERCE else - Proj.damage = 0 //Armor has stopped the projectile effectively, if it has other effects that's another issue + incoming.damage = 0 //Armor has stopped the projectile effectively, if it has other effects that's another issue return BULLET_ACT_BLOCK - Proj.damage *= booster_damage_modifier //If you manage to shoot THROUGH a mech with something, the bullet wont be fully intact - if(!HAS_TRAIT(Proj, TRAIT_SHIELDBUSTER)) // Exceptionally strong projectiles do the full damage - Proj.demolition_mod = (1 + Proj.demolition_mod) / 2 + incoming.damage *= damage_modifier //If you manage to shoot THROUGH a mech with something, the bullet wont be fully intact + if(!HAS_TRAIT(incoming, TRAIT_SHIELDBUSTER)) // Exceptionally strong projectiles do the full damage + incoming.demolition_mod = (1 + incoming.demolition_mod) / 2 - log_message("Hit by projectile. Type: [Proj.name]([Proj.armor_flag]).", LOG_MECHA, color="red") + log_message("Hit by projectile. Type: [incoming.name]([incoming.armor_flag]).", LOG_MECHA, color="red") return ..() /obj/mecha/ex_act(severity, target) @@ -181,32 +175,56 @@ . = ..() if (. & EMP_PROTECT_SELF) return + severity -= EMP_HEAVY * (100 - armor.getRating(ENERGY)) / 100 // energy armor is subtractive so that it's less effective against stronger EMPs and more against weaker ones if(get_charge()) - use_power((cell.charge * severity / 15)) - - take_damage(4 * severity, BURN, ENERGY, 1) + use_power(cell.charge * severity / 40) + if(overheat < OVERHEAT_EMP_MAX) + adjust_overheat(min(severity, OVERHEAT_EMP_MAX - overheat)) + + take_damage(2 * severity, BURN, ENERGY, 1) log_message("EMP detected", LOG_MECHA, color="red") + if(severity <= EMP_LIGHT || overheat < OVERHEAT_WARNING / 2) + return // only a light EMP, equipment is still fine + if(istype(src, /obj/mecha/combat)) mouse_pointer = 'icons/mecha/mecha_mouse-disable.dmi' occupant?.update_mouse_pointer() if(!equipment_disabled && occupant) //prevent spamming this message with back-to-back EMPs to_chat(occupant, "Error -- Connection to equipment control unit has been lost.") - overload_action.Activate(0) - addtimer(CALLBACK(src, /obj/mecha/proc/restore_equipment), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) - equipment_disabled = 1 + overload_action.Activate(FALSE) + addtimer(CALLBACK(src, /obj/mecha/proc/restore_equipment), (overheat / OVERHEAT_WARNING) SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) // up to 3 seconds based on heat + equipment_disabled = TRUE /obj/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature>max_temperature) log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red") take_damage(5, BURN, 0, 1) +/obj/mecha/welder_act(mob/living/user, obj/item/tool, modifiers) + if(user.combat_mode) + return FALSE + if(wrecked) + try_repair(tool, user) + else if(atom_integrity < max_integrity) + while(atom_integrity < max_integrity && tool.use_tool(src, user, 1 SECONDS, volume=50, amount=1)) + if(internal_damage & MECHA_INT_TANK_BREACH) + clearInternalDamage(MECHA_INT_TANK_BREACH) + to_chat(user, span_notice("You repair the damaged gas tank.")) + user.visible_message(span_notice("[user] repairs some damage to [name]."), span_notice("You repair some damage to [src].")) + repair_damage(10) + if(atom_integrity == max_integrity) + to_chat(user, span_notice("It looks to be fully repaired now.")) + else + to_chat(user, span_warning("The [name] is at full integrity!")) + return TRUE + /obj/mecha/attackby(obj/item/W, mob/living/user, params) if(user.combat_mode) return ..() if(wrecked) - return try_repair(W, user, params) + return try_repair(W, user) if(istype(W, /obj/item/mmi)) if(mmi_move_inside(W,user)) @@ -303,23 +321,6 @@ to_chat(user, span_notice("There's already a capacitor installed.")) return - else if(W.tool_behaviour == TOOL_WELDER && !user.combat_mode) - user.changeNext_move(CLICK_CD_MELEE) - if(atom_integrity < max_integrity) - if(W.use_tool(src, user, 0, volume=50, amount=1)) - if (internal_damage & MECHA_INT_TANK_BREACH) - clearInternalDamage(MECHA_INT_TANK_BREACH) - to_chat(user, span_notice("You repair the damaged gas tank.")) - else - user.visible_message(span_notice("[user] repairs some damage to [name]."), span_notice("You repair some damage to [src].")) - update_integrity(atom_integrity + min(10, max_integrity-atom_integrity)) - if(atom_integrity == max_integrity) - to_chat(user, span_notice("It looks to be fully repaired now.")) - return 1 - else - to_chat(user, span_warning("The [name] is at full integrity!")) - return 1 - else if(istype(W, /obj/item/airlock_scanner)) //yogs start var/obj/item/airlock_scanner/S = W S.show_access(src, user) //yogs end @@ -327,7 +328,7 @@ else return ..() -/obj/mecha/proc/try_repair(obj/item/I, mob/living/user, params) +/obj/mecha/proc/try_repair(obj/item/I, mob/living/user) if(!capacitor?.rating) to_chat(user, span_warning("[src] is damaged beyond repair, there is nothing you can do.")) return diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm index 609a062059dd..820894348fe4 100644 --- a/code/game/mecha/mecha_topic.dm +++ b/code/game/mecha/mecha_topic.dm @@ -91,6 +91,8 @@ . = {"[report_internal_damage()] [integrity<30?"[span_userdanger("DAMAGE LEVEL CRITICAL")]
":null] Integrity: [integrity]%
+ [overheat >= OVERHEAT_THRESHOLD ? "[span_userdanger("TEMPERATURE CRITICAL")]
" : ""] + Temperature: [overheat]°C
Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
Air source: [internal_tank?"[use_internal_tank?"Internal Airtank":"Environment"]":"Environment"]
Airtank pressure: [internal_tank?"[tank_pressure]kPa":"N/A"]
diff --git a/code/game/mecha/working/clarke.dm b/code/game/mecha/working/clarke.dm index 1308dc2ed94d..9268b98d2ec8 100644 --- a/code/game/mecha/working/clarke.dm +++ b/code/game/mecha/working/clarke.dm @@ -11,6 +11,7 @@ slow_pressure_step_in = 2 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF weather_protection = WEATHER_LAVA|WEATHER_STORM + facing_modifiers = list(FRONT_ARMOUR = 1.2, SIDE_ARMOUR = 1, BACK_ARMOUR = 0.8) // omnidirectional, less significant difference between attack directions light_power = 7 deflect_chance = 10 flags_1 = HEAR_1 | RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1 diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 76a37f2d00fe..52b6653f9c3e 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -695,7 +695,7 @@ /obj/item/melee/roastingstick/Initialize(mapload) . = ..() if (!ovens) - ovens = typecacheof(list(/obj/singularity, /obj/machinery/power/supermatter_crystal, /obj/structure/bonfire, /obj/structure/destructible/clockwork/massive/ratvar, /obj/structure/destructible/clockwork/massive/celestial_gateway)) + ovens = typecacheof(list(/obj/singularity, /obj/machinery/power/supermatter_crystal, /obj/structure/bonfire, /obj/structure/destructible/clockwork/massive/ratvar, /obj/structure/destructible/clockwork/massive/celestial_gateway, /obj/mecha)) /obj/item/melee/roastingstick/attack_self(mob/user) on = !on @@ -763,6 +763,11 @@ if (held_sausage && held_sausage.roasted) to_chat("Your [held_sausage] has already been cooked.") return + if(ismecha(target)) + var/obj/mecha/overheating_mech = target + if(overheating_mech.overheat < OVERHEAT_THRESHOLD) + to_chat(user, span_warning("[overheating_mech] isn't hot enough!")) + return if (istype(target, /obj/singularity) && get_dist(user, target) < 10) to_chat(user, "You send [held_sausage] towards [target].") playsound(src, 'sound/items/rped.ogg', 50, 1) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_gun.dm b/code/modules/antagonists/eldritch_cult/eldritch_gun.dm index a21f30ec0d2b..fb576bc17379 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_gun.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_gun.dm @@ -134,7 +134,7 @@ // If fired without aiming or at someone too close, it will do much less damage = 30 stamina = 30 - penetration_flags = PENETRATE_OBJECTS | PENETRATE_MOBS + penetration_flags = PENETRATE_OBJECTS | PENETRATE_WALLS | PENETRATE_MOBS penetrations = INFINITY // Extra ammunition can be made with a heretic ritual. diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index b765a918e500..741ea7ce93dc 100644 --- a/code/modules/fields/timestop.dm +++ b/code/modules/fields/timestop.dm @@ -128,11 +128,11 @@ global_frozen_atoms -= A -/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/M) - M.completely_disabled = TRUE +/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/mech) + ADD_TRAIT(mech, TRAIT_MECH_DISABLED, type) -/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/M) - M.completely_disabled = FALSE +/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/mech) + REMOVE_TRAIT(mech, TRAIT_MECH_DISABLED, type) /datum/proximity_monitor/advanced/timestop/proc/freeze_throwing(atom/movable/AM) diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index bb257e3cd449..2a8c4376ced5 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -368,7 +368,7 @@ aoe_range = 0 // no AOE, has piercing instead penetrations = 2 tracer_fire_chance = 50 - penetration_flags = PENETRATE_OBJECTS | PENETRATE_MOBS + penetration_flags = PENETRATE_OBJECTS | PENETRATE_WALLS | PENETRATE_MOBS /obj/projectile/beam/beam_rifle/hitscan/impact damage = 30 // total of 60 on direct hit diff --git a/code/modules/projectiles/guns/misc/flamethrower.dm b/code/modules/projectiles/guns/misc/flamethrower.dm index d3df0c829cd1..9cda9b624b84 100644 --- a/code/modules/projectiles/guns/misc/flamethrower.dm +++ b/code/modules/projectiles/guns/misc/flamethrower.dm @@ -223,7 +223,7 @@ range = 6 damage = 16 demolition_mod = 2 // bonus damage against blobs and vines, most other structures have very high fire armor - penetration_flags = PENETRATE_OBJECTS|PENETRATE_MOBS + penetration_flags = PENETRATE_OBJECTS | PENETRATE_WALLS | PENETRATE_MOBS penetrations = INFINITY ignore_crit = TRUE ///Reference to the fuel tank in the flamethrower. @@ -262,6 +262,9 @@ /obj/projectile/flamethrower/prehit(atom/target) // humans use a different heat protection system if(nodamage) return FALSE // don't do direct damage, just make fire + var/turf/target_turf = get_turf(target) + if(target.loc.return_air() != target_turf.return_air()) + return FALSE if(ishuman(target)) var/mob/living/carbon/human/joshua_graham = target joshua_graham.apply_damage(damage, BURN, null, joshua_graham.get_heat_protection(last_burn_temp) * 100) diff --git a/code/modules/projectiles/guns/misc/medbeam.dm b/code/modules/projectiles/guns/misc/medbeam.dm index fb88edb6ae95..4da1db246acd 100644 --- a/code/modules/projectiles/guns/misc/medbeam.dm +++ b/code/modules/projectiles/guns/misc/medbeam.dm @@ -64,7 +64,7 @@ if(current_target) LoseTarget() if(!isliving(target)) - return + return FALSE current_target = target active = TRUE @@ -72,8 +72,9 @@ RegisterSignal(current_beam, COMSIG_QDELETING, PROC_REF(beam_died))//this is a WAY better rangecheck than what was done before (process check) SSblackbox.record_feedback("tally", "gun_fired", 1, type) + return TRUE -/obj/item/gun/medbeam/process() +/obj/item/gun/medbeam/process(delta_time) var/source = loc if(!mounted && !isliving(source)) @@ -96,7 +97,7 @@ return if(current_target) - on_beam_tick(current_target) + on_beam_tick(current_target, delta_time) /obj/item/gun/medbeam/proc/los_check(atom/movable/user, mob/target) var/turf/user_turf = user.loc @@ -127,14 +128,14 @@ /obj/item/gun/medbeam/proc/on_beam_hit(mob/living/target) return -/obj/item/gun/medbeam/proc/on_beam_tick(mob/living/target) +/obj/item/gun/medbeam/proc/on_beam_tick(mob/living/target, delta_time = SSOBJ_DT) if(target.health != target.maxHealth) new /obj/effect/temp_visual/heal(get_turf(target), COLOR_HEALING_CYAN) var/need_mob_update - need_mob_update = target.adjustBruteLoss(-4, updating_health = FALSE, forced = TRUE) - need_mob_update += target.adjustFireLoss(-4, updating_health = FALSE, forced = TRUE) - need_mob_update += target.adjustToxLoss(-1, updating_health = FALSE, forced = TRUE) - need_mob_update += target.adjustOxyLoss(-1, updating_health = FALSE, forced = TRUE) + need_mob_update = target.adjustBruteLoss(-2 * delta_time, updating_health = FALSE, forced = TRUE) + need_mob_update += target.adjustFireLoss(-2 * delta_time, updating_health = FALSE, forced = TRUE) + need_mob_update += target.adjustToxLoss(-0.5 * delta_time, updating_health = FALSE, forced = TRUE) + need_mob_update += target.adjustOxyLoss(-0.5 * delta_time, updating_health = FALSE, forced = TRUE) if(need_mob_update) target.updatehealth() return diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 3a3cf3b70144..973725ef1001 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -226,7 +226,7 @@ W.add_dent(WALL_DENT_SHOT, hitx, hity) - if((penetration_flags & PENETRATE_OBJECTS) && penetrations > 0) + if((penetration_flags & PENETRATE_WALLS) && penetrations > 0) penetrations -= 1 return BULLET_ACT_FORCE_PIERCE diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm index e3f67d9874d5..bb75e9f2a546 100644 --- a/code/modules/projectiles/projectile/bullets/rifle.dm +++ b/code/modules/projectiles/projectile/bullets/rifle.dm @@ -62,7 +62,7 @@ damage = 52 armour_penetration = 40 penetrations = 2 //Passes through two objects, stops on a mob or on a third object - penetration_flags = PENETRATE_OBJECTS + penetration_flags = PENETRATE_OBJECTS | PENETRATE_WALLS demolition_mod = 1.5 // anti-armor /obj/projectile/bullet/a762/vulcan diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 9dc2917e3018..ef855bbf3691 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -76,6 +76,7 @@ armour_penetration = 60 // he he funny round go through armor wound_bonus = -40 demolition_mod = 3 // very good at smashing through stuff + penetration_flags = PENETRATE_OBJECTS | PENETRATE_MOBS penetrations = INFINITY //Goes through an infinite number of mobs /obj/projectile/bullet/shotgun/slug/uranium/Initialize(mapload) diff --git a/code/modules/projectiles/projectile/bullets/sniper.dm b/code/modules/projectiles/projectile/bullets/sniper.dm index e4a4f0c75a72..315577e7185b 100644 --- a/code/modules/projectiles/projectile/bullets/sniper.dm +++ b/code/modules/projectiles/projectile/bullets/sniper.dm @@ -34,7 +34,7 @@ icon_state = "gauss" damage = 60 penetrations = INFINITY //Passes through everything and anything until it reaches the end of its range - penetration_flags = PENETRATE_OBJECTS | PENETRATE_MOBS + penetration_flags = PENETRATE_OBJECTS | PENETRATE_WALLS | PENETRATE_MOBS dismemberment = 0 //It goes through you cleanly. paralyze = 0 shieldbuster = FALSE diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index 506b62d4b72f..bb779e62caeb 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -506,7 +506,7 @@ desc = "Exosuit-mounted 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/melee materials = list(/datum/material/iron=20000,/datum/material/silver=5000) construction_time = 100 category = list("Exosuit Equipment") @@ -516,7 +516,7 @@ desc = "Exosuit-mounted 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/ranged materials = list(/datum/material/iron=20000,/datum/material/gold=5000) construction_time = 100 category = list("Exosuit Equipment") @@ -581,6 +581,36 @@ construction_time = 100 category = list("Exosuit Equipment") +/datum/design/mech_passive_cooling + name = "Exosuit Module (Passive Cooling)" + desc = "Passive cooling system. Requires an atmosphere." + id = "mech_passive_cooling" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/cooling/passive + materials = list(/datum/material/iron=5000,) + construction_time = 100 + category = list("Exosuit Equipment") + +/datum/design/mech_active_cooling + name = "Exosuit Module (Active Cooling)" + desc = "Active cooling system. Requires power." + id = "mech_active_cooling" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/cooling/active + materials = list(/datum/material/iron=10000,/datum/material/gold=100) + construction_time = 100 + category = list("Exosuit Equipment") + +/datum/design/mech_heat_sink + name = "Exosuit Module (Heat Sink)" + desc = "Slows down both heating and cooling." + id = "mech_heat_sink" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/heat_sink + materials = list(/datum/material/iron=10000,/datum/material/plasma=1000) + construction_time = 100 + category = list("Exosuit Equipment") + /datum/design/mech_plasma_cutter name = "Exosuit Mining Design (217-D Heavy Plasma Cutter)" desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles." diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index e72b6813285b..bea5fa507482 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -156,7 +156,7 @@ "atmosalerts", "atmos_control", "recycler", "autolathe", "high_micro_laser", "nano_mani", "mesons", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod", "cell_charger", "stack_console", "stack_machine", "conveyor_belt", "conveyor_switch", "reactor_control", "oxygen_tank", "plasma_tank", "emergency_oxygen", "emergency_oxygen_engi", "plasmaman_tank_belt", "electrolyzer", "floorigniter", "crystallizer", "suit_storage_unit", - "atmos_thermal") + "atmos_thermal", "mech_heat_sink", "mech_passive_cooling") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) /datum/techweb_node/adv_engi @@ -164,7 +164,7 @@ display_name = "Advanced Engineering" description = "Pushing the boundaries of physics, one chainsaw-fist at a time." prereq_ids = list("engineering", "emp_basic") - design_ids = list("engine_goggles", "magboots", "mech_magtreads", "forcefield_projector", "weldingmask", "decontamination_unit", "particle_emitter", "tricorder", "mass_driver") + design_ids = list("engine_goggles", "magboots", "mech_magtreads", "mech_active_cooling", "forcefield_projector", "weldingmask", "decontamination_unit", "particle_emitter", "tricorder", "mass_driver") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) /datum/techweb_node/anomaly diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi index 35bd90f2a64a..65b5b9452b4c 100644 Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index ed1005c60327..b666704624c7 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/yogstation.dme b/yogstation.dme index 1a4b85ecf221..877a55e18dbd 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -100,6 +100,7 @@ #include "code\__DEFINES\maths.dm" #include "code\__DEFINES\matrices.dm" #include "code\__DEFINES\MC.dm" +#include "code\__DEFINES\mecha.dm" #include "code\__DEFINES\melee.dm" #include "code\__DEFINES\menu.dm" #include "code\__DEFINES\misc.dm" @@ -488,6 +489,7 @@ #include "code\controllers\subsystem\processing\fields.dm" #include "code\controllers\subsystem\processing\greyscale.dm" #include "code\controllers\subsystem\processing\instruments.dm" +#include "code\controllers\subsystem\processing\mecha.dm" #include "code\controllers\subsystem\processing\nanites.dm" #include "code\controllers\subsystem\processing\obj.dm" #include "code\controllers\subsystem\processing\plumbing.dm" @@ -1183,11 +1185,13 @@ #include "code\game\mecha\combat\reticence.dm" #include "code\game\mecha\combat\sidewinder.dm" #include "code\game\mecha\equipment\mecha_equipment.dm" +#include "code\game\mecha\equipment\tools\cooling.dm" #include "code\game\mecha\equipment\tools\medical_tools.dm" #include "code\game\mecha\equipment\tools\mining_tools.dm" #include "code\game\mecha\equipment\tools\other_tools.dm" #include "code\game\mecha\equipment\tools\weapon_bay.dm" #include "code\game\mecha\equipment\tools\work_tools.dm" +#include "code\game\mecha\equipment\weapons\armor.dm" #include "code\game\mecha\equipment\weapons\mecha_ammo.dm" #include "code\game\mecha\equipment\weapons\melee_weapons.dm" #include "code\game\mecha\equipment\weapons\other_weapons.dm" diff --git a/yogstation/icons/mob/hud.dmi b/yogstation/icons/mob/hud.dmi index f5584d934a4c..8209c39a91f8 100644 Binary files a/yogstation/icons/mob/hud.dmi and b/yogstation/icons/mob/hud.dmi differ