diff --git a/code/__DEFINES/exosuit_fab.dm b/code/__DEFINES/exosuit_fab.dm index 4cc21f210d6..4fd921bdeb7 100644 --- a/code/__DEFINES/exosuit_fab.dm +++ b/code/__DEFINES/exosuit_fab.dm @@ -35,10 +35,12 @@ #define EXOSUIT_MODULE_MARAUDER (1<<10) /// Module is compatible with Paddy models #define EXOSUIT_MODULE_PADDY (1<<11) +/// Module is compatible with Justice models +#define EXOSUIT_MODULE_JUSTICE (1<<12) /// Module is compatible with "Working" Exosuit models - Ripley and Clarke #define EXOSUIT_MODULE_WORKING (EXOSUIT_MODULE_RIPLEY | EXOSUIT_MODULE_CLARKE) /// Module is compatible with "Combat" Exosuit models - Gygax, H.O.N.K, Durand and Phazon, or any Exosuit with an empty Concealed Weapon Bay -#define EXOSUIT_MODULE_COMBAT (EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON | EXOSUIT_MODULE_SAVANNAH | EXOSUIT_MODULE_RETICENCE | EXOSUIT_MODULE_MARAUDER | EXOSUIT_MODULE_PADDY | EXOSUIT_MODULE_CONCEALED_WEP_BAY) +#define EXOSUIT_MODULE_COMBAT (EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON | EXOSUIT_MODULE_SAVANNAH | EXOSUIT_MODULE_RETICENCE | EXOSUIT_MODULE_MARAUDER | EXOSUIT_MODULE_PADDY | EXOSUIT_MODULE_JUSTICE | EXOSUIT_MODULE_CONCEALED_WEP_BAY) /// Module is compatible with "Medical" Exosuit modelsm - Odysseus #define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS diff --git a/code/__DEFINES/research/research_categories.dm b/code/__DEFINES/research/research_categories.dm index 3f6428eb731..cd7a216bc9c 100644 --- a/code/__DEFINES/research/research_categories.dm +++ b/code/__DEFINES/research/research_categories.dm @@ -134,6 +134,7 @@ #define RND_CATEGORY_MECHFAB_PHAZON "/Phazon" #define RND_CATEGORY_MECHFAB_CLARKE "/Clarke" #define RND_CATEGORY_MECHFAB_SAVANNAH_IVANOV "/Savannah-Ivanov" +#define RND_CATEGORY_MECHFAB_JUSTICE "/Justice" #define RND_SUBCATEGORY_MECHFAB_CHASSIS "/Chassis" #define RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT "/Supported Equipment" #define RND_SUBCATEGORY_MECHFAB_CONTROL_INTERFACES "/Control Interfaces" diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index d132dd53da8..9cb926fd197 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -709,3 +709,29 @@ flags = ANIMATION_RELATIVE, ) return ..() + +/obj/effect/temp_visual/mech_sparks + name = "mech sparks" + icon_state = "mech_sparks" + duration = 0.4 SECONDS + +/obj/effect/temp_visual/mech_sparks/Initialize(mapload, set_color) + . = ..() + pixel_x = rand(-16, 16) + pixel_y = rand(-8, 8) + +/obj/effect/temp_visual/mech_attack_aoe_charge + name = "mech attack aoe charge" + icon = 'icons/effects/96x96.dmi' + icon_state = "mech_attack_aoe_charge" + duration = 1 SECONDS + pixel_x = -32 + pixel_y = -32 + +/obj/effect/temp_visual/mech_attack_aoe_attack + name = "mech attack aoe attack" + icon = 'icons/effects/96x96.dmi' + icon_state = "mech_attack_aoe_attack" + duration = 0.5 SECONDS + pixel_x = -32 + pixel_y = -32 diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 0583269f1c6..f6b12603fab 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -907,6 +907,104 @@ RND_CATEGORY_MECHFAB_SAVANNAH_IVANOV + RND_SUBCATEGORY_MECHFAB_CHASSIS ) +//Justice (emaged only) +/datum/design/justice_chassis + name = "Exosuit Chassis (\"Justice\")" + id = "justice_chassis" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/chassis/justice + materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*20) + construction_time = 10 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + +/datum/design/justice_torso + name = "Exosuit Torso (\"Justice\")" + id = "justice_torso" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/part/justice_torso + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 50, + /datum/material/silver = SHEET_MATERIAL_AMOUNT * 5, + ) + construction_time = 30 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + +/datum/design/justice_left_arm + name = "Exosuit Left Arm (\"Justice\")" + id = "justice_left_arm" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/part/justice_left_arm + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, + /datum/material/silver = SHEET_MATERIAL_AMOUNT * 2, + ) + construction_time = 10 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + +/datum/design/justice_right_arm + name = "Exosuit Right Arm (\"Justice\")" + id = "justice_right_arm" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/part/justice_right_arm + materials = list( + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + /datum/material/silver=SHEET_MATERIAL_AMOUNT*2, + ) + construction_time = 10 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + +/datum/design/justice_left_leg + name = "Exosuit Left Leg (\"Justice\")" + id = "justice_left_leg" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/part/justice_left_leg + materials = list( + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + /datum/material/titanium=SHEET_MATERIAL_AMOUNT*2, + ) + construction_time = 10 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + +/datum/design/justice_right_leg + name = "Exosuit Right Leg (\"Justice\")" + id = "justice_right_leg" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/part/justice_right_leg + materials = list( + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + /datum/material/titanium=SHEET_MATERIAL_AMOUNT*2, + ) + construction_time = 10 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + +/datum/design/justice_armor + name = "Exosuit Armor (\"Justice\")" + id = "justice_armor" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/part/justice_armor + materials = list( + /datum/material/silver=SHEET_MATERIAL_AMOUNT*10, + /datum/material/titanium=SHEET_MATERIAL_AMOUNT*10, + /datum/material/plastic=SHEET_MATERIAL_AMOUNT*5, + /datum/material/diamond=SHEET_MATERIAL_AMOUNT*1, + ) + construction_time = 20 SECONDS + category = list( + RND_CATEGORY_MECHFAB_JUSTICE + RND_SUBCATEGORY_MECHFAB_CHASSIS + ) + //Clarke /datum/design/clarke_chassis name = "Exosuit Chassis (\"Clarke\")" diff --git a/code/modules/research/techweb/_techweb_node.dm b/code/modules/research/techweb/_techweb_node.dm index c36eb886271..7714946a4d2 100644 --- a/code/modules/research/techweb/_techweb_node.dm +++ b/code/modules/research/techweb/_techweb_node.dm @@ -40,6 +40,8 @@ var/list/experiments_to_unlock = list() /// Whether or not this node should show on the wiki var/show_on_wiki = TRUE + /// Hidden Mech nodes unlocked when mech fabricator emaged. + var/illegal_mech_node = FALSE /datum/techweb_node/error_node id = "ERROR" diff --git a/code/modules/research/techweb/nodes/mech_nodes.dm b/code/modules/research/techweb/nodes/mech_nodes.dm index 5f3d3021323..1cb7376c6a9 100644 --- a/code/modules/research/techweb/nodes/mech_nodes.dm +++ b/code/modules/research/techweb/nodes/mech_nodes.dm @@ -194,6 +194,22 @@ ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) +/datum/techweb_node/justice + id = "mecha_justice" + display_name = "EXOSUIT: Justice" + description = "Justice exosuit designs" + design_ids = list( + "justice_armor", + "justice_chassis", + "justice_left_arm", + "justice_left_leg", + "justice_right_arm", + "justice_right_leg", + "justice_torso", + ) + hidden = TRUE + illegal_mech_node = TRUE + /datum/techweb_node/mech_energy_guns id = TECHWEB_NODE_MECH_ENERGY_GUNS display_name = "Mech Energy Guns" diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index 98378a9422a..5e7ba1daba2 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -390,3 +390,4 @@ restricted = TRUE refundable = FALSE purchasable_from = parent_type::purchasable_from & ~UPLINK_SPY + diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 32aa4f1f7a3..d35df312663 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -137,6 +137,15 @@ var/stepsound = 'sound/mecha/mechstep.ogg' ///Sound played when the mech walks var/turnsound = 'sound/mecha/mechturn.ogg' + ///Sounds for types of melee attack + var/brute_attack_sound = 'sound/weapons/punch4.ogg' + var/burn_attack_sound = 'sound/items/welder.ogg' + var/tox_attack_sound = 'sound/effects/spray2.ogg' + ///Sound on wall destroying + var/destroy_wall_sound = 'sound/effects/meteorimpact.ogg' + + ///Melee attack verb + var/list/attack_verbs = list("hit", "hits", "hitting") ///Cooldown duration between melee punches var/melee_cooldown = CLICK_CD_SLOW @@ -151,6 +160,8 @@ var/is_currently_ejecting = FALSE ///Safety for weapons. Won't fire if enabled, and toggled by middle click. var/weapons_safety = FALSE + ///Don't play standard sound when set safety if TRUE. + var/safety_sound_custom = FALSE var/datum/effect_system/fluid_spread/smoke/smoke_system @@ -365,7 +376,8 @@ */ /obj/vehicle/sealed/mecha/proc/set_safety(mob/user) weapons_safety = !weapons_safety - SEND_SOUND(user, sound('sound/machines/beep.ogg', volume = 25)) + if(!safety_sound_custom) + SEND_SOUND(user, sound('sound/machines/beep.ogg', volume = 25)) balloon_alert(user, "equipment [weapons_safety ? "safe" : "ready"]") set_mouse_pointer() SEND_SIGNAL(src, COMSIG_MECH_SAFETIES_TOGGLE, user, weapons_safety) @@ -905,3 +917,9 @@ act.button_icon_state = "mech_lights_off" balloon_alert(occupant, "lights [mecha_flags & LIGHTS_ON ? "on":"off"]") act.build_all_button_icons() + +/obj/vehicle/sealed/mecha/proc/melee_attack_effect(mob/living/victim, heavy) + if(heavy) + victim.Unconscious(2 SECONDS) + else + victim.Knockdown(4 SECONDS) diff --git a/code/modules/vehicles/mecha/combat/justice.dm b/code/modules/vehicles/mecha/combat/justice.dm new file mode 100644 index 00000000000..babdb8af17b --- /dev/null +++ b/code/modules/vehicles/mecha/combat/justice.dm @@ -0,0 +1,535 @@ +#define DISMEMBER_CHANCE_HIGH 50 +#define DISMEMBER_CHANCE_LOW 25 + +#define MOVEDELAY_ANGRY 4.5 +#define MOVEDELAY_SAFETY 2.5 + +/obj/vehicle/sealed/mecha/justice + name = "\improper Justice" + desc = "Black and red syndicate mech designed for execution orders. \ + For safety reasons, the syndicate advises against standing too close." + icon_state = "justice" + base_icon_state = "justice" + movedelay = MOVEDELAY_SAFETY // fast + max_integrity = 200 // but weak + accesses = list(ACCESS_SYNDICATE) + armor_type = /datum/armor/mecha_justice + max_temperature = 40000 + force = 60 // dangerous in melee + damtype = BRUTE + destruction_sleep_duration = 10 + exit_delay = 10 + wreckage = /obj/structure/mecha_wreckage/justice + mech_type = EXOSUIT_MODULE_JUSTICE + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + mecha_flags = ID_LOCK_ON | QUIET_STEPS | QUIET_TURNS | CAN_STRAFE | HAS_LIGHTS | MMI_COMPATIBLE | IS_ENCLOSED + destroy_wall_sound = 'sound/mecha/mech_blade_break_wall.ogg' + brute_attack_sound = 'sound/mecha/mech_blade_attack.ogg' + attack_verbs = list("cut", "cuts", "cutting") + weapons_safety = TRUE + safety_sound_custom = TRUE + max_equip_by_category = list( + MECHA_L_ARM = null, + MECHA_R_ARM = null, + MECHA_UTILITY = 3, + MECHA_POWER = 1, + MECHA_ARMOR = 2, + ) + step_energy_drain = 2 + +/datum/armor/mecha_justice + melee = 30 + bullet = 20 + laser = 20 + energy = 30 + fire = 100 + acid = 100 + +/obj/vehicle/sealed/mecha/justice/Initialize(mapload, built_manually) + . = ..() + RegisterSignal(src, COMSIG_MECHA_MELEE_CLICK, PROC_REF(justice_fatality)) //We do not hit those who are in crit or stun. We are finishing them. + transform = transform.Scale(1.04, 1.04) + +/obj/vehicle/sealed/mecha/justice/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/invisibility) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/charge_attack) + +/obj/vehicle/sealed/mecha/justice/update_icon_state() + . = ..() + if(LAZYLEN(occupants)) + icon_state = weapons_safety ? "[base_icon_state]" : "[base_icon_state]-angry" + if(!has_gravity()) + icon_state = "[icon_state]-fly" + +/obj/vehicle/sealed/mecha/justice/set_safety(mob/user) + . = ..() + if(weapons_safety) + movedelay = MOVEDELAY_SAFETY + else + movedelay = MOVEDELAY_ANGRY + + playsound(src, 'sound/mecha/mech_blade_safty.ogg', 75, FALSE) //everyone need to hear this sound + + update_appearance(UPDATE_ICON_STATE) + +/obj/vehicle/sealed/mecha/justice/Move(newloc, dir) + if(HAS_TRAIT(src, TRAIT_IMMOBILIZED)) + return + . = ..() + update_appearance(UPDATE_ICON_STATE) + +/// Says 1 of 3 epic phrases before attacking and make a finishing blow to targets in stun or crit after 1 SECOND. +/obj/vehicle/sealed/mecha/justice/proc/justice_fatality(datum/source, mob/living/pilot, atom/target, on_cooldown, is_adjacent) + SIGNAL_HANDLER + + if(!ishuman(target)) + return FALSE + var/mob/living/carbon/human/live_or_dead = target + if(live_or_dead.stat < UNCONSCIOUS && live_or_dead.getStaminaLoss() < 100) + return FALSE + var/obj/item/bodypart/check_head = live_or_dead.get_bodypart(BODY_ZONE_HEAD) + if(!check_head) + return FALSE + INVOKE_ASYNC(src, PROC_REF(finish_him), src, pilot, live_or_dead) + return TRUE + +/** + * ## finish_him + * + * Target's head is cut off (if it has one) + * Attack from invisibility and charged attack have higher priority. + * Arguments: + * * finisher - Mech pilot who makes an attack. + * * him - Target at which the mech makes an attack. + */ +/obj/vehicle/sealed/mecha/justice/proc/finish_him(obj/vehicle/sealed/mecha/my_mech, mob/finisher, mob/living/him) + say(pick("Take my Justice-Slash!", "A falling leaf...", "Justice is quite a lonely path"), forced = "Justice Mech") + playsound(src, 'sound/mecha/mech_stealth_pre_attack.ogg', 75, FALSE) + if(!do_after(finisher, 1 SECONDS, him)) + return + if(QDELETED(finisher)) + return + if(QDELETED(him)) + return + if(QDELETED(my_mech)) + return + if(!LAZYLEN(my_mech.occupants)) + return + var/turf/finish_turf = get_step(him, get_dir(my_mech, him)) + var/turf/for_line_turf = get_turf(my_mech) + var/obj/item/bodypart/in_your_head = him.get_bodypart(BODY_ZONE_HEAD) + in_your_head?.dismember(BRUTE) + playsound(src, brute_attack_sound, 75, FALSE) + for_line_turf.Beam(src, icon_state = "mech_charge", time = 8) + forceMove(finish_turf) + +/obj/vehicle/sealed/mecha/justice/melee_attack_effect(mob/living/victim, heavy) + if(!heavy) + victim.Knockdown(4 SECONDS) + return + if(!prob(DISMEMBER_CHANCE_HIGH)) + return + var/obj/item/bodypart/cut_bodypart = victim.get_bodypart(pick(BODY_ZONE_R_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG)) + cut_bodypart?.dismember(BRUTE) + + +/obj/vehicle/sealed/mecha/justice/mob_exit(mob/M, silent, randomstep, forced) + . = ..() + if(alpha == 255) + return + animate(src, alpha = 255, time = 0.5 SECONDS) + playsound(src, 'sound/mecha/mech_stealth_effect.ogg' , 75, FALSE) + +/obj/vehicle/sealed/mecha/justice/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration) + if(LAZYLEN(occupants)) + if(prob(60)) + new /obj/effect/temp_visual/mech_sparks(get_turf(src)) + playsound(src, 'sound/mecha/mech_stealth_effect.ogg' , 75, FALSE) + return + return ..() + +/datum/action/vehicle/sealed/mecha/invisibility + name = "Invisibility" + button_icon_state = "mech_stealth_off" + /// Is invisibility activated. + var/on = FALSE + /// Recharge check. + var/charge = TRUE + /// Varset for invisibility timer + var/invisibility_timer + /// Energy cost to become invisibile + var/energy_cost = 200 + /// Aoe pre attack sound. + var/stealth_pre_attack_sound = 'sound/mecha/mech_stealth_pre_attack.ogg' + /// Aoe attack sound. + var/stealth_attack_sound = 'sound/mecha/mech_stealth_attack.ogg' + +/datum/action/vehicle/sealed/mecha/invisibility/set_chassis(passed_chassis) + . = ..() + RegisterSignal(chassis, COMSIG_MECH_SAFETIES_TOGGLE, PROC_REF(on_toggle_safety)) + +/// update button icon when toggle safety. +/datum/action/vehicle/sealed/mecha/invisibility/proc/on_toggle_safety() + SIGNAL_HANDLER + + build_all_button_icons(UPDATE_BUTTON_STATUS) + +/datum/action/vehicle/sealed/mecha/invisibility/Trigger(trigger_flags) + . = ..() + if(!.) + return + on = !on + if(on) + invisibility_on() + else + invisibility_off() + +/datum/action/vehicle/sealed/mecha/invisibility/IsAvailable(feedback) + . = ..() + if(!.) + return FALSE + if(!chassis.has_charge(energy_cost)) + if(feedback) + owner.balloon_alert(owner, "not enough energy!") + return FALSE + if(chassis.weapons_safety) + if(feedback) + owner.balloon_alert(owner, "safety is on!") + return FALSE + if(!charge) + if(feedback) + owner.balloon_alert(owner, "recharging!") + return FALSE + + return TRUE + +///Called when invisibility activated. +/datum/action/vehicle/sealed/mecha/invisibility/proc/invisibility_on() + new /obj/effect/temp_visual/mech_sparks(get_turf(chassis)) + playsound(chassis, 'sound/mecha/mech_stealth_effect.ogg' , 75, FALSE) + check_charge_attack() + animate(chassis, alpha = 0, time = 0.5 SECONDS) + button_icon_state = "mech_stealth_on" + invisibility_timer = addtimer(CALLBACK(src, PROC_REF(end_stealth)), 20 SECONDS) + RegisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK, PROC_REF(stealth_attack_aoe)) + RegisterSignal(chassis, COMSIG_MOVABLE_BUMP, PROC_REF(bumb_on)) + RegisterSignal(chassis, COMSIG_ATOM_BUMPED, PROC_REF(bumbed_on)) + RegisterSignal(chassis, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(take_damage)) + chassis.use_energy(energy_cost) + build_all_button_icons() + +///Called when invisibility deactivated. +/datum/action/vehicle/sealed/mecha/invisibility/proc/invisibility_off() + new /obj/effect/temp_visual/mech_sparks(get_turf(chassis)) + playsound(chassis, 'sound/mecha/mech_stealth_effect.ogg' , 75, FALSE) + invisibility_timer = null + charge = FALSE + addtimer(CALLBACK(src, PROC_REF(charge)), 5 SECONDS) + button_icon_state = "mech_stealth_cooldown" + animate(chassis, alpha = 255, time = 0.5 SECONDS) + UnregisterSignal(chassis, list( + COMSIG_MECHA_MELEE_CLICK, + COMSIG_MOVABLE_BUMP, + COMSIG_ATOM_BUMPED, + COMSIG_ATOM_TAKE_DAMAGE + )) + build_all_button_icons() + +///Check if mech use charge attack and deactivate it when we activate invisibility. +/datum/action/vehicle/sealed/mecha/invisibility/proc/check_charge_attack() + for(var/mob/living/occupant in chassis.occupants) + var/datum/action/vehicle/sealed/mecha/charge_attack/charge_action = LAZYACCESSASSOC(chassis.occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/charge_attack) + if(charge_action?.on) + charge_action.on = !on + charge_action.charge_attack_off() +/** + * ## end_stealth + * + * Called when mech runs out of invisibility time. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/end_stealth() + make_visible() + +/** + * ## bumb_on + * + * Called when mech bumb on somthing. If is living somthing shutdown mech invisibility. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/bumb_on(obj/vehicle/sealed/mecha/our_mech, atom/obstacle) + SIGNAL_HANDLER + + if(!isliving(obstacle)) + return + make_visible() + +/** + * ## bumbed_on + * + * Called when somthing bumbed on mech. If is living somthing shutdown mech invisibility. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/bumbed_on(obj/vehicle/sealed/mecha/our_mech, atom/movable/bumped_atom) + SIGNAL_HANDLER + + if(!isliving(bumped_atom)) + return + make_visible() + +/** + * ## take_damage + * + * Called when mech take damage. Shutdown mech invisibility. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/take_damage(obj/vehicle/sealed/mecha/our_mech) + SIGNAL_HANDLER + + make_visible() + +/** + * ## make_visible + * + * Called when somthing force invisibility shutdown. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/make_visible() + if(!on) + return + on = !on + invisibility_off() + +/** + * Proc makes an AOE attack after 1 SECOND. + * Called by the mech pilot when he is in stealth mode and wants to attack. + * During this, mech cannot move. +*/ +/datum/action/vehicle/sealed/mecha/invisibility/proc/stealth_attack_aoe(datum/source, mob/living/pilot, atom/target, on_cooldown, is_adjacent) + SIGNAL_HANDLER + + if(!charge) + return FALSE + if(chassis.alpha != 0) + UnregisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK) + return FALSE + UnregisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK) + new /obj/effect/temp_visual/mech_attack_aoe_charge(get_turf(chassis)) + ADD_TRAIT(chassis, TRAIT_IMMOBILIZED, REF(src)) + playsound(chassis, stealth_pre_attack_sound, 75, FALSE) + addtimer(CALLBACK(src, PROC_REF(attack_in_aoe), pilot), 1 SECONDS) + return TRUE + +/** + * ## attack_in_aoe + * + * Brings mech out of invisibility. + * Deal everyone in range 3x3 35 damage and 25 chanse to cut off limb. + * Arguments: + * * pilot - occupant inside mech. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/attack_in_aoe(mob/living/pilot) + invisibility_off() + new /obj/effect/temp_visual/mech_attack_aoe_attack(get_turf(chassis)) + for(var/mob/living/something_living in range(1, get_turf(chassis))) + if(something_living.stat >= UNCONSCIOUS) + continue + if(something_living.getStaminaLoss() >= 100) + continue + if(something_living == pilot) + continue + if(prob(DISMEMBER_CHANCE_LOW)) + var/obj/item/bodypart/cut_bodypart = something_living.get_bodypart(pick(BODY_ZONE_R_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG)) + cut_bodypart?.dismember(BRUTE) + something_living.apply_damage(35, BRUTE) + playsound(chassis, stealth_attack_sound, 75, FALSE) + REMOVE_TRAIT(chassis, TRAIT_IMMOBILIZED, REF(src)) + on = !on + charge = FALSE + button_icon_state = "mech_stealth_cooldown" + build_all_button_icons() + addtimer(CALLBACK(src, PROC_REF(charge)), 5 SECONDS) + +/** + * ## charge + * + * Recharge invisibility action after 5 SECONDS. + */ +/datum/action/vehicle/sealed/mecha/invisibility/proc/charge() + button_icon_state = "mech_stealth_off" + charge = TRUE + build_all_button_icons() + +/datum/action/vehicle/sealed/mecha/charge_attack + name = "Charge Attack" + button_icon_state = "mech_charge_off" + /// Is charge attack activated. + var/on = FALSE + /// Recharge check. + var/charge = TRUE + /// Energy cost to perform charge attack + var/energy_cost = 400 + /// Maximum range of charge attack. + var/max_charge_range = 7 + /// Sound when mech do charge attack. + var/charge_attack_sound = 'sound/mecha/mech_charge_attack.ogg' + +/datum/action/vehicle/sealed/mecha/charge_attack/set_chassis(passed_chassis) + . = ..() + RegisterSignal(chassis, COMSIG_MECH_SAFETIES_TOGGLE, PROC_REF(on_toggle_safety)) + +/// update button icon when toggle safety. +/datum/action/vehicle/sealed/mecha/charge_attack/proc/on_toggle_safety() + SIGNAL_HANDLER + + build_all_button_icons(UPDATE_BUTTON_STATUS) + +/datum/action/vehicle/sealed/mecha/charge_attack/Trigger(trigger_flags) + . = ..() + if(!.) + return + on = !on + if(on) + charge_attack_on() + else + charge_attack_off() + +/datum/action/vehicle/sealed/mecha/charge_attack/IsAvailable(feedback) + . = ..() + if(!.) + return FALSE + if(!chassis.has_charge(energy_cost)) + if(feedback) + owner.balloon_alert(owner, "not enough energy!") + return FALSE + if(chassis.weapons_safety) + if(feedback) + owner.balloon_alert(owner, "safety is on!") + return FALSE + if(!charge) + if(feedback) + owner.balloon_alert(owner, "recharging!") + return FALSE + + return TRUE + +///Called when charge attack activated +/datum/action/vehicle/sealed/mecha/charge_attack/proc/charge_attack_on() + check_visability() + button_icon_state = "mech_charge_on" + RegisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK, PROC_REF(click_try_charge)) + build_all_button_icons() + +///Called when charge attack deactivated +/datum/action/vehicle/sealed/mecha/charge_attack/proc/charge_attack_off() + button_icon_state = "mech_charge_off" + UnregisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK) + build_all_button_icons() + +///Check if mech use invisibility and deactivate it when we activate charge attack. +/datum/action/vehicle/sealed/mecha/charge_attack/proc/check_visability() + for(var/who_inside in chassis.occupants) + var/mob/living/occupant = who_inside + var/datum/action/vehicle/sealed/mecha/invisibility/stealth_action = LAZYACCESSASSOC(chassis.occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/invisibility) + if(stealth_action?.on) + stealth_action.make_visible() + +///Called when mech attacks with charge attack enabled. +/datum/action/vehicle/sealed/mecha/charge_attack/proc/click_try_charge(datum/source, mob/living/pilot, atom/target, on_cooldown, is_adjacent) + SIGNAL_HANDLER + + var/turf = get_turf(target) + if(!on) + UnregisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK) + return FALSE + if(isnull(turf)) + pilot.balloon_alert(pilot, "invalid direction!") + return FALSE + if(!charge) + pilot.balloon_alert(pilot, "recharging!") + return FALSE + else + if(charge_attack(pilot, turf)) + return TRUE + return FALSE + +/** + * ## charge_attack + * + * Deal everyone in line for mech location to mouse location 35 damage and 25 chanse to cut off limb. + * Teleport mech to the end of line. + * Arguments: + * * charger - occupant inside mech. + * * target - occupant inside mech. + */ +/datum/action/vehicle/sealed/mecha/charge_attack/proc/charge_attack(mob/living/charger, turf/target) + var/turf/start_charge_here = get_turf(charger) + var/charge_range = min(get_dist_euclidean(start_charge_here, target), max_charge_range) + var/turf/but_we_gonna_here = get_ranged_target_turf(start_charge_here, get_dir(start_charge_here, target), floor(charge_range)) + var/turf/here_we_go = start_charge_here + for(var/turf/line_turf in get_line(get_step(start_charge_here, get_dir(start_charge_here, target)), but_we_gonna_here)) + if(get_turf(charger) == get_turf(line_turf)) + continue + if(isclosedturf(line_turf)) + break + var/obj/machinery/power/supermatter_crystal/funny_crystal = locate() in line_turf + if(funny_crystal) + funny_crystal.Bumped(chassis) + break + var/obj/machinery/door/airlock/like_a_wall = locate() in line_turf + if(like_a_wall?.density) + break + if(locate(/obj/structure/window) in line_turf) + break + for(var/mob/living/something_living in line_turf.contents) + if(something_living.stat >= UNCONSCIOUS || something_living.getStaminaLoss() >= 100 || something_living == charger) + continue + if(prob(DISMEMBER_CHANCE_LOW)) + var/obj/item/bodypart/cut_bodypart = something_living.get_bodypart(pick(BODY_ZONE_R_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_HEAD)) + cut_bodypart?.dismember(BRUTE) + something_living.apply_damage(35, BRUTE) + here_we_go = line_turf + + // If the mech didn't move, it didn't charge + if(here_we_go == start_charge_here) + charger.balloon_alert(charger, "invalid direction!") + return FALSE + chassis.forceMove(here_we_go) + start_charge_here.Beam(chassis, icon_state = "mech_charge", time = 8) + playsound(chassis, charge_attack_sound, 75, FALSE) + on = !on + chassis.use_energy(energy_cost) + UnregisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK) + charge = FALSE + button_icon_state = "mech_charge_cooldown" + build_all_button_icons() + addtimer(CALLBACK(src, PROC_REF(charge)), 5 SECONDS) + return TRUE + +/** + * ## charge + * + * Recharge charge attack action after 5 SECONDS. + */ +/datum/action/vehicle/sealed/mecha/charge_attack/proc/charge() + charge = TRUE + button_icon_state = "mech_charge_off" + build_all_button_icons() + +/obj/vehicle/sealed/mecha/justice/loaded + equip_by_category = list( + MECHA_L_ARM = null, + MECHA_R_ARM = null, + MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/radio, /obj/item/mecha_parts/mecha_equipment/air_tank/full, /obj/item/mecha_parts/mecha_equipment/thrusters/ion), + MECHA_POWER = list(), + MECHA_ARMOR = list(), + ) + +/obj/vehicle/sealed/mecha/justice/loaded/populate_parts() + cell = new /obj/item/stock_parts/power_store/cell/bluespace(src) + scanmod = new /obj/item/stock_parts/scanning_module/triphasic(src) + capacitor = new /obj/item/stock_parts/capacitor/quadratic(src) + servo = new /obj/item/stock_parts/servo/femto(src) + update_part_values() + +#undef DISMEMBER_CHANCE_HIGH +#undef DISMEMBER_CHANCE_LOW + +#undef MOVEDELAY_ANGRY +#undef MOVEDELAY_SAFETY diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index 33edb9e47c7..e2a6359bb42 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -52,10 +52,14 @@ //looping sound for printing items var/datum/looping_sound/lathe_print/print_sound + /// Local designs that only this mechfab have(using when mechfab emaged so it's illegal designs). + var/list/datum/design/illegal_local_designs + /obj/machinery/mecha_part_fabricator/Initialize(mapload) print_sound = new(src, FALSE) rmat = AddComponent(/datum/component/remote_materials, mapload && link_on_init) cached_designs = list() + illegal_local_designs = list() RefreshParts() //Recalculating local material sizes if the fab isn't linked return ..() @@ -142,6 +146,26 @@ balloon_alert(user, "rotated to [dir2text(dir)].") return CLICK_ACTION_SUCCESS +/obj/machinery/mecha_part_fabricator/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + if(user.job != JOB_ROBOTICIST) + to_chat(user, span_warning("You clicking and typing but don’t understand what to do with it")) + return FALSE + obj_flags |= EMAGGED + for(var/found_illegal_mech_nods in SSresearch.techweb_nodes) + var/datum/techweb_node/illegal_mech_node = SSresearch.techweb_nodes[found_illegal_mech_nods] + if(!illegal_mech_node?.illegal_mech_node) + continue + for(var/id in illegal_mech_node.design_ids) + var/datum/design/illegal_mech_design = SSresearch.techweb_design_by_id(id) + illegal_local_designs |= illegal_mech_design + cached_designs |= illegal_mech_design + say("R$c!i&ed ERROR de#i$ns. C@n%ec$%ng to ~NULL~ se%ve$s.") + playsound(src, 'sound/machines/uplinkerror.ogg', 50, TRUE) + update_static_data_for_all_viewers() + return TRUE + /** * Updates the `final_sets` and `buildable_parts` for the current mecha fabricator. */ @@ -418,7 +442,7 @@ if(!istext(design_id)) continue - if(!stored_research.researched_designs.Find(design_id)) + if(!(stored_research.researched_designs.Find(design_id) || is_type_in_list(SSresearch.techweb_design_by_id(design_id), illegal_local_designs))) continue var/datum/design/design = SSresearch.techweb_design_by_id(design_id) diff --git a/code/modules/vehicles/mecha/mech_melee_attack.dm b/code/modules/vehicles/mecha/mech_melee_attack.dm index d88aaaeb8c8..655a2f35339 100644 --- a/code/modules/vehicles/mecha/mech_melee_attack.dm +++ b/code/modules/vehicles/mecha/mech_melee_attack.dm @@ -21,15 +21,15 @@ mecha_attacker.do_attack_animation(src) switch(mecha_attacker.damtype) if(BRUTE) - playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) + playsound(src, mecha_attacker.brute_attack_sound, 50, TRUE) if(BURN) - playsound(src, 'sound/items/welder.ogg', 50, TRUE) + playsound(src, mecha_attacker.burn_attack_sound, 50, TRUE) else return 0 mecha_attacker.visible_message(span_danger("[mecha_attacker] hits [src]!"), span_danger("You hit [src]!"), null, COMBAT_MESSAGE_RANGE) if(prob(hardness + mecha_attacker.force) && mecha_attacker.force > 20) dismantle_wall(1) - playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) + playsound(src, mecha_attacker.destroy_wall_sound, 100, TRUE) else add_dent(WALL_DENT_HIT) ..() @@ -58,9 +58,9 @@ mecha_attacker.do_attack_animation(src) switch(mecha_attacker.damtype) if(BRUTE) - playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) + playsound(src, mecha_attacker.brute_attack_sound, 50, TRUE) if(BURN) - playsound(src, 'sound/items/welder.ogg', 50, TRUE) + playsound(src, mecha_attacker.burn_attack_sound, 50, TRUE) else return 0 mecha_attacker.visible_message(span_danger("[mecha_attacker] hits [src]!"), span_danger("You hit [src]!"), null, COMBAT_MESSAGE_RANGE) @@ -88,29 +88,34 @@ if(mecha_attacker.damtype == BRUTE) step_away(src, mecha_attacker, 15) var/obj/item/bodypart/selected_zone = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD)) - if(selected_zone) - var/dmg = rand(mecha_attacker.force * 0.5, mecha_attacker.force) - switch(mecha_attacker.damtype) - if(BRUTE) - if(mecha_attacker.force > 35) // durand and other heavy mechas - Unconscious(20) - else if(mecha_attacker.force > 20 && !IsKnockdown()) // lightweight mechas like gygax - Knockdown(40) + var/dmg = rand(mecha_attacker.force * 0.5, mecha_attacker.force) + switch(mecha_attacker.damtype) + if(BRUTE) + if(mecha_attacker.force > 35) // durand and other heavy mechas + mecha_attacker.melee_attack_effect(src, heavy = TRUE) + else if(mecha_attacker.force > 20 && !IsKnockdown()) // lightweight mechas like gygax + mecha_attacker.melee_attack_effect(src, heavy = FALSE) + if(selected_zone) selected_zone.receive_damage(dmg, 0, updating_health = TRUE) - playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) - if(FIRE) - selected_zone.receive_damage(0, dmg, updating_health = TRUE) - playsound(src, 'sound/items/welder.ogg', 50, TRUE) - if(TOX) - playsound(src, 'sound/effects/spray2.ogg', 50, TRUE) - if((reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + mecha_attacker.force) < mecha_attacker.force*2) - reagents.add_reagent(/datum/reagent/cryptobiolin, mecha_attacker.force/2) - if((reagents.get_reagent_amount(/datum/reagent/toxin) + mecha_attacker.force) < mecha_attacker.force*2) - reagents.add_reagent(/datum/reagent/toxin, mecha_attacker.force/2.5) else - return 0 - . = dmg - visible_message(span_danger("[mecha_attacker.name] hits [src]!"), \ - span_userdanger("[mecha_attacker.name] hits you!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, list(mecha_attacker)) - to_chat(mecha_attacker, span_danger("You hit [src]!")) + apply_damage(dmg, BRUTE) + playsound(src, mecha_attacker.brute_attack_sound, 50, TRUE) + if(FIRE) + if(selected_zone) + selected_zone.receive_damage(0, dmg, updating_health = TRUE) + else + apply_damage(dmg, BURN) + playsound(src, mecha_attacker.burn_attack_sound, 50, TRUE) + if(TOX) + playsound(src, mecha_attacker.tox_attack_sound, 50, TRUE) + if((reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + mecha_attacker.force) < mecha_attacker.force*2) + reagents.add_reagent(/datum/reagent/cryptobiolin, mecha_attacker.force/2) + if((reagents.get_reagent_amount(/datum/reagent/toxin) + mecha_attacker.force) < mecha_attacker.force*2) + reagents.add_reagent(/datum/reagent/toxin, mecha_attacker.force/2.5) + else + return 0 + . = dmg + visible_message(span_danger("[mecha_attacker.name] [mecha_attacker.attack_verbs[1]] [src]!"), \ + span_userdanger("[mecha_attacker.name] [mecha_attacker.attack_verbs[2]] you!"), span_hear("You hear a sickening sound of flesh [mecha_attacker.attack_verbs[3]] flesh!"), COMBAT_MESSAGE_RANGE, list(mecha_attacker)) + to_chat(mecha_attacker, span_danger("You [mecha_attacker.attack_verbs[1]] [src]!")) ..() diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm index f4b1a679596..0a305a5db66 100644 --- a/code/modules/vehicles/mecha/mecha_construction_paths.dm +++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm @@ -819,3 +819,39 @@ outer_plating = /obj/item/stack/sheet/plasteel outer_plating_amount = 5 + +//Justice +/datum/component/construction/unordered/mecha_chassis/justice + result = /datum/component/construction/mecha/justice + steps = list( + /obj/item/mecha_parts/part/justice_torso, + /obj/item/mecha_parts/part/justice_left_arm, + /obj/item/mecha_parts/part/justice_right_arm, + /obj/item/mecha_parts/part/justice_left_leg, + /obj/item/mecha_parts/part/justice_right_leg + ) + +/datum/component/construction/mecha/justice + result = /obj/vehicle/sealed/mecha/justice + base_icon = "justice" + + inner_plating = /obj/item/stack/telecrystal + inner_plating_amount = 8 + + outer_plating = /obj/item/mecha_parts/part/justice_armor + outer_plating_amount = 1 + +/datum/component/construction/mecha/justice/get_circuit_steps() + return list() + +/datum/component/construction/mecha/justice/get_inner_plating_steps() + return list( + list( + "key" = inner_plating, + "amount" = inner_plating_amount, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The power cell is secured, and [inner_plating_amount] telecrystals can be added.", + "forward_message" = "added telecrystal", + "backward_message" = "unsecured power cell" + ) + ) diff --git a/code/modules/vehicles/mecha/mecha_parts.dm b/code/modules/vehicles/mecha/mecha_parts.dm index 7fcee209259..474716568eb 100644 --- a/code/modules/vehicles/mecha/mecha_parts.dm +++ b/code/modules/vehicles/mecha/mecha_parts.dm @@ -332,6 +332,42 @@ desc="Savannah-Ivanov armor plates. They are uniquely shaped and reinforced to deal with the stresses of two pilots, grandiose leaps, and missiles." icon_state = "savannah_ivanov_armor" +// Justice + +/obj/item/mecha_parts/chassis/justice + name = "\improper Justice chassis" + construct_type = /datum/component/construction/unordered/mecha_chassis/justice + +/obj/item/mecha_parts/part/justice_torso + name="\improper Justice torso" + desc="A Justice torso part." + icon_state = "justice_torso" + +/obj/item/mecha_parts/part/justice_left_arm + name="\improper Justice left arm" + desc="A Justice left arm." + icon_state = "justice_l_arm" + +/obj/item/mecha_parts/part/justice_right_arm + name="\improper Justice right arm" + desc="A Justice left arm." + icon_state = "justice_r_arm" + +/obj/item/mecha_parts/part/justice_left_leg + name="\improper Justice left leg" + desc="A Justice left leg." + icon_state = "justice_l_leg" + +/obj/item/mecha_parts/part/justice_right_leg + name="\improper Justice right leg" + desc="A Justice left leg." + icon_state = "justice_r_leg" + +/obj/item/mecha_parts/part/justice_armor + name="Justice armor" + desc="Justice armor plates." + icon_state = "justice_armor" + ///////// Circuitboards /obj/item/circuitboard/mecha diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm index 712d5f0d712..1113a853813 100644 --- a/code/modules/vehicles/mecha/mecha_ui.dm +++ b/code/modules/vehicles/mecha/mecha_ui.dm @@ -111,16 +111,17 @@ var/module_index = 0 for(var/category in max_equip_by_category) var/max_per_category = max_equip_by_category[category] - for(var/i = 1 to max_per_category) - var/equipment = equip_by_category[category] - var/is_slot_free = islist(equipment) ? i > length(equipment) : isnull(equipment) - if(is_slot_free) - data += list(list( - "slot" = category - )) - if(ui_selected_module_index == module_index) - ui_selected_module_index = null - else + if(max_per_category) + for(var/i = 1 to max_per_category) + var/equipment = equip_by_category[category] + var/is_slot_free = islist(equipment) ? i > length(equipment) : isnull(equipment) + if(is_slot_free) + data += list(list( + "slot" = category + )) + if(ui_selected_module_index == module_index) + ui_selected_module_index = null + continue var/obj/item/mecha_parts/mecha_equipment/module = islist(equipment) ? equipment[i] : equipment data += list(list( "slot" = category, @@ -140,7 +141,7 @@ )) if(isnull(ui_selected_module_index)) ui_selected_module_index = module_index - module_index++ + module_index++ return data /obj/vehicle/sealed/mecha/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) diff --git a/code/modules/vehicles/mecha/mecha_wreckage.dm b/code/modules/vehicles/mecha/mecha_wreckage.dm index dc0414e8606..8f972ef4781 100644 --- a/code/modules/vehicles/mecha/mecha_wreckage.dm +++ b/code/modules/vehicles/mecha/mecha_wreckage.dm @@ -245,3 +245,8 @@ /obj/item/mecha_parts/part/odysseus_right_arm, /obj/item/mecha_parts/part/odysseus_left_leg, /obj/item/mecha_parts/part/odysseus_right_leg) + +/obj/structure/mecha_wreckage/justice + name = "\improper Justice wreckage" + icon_state = "justice-broken" + welder_salvage = list(/obj/item/stack/sheet/iron, /obj/item/stack/rods) diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 31f26c3e6e1..38921a6e484 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index fd7bee8ed60..ae668b0495a 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 67b8ea51c18..9ff653047dd 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/actions/actions_mecha.dmi b/icons/mob/actions/actions_mecha.dmi index 7c659ca3b57..60df1b5ed1a 100644 Binary files a/icons/mob/actions/actions_mecha.dmi and b/icons/mob/actions/actions_mecha.dmi differ diff --git a/icons/mob/rideables/mech_construct.dmi b/icons/mob/rideables/mech_construct.dmi index c25eb971f2e..656322b8187 100644 Binary files a/icons/mob/rideables/mech_construct.dmi and b/icons/mob/rideables/mech_construct.dmi differ diff --git a/icons/mob/rideables/mech_construction.dmi b/icons/mob/rideables/mech_construction.dmi index f26dbe17fd0..6e1cdbc3a2d 100644 Binary files a/icons/mob/rideables/mech_construction.dmi and b/icons/mob/rideables/mech_construction.dmi differ diff --git a/icons/mob/rideables/mecha.dmi b/icons/mob/rideables/mecha.dmi index 0c0f62de4d2..5960d054137 100644 Binary files a/icons/mob/rideables/mecha.dmi and b/icons/mob/rideables/mecha.dmi differ diff --git a/sound/mecha/mech_blade_attack.ogg b/sound/mecha/mech_blade_attack.ogg new file mode 100644 index 00000000000..f6c9274762b Binary files /dev/null and b/sound/mecha/mech_blade_attack.ogg differ diff --git a/sound/mecha/mech_blade_break_wall.ogg b/sound/mecha/mech_blade_break_wall.ogg new file mode 100644 index 00000000000..cec9c7a667c Binary files /dev/null and b/sound/mecha/mech_blade_break_wall.ogg differ diff --git a/sound/mecha/mech_blade_safty.ogg b/sound/mecha/mech_blade_safty.ogg new file mode 100644 index 00000000000..80e06388127 Binary files /dev/null and b/sound/mecha/mech_blade_safty.ogg differ diff --git a/sound/mecha/mech_charge_attack.ogg b/sound/mecha/mech_charge_attack.ogg new file mode 100644 index 00000000000..b6d202c8e26 Binary files /dev/null and b/sound/mecha/mech_charge_attack.ogg differ diff --git a/sound/mecha/mech_stealth_attack.ogg b/sound/mecha/mech_stealth_attack.ogg new file mode 100644 index 00000000000..e12ff890c7d Binary files /dev/null and b/sound/mecha/mech_stealth_attack.ogg differ diff --git a/sound/mecha/mech_stealth_effect.ogg b/sound/mecha/mech_stealth_effect.ogg new file mode 100644 index 00000000000..b7a5a513308 Binary files /dev/null and b/sound/mecha/mech_stealth_effect.ogg differ diff --git a/sound/mecha/mech_stealth_pre_attack.ogg b/sound/mecha/mech_stealth_pre_attack.ogg new file mode 100644 index 00000000000..15b2c04ab5c Binary files /dev/null and b/sound/mecha/mech_stealth_pre_attack.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 33bc6c0ab92..e5ee93c81f3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6101,6 +6101,7 @@ #include "code\modules\vehicles\mecha\combat\durand.dm" #include "code\modules\vehicles\mecha\combat\gygax.dm" #include "code\modules\vehicles\mecha\combat\honker.dm" +#include "code\modules\vehicles\mecha\combat\justice.dm" #include "code\modules\vehicles\mecha\combat\marauder.dm" #include "code\modules\vehicles\mecha\combat\phazon.dm" #include "code\modules\vehicles\mecha\combat\reticence.dm"