diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 7f229590013..6a7ed02f7bf 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -67,6 +67,9 @@ #define COMSIG_MOVABLE_Z_CHANGED "movable_z_moved" //from atom/movable/Move and forceMove): (oldz, newz) #define COMSIG_MOVABLE_PREMOVE "moveable_boutta_move" +#define COMSIG_ATTEMPT_PULLING "attempt_pulling" + #define COMSIG_PULL_CANCEL (1<<0) + // /mob signals #define COMSIG_MOB_LIFE "mob_life" //from mob/Life() #define COMSIG_MOB_LOGIN "mob_login" //from mob/Login() diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 085a2797f75..bdea8016c83 100755 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -124,7 +124,7 @@ return 1 if(in_throw_mode) - if(isturf(A) || isturf(A.loc)) + if(isturf(A) || isturf(A.loc) && isturf(loc)) throw_item(A) return 1 throw_mode_off() diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index bf0fa7a49b8..b999aee03c6 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -200,6 +200,7 @@ var/list/target_procs = (procs[target] ||= list()) var/list/lookup = (target.comp_lookup ||= list()) + if(!override && target_procs[signal_type]) var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Proc: [proctype]" //log_signal(override_message) diff --git a/code/datums/movement/mob.dm b/code/datums/movement/mob.dm index 6e2ba7fa6ce..4d348bbd4f2 100755 --- a/code/datums/movement/mob.dm +++ b/code/datums/movement/mob.dm @@ -268,6 +268,12 @@ else M.stop_pulling() + if(istype(mob.loc, /obj/item/mech_equipment/forklifting_system)) + if(mover == mob && isliving(mob)) + mob:resist() + return MOVEMENT_STOP + + return MOVEMENT_PROCEED diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index 85110919d66..cfe262016f2 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -145,7 +145,11 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" var/mob/living/L = usr if(CanUse(L) && href_list["action"]) var/obj/item/I = L.get_active_hand() - holder.add_hiddenprint(L) + if(!ismech(L.loc)) + holder.add_hiddenprint(L) + else + var/mob/living/exosuit/mech = L.loc + I = mech.get_active_hand() if(href_list["cut"]) // Toggles the cut/mend status if (!istype(I)) return diff --git a/code/game/atoms.dm b/code/game/atoms.dm index fe7d94739c7..043ba3acf83 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -649,7 +649,7 @@ its easier to just keep the beam vertical. /atom/movable/proc/fall_impact(turf/from, turf/dest) //If atom stands under open space, it can prevent fall, or not -/atom/proc/can_prevent_fall() +/atom/proc/can_prevent_fall(above, atom/movable/thing) return FALSE // Show a message to all mobs and objects in sight of this atom diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 6946ff4d385..b3cd1833cc3 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -53,8 +53,8 @@ GLOB.all_doors -= src ..() -/obj/machinery/door/can_prevent_fall() - return density +/obj/machinery/door/can_prevent_fall(above) + return above ? density : null /obj/machinery/door/attack_generic(mob/user, var/damage) if(damage >= resistance) diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index c920cc018de..f55105c31fb 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -91,5 +91,5 @@ return -/obj/structure/catwalk/can_prevent_fall() - return FALSE +/obj/structure/catwalk/can_prevent_fall(above) + return above ? FALSE : TRUE diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 5236cf9b3b7..eff2df7b10f 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -42,8 +42,8 @@ var/store_mobs = 1 var/old_chance = 0 //Chance to have rusted closet content in it, from 0 to 100. Keep in mind that chance increases in maints -/obj/structure/closet/can_prevent_fall() - return TRUE +/obj/structure/closet/can_prevent_fall(above) + return above ? TRUE : FALSE /obj/structure/closet/Initialize(mapload) ..() @@ -350,6 +350,10 @@ //Empty gripper attacks will call attack_AI return FALSE + /// So mechs dont open these when attacking. + if(istype(I, /obj/item/mech_equipment/forklifting_system)) + return FALSE + var/list/usable_qualities = list(QUALITY_WELDING) if(opened) usable_qualities += QUALITY_SAWING diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 11b79502719..469fdd9493b 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -81,5 +81,5 @@ return -/obj/structure/lattice/can_prevent_fall() - return TRUE +/obj/structure/lattice/can_prevent_fall(above) + return above ? FALSE : TRUE diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 3c8f5da4ce5..10502621d96 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -24,8 +24,8 @@ atmos_canpass = CANPASS_PROC -/obj/structure/window/can_prevent_fall() - return !is_fulltile() +/obj/structure/window/can_prevent_fall(above) + return above ? !is_fulltile() : FALSE /obj/structure/window/get_fall_damage(var/turf/from, var/turf/dest) var/damage = health * 0.4 * get_health_ratio() @@ -357,7 +357,7 @@ proc/end_grab_onto(mob/living/user, mob/living/target) usable_qualities.Add(QUALITY_SEALING) //If you set intent to harm, you can hit the window with tools to break it. Set to any other intent to use tools on it - if (usr.a_intent != I_HURT) + if (user.a_intent != I_HURT) var/tool_type = I.get_tool_type(user, usable_qualities, src) switch(tool_type) if(QUALITY_SEALING) diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index 397b0b21bac..6b93f1a8afa 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -97,7 +97,10 @@ return //get the user's location - if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such + if(!istype(user.loc, /turf)) + if(!(ismech(user.loc) && istype(I, /obj/item/tool/mech_kit))) + return + if(I) radiate() diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index e42111baf92..3d0b90fecc2 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -113,6 +113,15 @@ var/list/name_to_material var/explosion_resistance = 5 // Only used by walls currently. var/conductive = 1 // Objects with this var add CONDUCTS to flags on spawn. var/list/composite_material // If set, object matter var will be a list containing these values. + /// Armor values for this material whenever its applied on something. + var/datum/armor/armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 1, + bio = 1, + rad = 1 + ) // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods. var/created_window @@ -258,6 +267,16 @@ var/list/name_to_material hardness = 80 stack_origin_tech = list(TECH_MATERIAL = 5) door_icon_base = "stone" + // it is a metal and it does conduct , but it does very poorly + conductive = FALSE + armor = list( + melee = 6, + bullet = 6, + energy = 10, + bomb = 25, + bio = 25, + rad = 0 + ) /material/diamond name = MATERIAL_DIAMOND @@ -271,6 +290,14 @@ var/list/name_to_material hardness = 100 weight = 50 stack_origin_tech = list(TECH_MATERIAL = 6) + armor = list( + melee = 15, + bullet = 15, + energy = 0, + bomb = 80, + bio = 0, + rad = 0 + ) /material/gold name = MATERIAL_GOLD @@ -281,10 +308,28 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 4) sheet_singular_name = "ingot" sheet_plural_name = "ingots" + conductive = TRUE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 1, + bio = 45, + rad = 1 + ) /material/gold/bronze //placeholder for ashtrays name = "bronze" icon_colour = "#EDD12F" + conductive = TRUE + armor = list( + melee = 2, + bullet = 2, + energy = 3, + bomb = 10, + bio = 30, + rad = 0 + ) /material/silver name = MATERIAL_SILVER @@ -295,6 +340,15 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 3) sheet_singular_name = "ingot" sheet_plural_name = "ingots" + conductive = TRUE + armor = list( + melee = 2, + bullet = 2, + energy = 2, + bomb = 10, + bio = 80, + rad = 0 + ) /material/plasma name = MATERIAL_PLASMA @@ -309,6 +363,15 @@ var/list/name_to_material door_icon_base = "stone" sheet_singular_name = "crystal" sheet_plural_name = "crystals" + conductive = TRUE + armor = list( + melee = 1, + bullet = 1, + energy = 6, + bomb = 1, + bio = 80, + rad = 45 + ) /* // Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately. @@ -339,6 +402,15 @@ var/list/name_to_material door_icon_base = "stone" sheet_singular_name = "brick" sheet_plural_name = "bricks" + conductive = FALSE + armor = list( + melee = 2, + bullet = 0, + energy = 1, + bomb = 25, + bio = 0, + rad = 0 + ) /material/stone/marble name = MATERIAL_MARBLE @@ -358,12 +430,30 @@ var/list/name_to_material icon_reinf = "reinf_over" icon_colour = PLASTEEL_COLOUR hitsound = 'sound/weapons/genhit.ogg' + conductive = TRUE + armor = list( + melee = 5, + bullet = 5, + energy = 5, + bomb = 35, + bio = 0, + rad = 0 + ) /material/steel/holographic name = "holo" + MATERIAL_STEEL display_name = MATERIAL_STEEL stack_type = null shard_type = SHARD_NONE + // wish.com steel + armor = list( + melee = 0, + bullet = 0, + energy = 0, + bomb = 0, + bio = 0, + rad = 0 + ) /material/plasteel name = MATERIAL_PLASTEEL @@ -377,7 +467,16 @@ var/list/name_to_material hardness = 80 weight = 23 stack_origin_tech = list(TECH_MATERIAL = 2) + conductive = TRUE hitsound = 'sound/weapons/genhit.ogg' + armor = list( + melee = 8, + bullet = 8, + energy = 4, + bomb = 75, + bio = 35, + rad = 25 + ) /material/plasteel/titanium name = "titanium" @@ -388,6 +487,15 @@ var/list/name_to_material door_icon_base = "metal" icon_colour = "#D1E6E3" icon_reinf = "reinf_metal" + conductive = TRUE + armor = list( + melee = 16, + bullet = 10, + energy = 6, + bomb = 125, + bio = 35, + rad = 0 + ) /material/glass name = MATERIAL_GLASS @@ -406,7 +514,16 @@ var/list/name_to_material created_window = /obj/structure/window/basic created_window_full = /obj/structure/window/basic/full rod_product = /obj/item/stack/material/glass/reinforced + conductive = FALSE hitsound = 'sound/effects/Glasshit.ogg' + armor = list( + melee = 1, + bullet = 1, + energy = 0, + bomb = 0, + bio = 0, + rad = 0 + ) /material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) @@ -522,8 +639,17 @@ var/list/name_to_material window_options = list("One Direction" = 1, "Full Window" = 6, "Windoor" = 5) created_window = /obj/structure/window/reinforced created_window_full = /obj/structure/window/reinforced/full + conductive = FALSE wire_product = null rod_product = null + armor = list( + melee = 4, + bullet = 4, + energy = 0, + bomb = 35, + bio = 0, + rad = 0 + ) /material/glass/plasma name = MATERIAL_PLASMAGLASS @@ -539,6 +665,15 @@ var/list/name_to_material created_window_full = /obj/structure/window/plasmabasic/full wire_product = null rod_product = /obj/item/stack/material/glass/plasmarglass + conductive = FALSE + armor = list( + melee = 6, + bullet = 6, + energy = 0, + bomb = 45, + bio = 0, + rad = 0 + ) /material/glass/plasma/reinforced name = MATERIAL_RPLASMAGLASS @@ -550,8 +685,17 @@ var/list/name_to_material created_window_full = /obj/structure/window/reinforced/plasma/full hardness = 60 weight = 50 + conductive = FALSE //composite_material = list() //todo rod_product = null + armor = list( + melee = 8, + bullet = 8, + energy = 0, + bomb = 50, + bio = 0, + rad = 0 + ) /material/plastic name = MATERIAL_PLASTIC @@ -563,13 +707,31 @@ var/list/name_to_material hardness = 10 weight = 12 melting_point = T0C+371 //assuming heat resistant plastic + conductive = FALSE stack_origin_tech = list(TECH_MATERIAL = 3) + armor = list( + melee = 3, + bullet = 3, + energy = 3, + bomb = 20, + bio = 5, + rad = 0 + ) /material/plastic/holographic name = "holoplastic" display_name = "plastic" stack_type = null shard_type = SHARD_NONE + conductive = FALSE + armor = list( + melee = 0, + bullet = 0, + energy = 0, + bomb = 0, + bio = 0, + rad = 0 + ) /material/osmium name = MATERIAL_OSMIUM @@ -580,6 +742,15 @@ var/list/name_to_material hardness = 90 sheet_singular_name = "ingot" sheet_plural_name = "ingots" + conductive = TRUE + armor = list( + melee = 20, + bullet = 14, + energy = 7, + bomb = 200, + bio = 0, + rad = 25 + ) /material/tritium name = MATERIAL_TRITIUM @@ -588,6 +759,15 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 5) sheet_singular_name = "ingot" sheet_plural_name = "ingots" + conductive = FALSE + armor = list( + melee = 0, + bullet = 0, + energy = 10, + bomb = 0, + bio = 100, + rad = 50 + ) /material/mhydrogen name = MATERIAL_MHYDROGEN @@ -596,7 +776,16 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5) weight = 10 hardness = 200 + conductive = TRUE display_name = "metallic hydrogen" + armor = list( + melee = 35, + bullet = 18, + energy = 8, + bomb = 350, + bio = 0, + rad = 35 + ) /material/platinum name = MATERIAL_PLATINUM @@ -607,6 +796,14 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 2) sheet_singular_name = "ingot" sheet_plural_name = "ingots" + armor = list( + melee = 3, + bullet = 3, + energy = 15, + bomb = 25, + bio = 55, + rad = 25 + ) /material/iron name = MATERIAL_IRON @@ -617,6 +814,15 @@ var/list/name_to_material sheet_singular_name = "ingot" sheet_plural_name = "ingots" hitsound = 'sound/weapons/smash.ogg' + conductive = TRUE + armor = list( + melee = 3, + bullet = 3, + energy = 3, + bomb = 35, + bio = 0, + rad = 0 + ) // Adminspawn only, do not let anyone get this. /material/voxalloy @@ -629,6 +835,14 @@ var/list/name_to_material explosion_resistance = 200 // Hull plating. hardness = 500 weight = 500 + armor = list( + melee = 50, + bullet = 35, + energy = 25, + bomb = 500, + bio = 0, + rad = 85 + ) /material/wood name = MATERIAL_WOOD @@ -650,12 +864,30 @@ var/list/name_to_material sheet_singular_name = "plank" sheet_plural_name = "planks" hitsound = 'sound/effects/woodhit.ogg' + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 5, + bomb = 10, + bio = 0, + rad = 0 + ) /material/wood/holographic name = "holowood" display_name = "wood" stack_type = null shard_type = SHARD_NONE + conductive = FALSE + armor = list( + melee = 0, + bullet = 0, + energy = 0, + bomb = 0, + bio = 0, + rad = 0 + ) /material/cardboard name = MATERIAL_CARDBOARD @@ -672,6 +904,15 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 1) door_icon_base = "wood" destruction_desc = "crumples" + conductive = FALSE + armor = list( + melee = 0, + bullet = 0, + energy = 0, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth //todo name = MATERIAL_CLOTH @@ -680,6 +921,16 @@ var/list/name_to_material ignition_point = T0C+232 melting_point = T0C+300 flags = MATERIAL_PADDING + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) + /material/biomatter name = MATERIAL_BIOMATTER @@ -688,6 +939,14 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) sheet_singular_name = "sheet" sheet_plural_name = "sheets" + armor = list( + melee = 2, + bullet = 2, + energy = 2, + bomb = 15, + bio = 100, + rad = 0 + ) /material/compressed name = MATERIAL_COMPRESSED @@ -695,6 +954,15 @@ var/list/name_to_material icon_colour = "#00E1FF" sheet_singular_name = "cartrigde" sheet_plural_name = "cartridges" + conductive = TRUE + armor = list( + melee = 18, + bullet = 10, + energy = 10, + bomb = 150, + bio = 0, + rad = 100 + ) //TODO PLACEHOLDERS: /material/leather @@ -704,6 +972,14 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+300 melting_point = T0C+300 + armor = list( + melee = 4, + bullet = 2, + energy = 2, + bomb = 10, + bio = 10, + rad = 0 + ) /material/carpet name = "carpet" @@ -715,6 +991,15 @@ var/list/name_to_material melting_point = T0C+300 sheet_singular_name = "tile" sheet_plural_name = "tiles" + conductive = FALSE + armor = list( + melee = 0, + bullet = 0, + energy = 0, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cotton name = "cotton" @@ -723,6 +1008,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 0, + bullet = 0, + energy = 0, + bomb = 0, + bio = 0, + rad = 0 + ) /material/cloth_teal name = "teal" @@ -732,6 +1026,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth_black name = "black" @@ -741,6 +1044,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth_green name = "green" @@ -750,6 +1062,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth_puple name = "purple" @@ -759,6 +1080,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth_blue name = "blue" @@ -768,6 +1098,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth_beige name = "beige" @@ -777,6 +1116,15 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) /material/cloth_lime name = "lime" @@ -786,3 +1134,12 @@ var/list/name_to_material flags = MATERIAL_PADDING ignition_point = T0C+232 melting_point = T0C+300 + conductive = FALSE + armor = list( + melee = 1, + bullet = 1, + energy = 1, + bomb = 5, + bio = 0, + rad = 0 + ) diff --git a/code/modules/mechs/_mech_defines.dm b/code/modules/mechs/_mech_defines.dm index 1bde101c220..d1217122fa1 100644 --- a/code/modules/mechs/_mech_defines.dm +++ b/code/modules/mechs/_mech_defines.dm @@ -7,6 +7,7 @@ #define MECH_HUD_ICON 'icons/mechs/mech_hud.dmi' #define HARDPOINT_BACK "back" +#define HARDPOINT_FRONT "front" #define HARDPOINT_LEFT_HAND "left hand" #define HARDPOINT_RIGHT_HAND "right hand" #define HARDPOINT_LEFT_SHOULDER "left shoulder" @@ -51,3 +52,12 @@ GLOBAL_LIST_INIT(mech_damage_overlay_cache, new) GLOBAL_LIST_INIT(mech_image_cache, new) GLOBAL_LIST_INIT(mech_icon_cache, new) GLOBAL_LIST_INIT(mech_weapon_overlays, icon_states(MECH_WEAPON_OVERLAYS_ICON)) + +#define MECH_POWER_OFF 0 +#define MECH_POWER_TRANSITION 1 +#define MECH_POWER_ON 2 + +/// It will make update_icon be called on the equipment after every move +#define EQUIPFLAG_UPDTMOVE 1 +/// It will have pretick() called on it before the mech checks wheter or not is powered +#define EQUIPFLAG_PRETICK 2 diff --git a/code/modules/mechs/components/_components.dm b/code/modules/mechs/components/_components.dm index efcd5483133..0f3d0d78ca0 100644 --- a/code/modules/mechs/components/_components.dm +++ b/code/modules/mechs/components/_components.dm @@ -17,8 +17,14 @@ var/max_damage = 60 var/damage_state = 1 var/list/has_hardpoints = list() + //var/material/reinforcement = null var/decal var/power_use = 0 + /// how many hits do we have to get to gib once we hit max damage + var/gib_hits_needed = 7 + var/gib_hits = 0 + /// wheter or not this component can just blow up + var/can_gib = FALSE /obj/item/mech_component/proc/set_colour(new_colour) var/last_colour = color @@ -35,13 +41,35 @@ if(.) if(ready_to_install()) - to_chat(usr, SPAN_NOTICE("It is ready for installation.")) + to_chat(user, SPAN_NOTICE("It is ready for installation.")) else show_missing_parts(usr) + /* + if(reinforcement) + to_chat(user, SPAN_NOTICE("It is reinforced with sheets of [reinforcement.material_display_name].")) + else + to_chat(user, SPAN_NOTICE("It can be reinforced with 5 sheets of a material for additional protection.")) + */ var/damage_string = src.get_damage_string() to_chat(user, "The [src.name] [src.gender == PLURAL ? "are" : "is"] [damage_string].") +/* + +/obj/item/mech_component/attackby(obj/item/I, mob/living/user) + . = ..() + + if(!reinforcement && istype(I, /obj/item/stack/material)) + var/obj/item/stack/material/mat = I + if(!mat.can_use(5)) + to_chat(user, SPAN_NOTICE("You need 5 sheets of reinforcing material!")) + return + to_chat(user, SPAN_NOTICE("You start reinforcing \the src.")) +*/ + + + + //These icons have multiple directions but before they're attached we only want south. /obj/item/mech_component/set_dir() @@ -70,6 +98,26 @@ if(damage_state == MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL) playsound(loc, 'sound/mechs/critdestr.ogg', 50) + if(total_damage == max_damage) + if(gib_hits > gib_hits_needed && can_gib) + var/mob/living/exosuit/owner = loc + if(!istype(owner)) + return + forceMove(NULLSPACE) + switch(type) + if(/obj/item/mech_component/manipulators) + owner.arms = null + if(/obj/item/mech_component/sensors) + owner.head = null + if(/obj/item/mech_component/propulsion) + owner.legs = null + if(/obj/item/mech_component/chassis) + owner.body = null + for(var/hardpoint in has_hardpoints) + owner.remove_system(hardpoint, null, TRUE) + owner.update_icon() + qdel(src) + /obj/item/mech_component/proc/ready_to_install() return TRUE @@ -89,6 +137,7 @@ update_health() if(total_damage >= max_damage) take_component_damage(amt,0) + gib_hits += (total_damage / 10) return /obj/item/mech_component/proc/take_burn_damage(amt) @@ -96,6 +145,7 @@ update_health() if(total_damage >= max_damage) take_component_damage(0,amt) + gib_hits += (total_damage / 10) return /obj/item/mech_component/proc/take_component_damage(brute, burn) diff --git a/code/modules/mechs/components/arms.dm b/code/modules/mechs/components/arms.dm index 3f7918ffbfe..a9c80304720 100644 --- a/code/modules/mechs/components/arms.dm +++ b/code/modules/mechs/components/arms.dm @@ -6,9 +6,17 @@ power_use = 10 matter = list(MATERIAL_STEEL = 10) + can_gib = TRUE + gib_hits_needed = 10 var/melee_damage = WEAPON_FORCE_PAINFUL var/action_delay = 15 + /// if they can force open powered doors + var/can_force_doors = TRUE var/obj/item/robot_parts/robot_component/actuator/motivator + tool_qualities = list( + QUALITY_HAMMERING = 30, + QUALITY_PRYING = 20 + ) var/punch_sound = ('sound/mechs/mech_punch.ogg') /obj/item/mech_component/manipulators/Destroy() @@ -50,6 +58,7 @@ desc = "Industrial lifter arms that allow you to crudely manipulate things from the safety of your cockpit." exosuit_desc_string = "industrial lifter arms" icon_state = "loader_arms" + can_force_doors = FALSE max_damage = 90 power_use = 30 @@ -59,6 +68,7 @@ desc = "As flexible as they are fragile, these manipulators can follow a pilot's movements in close to real time." icon_state = "light_arms" action_delay = 5 + can_force_doors = FALSE max_damage = 45 power_use = 10 matter = list(MATERIAL_STEEL = 10, MATERIAL_PLASTIC = 5) diff --git a/code/modules/mechs/components/body.dm b/code/modules/mechs/components/body.dm index be7214a9543..a29da3e5146 100644 --- a/code/modules/mechs/components/body.dm +++ b/code/modules/mechs/components/body.dm @@ -40,6 +40,10 @@ var/min_pilot_size = MOB_SMALL var/max_pilot_size = MOB_LARGE var/climb_time = 25 + /// does this mech chassis have support for charging all cells inside of its storage? if its 0 it doesnt + var/cell_charge_rate = 200 + /// Wheter chassis blocks sight from a outside POV (aka can see behind mech or not ?) + var/opaque_chassis = TRUE /obj/item/mech_component/chassis/New() ..() @@ -103,7 +107,7 @@ . = ..() air_supply = new /obj/machinery/portable_atmospherics/canister/air(src) storage_compartment = new(src) - cockpit = new(20) + cockpit = new(250) if(loc) cockpit.equalize(loc.return_air()) @@ -281,3 +285,33 @@ power_use = 50 climb_time = 35 //Takes longer to climb into, but is beefy as HELL. matter = list(MATERIAL_STEEL = 50, MATERIAL_URANIUM = 20, MATERIAL_PLASTEEL = 20) + +/obj/item/mech_component/chassis/forklift + name = "forklift chassis" + desc = "Has an integrated forklift clamp for the industrial relocation of resources. Are you ready to lift?" + icon_state = "seat-cockpit" + has_hardpoints = list(HARDPOINT_FRONT) + exosuit_desc_string = "a forklifting chassis" + pilot_coverage = 30 + max_damage = 100 + mech_health = 200 + opaque_chassis = FALSE + matter = list(MATERIAL_STEEL = 20, MATERIAL_PLASTIC = 10) + + +/obj/item/mech_component/chassis/forklift/Initialize() + pilot_positions = list( + list( + "[NORTH]" = list("x" = 9, "y" = 5), + "[SOUTH]" = list("x" = 9, "y" = 5), + "[EAST]" = list("x" = 6, "y" = 5), + "[WEST]" = list("x" = 8, "y" = 5) + ), + list( + "[NORTH]" = list("x" = 9, "y" = 5), + "[SOUTH]" = list("x" = 9, "y" = 10), + "[EAST]" = list("x" = 0, "y" = 5), + "[WEST]" = list("x" = 16, "y" = 5) + ) + ) + . = ..() diff --git a/code/modules/mechs/components/frame.dm b/code/modules/mechs/components/frame.dm index c972ff5f4b1..37474d2ef15 100644 --- a/code/modules/mechs/components/frame.dm +++ b/code/modules/mechs/components/frame.dm @@ -98,7 +98,7 @@ if(is_wired) usable_qualities += QUALITY_WIRE_CUTTING - if(is_wired == FRAME_WIRED_ADJUSTED && is_reinforced == FRAME_REINFORCED_WELDED && arms && legs && head && body) + if(is_wired == FRAME_WIRED_ADJUSTED && is_reinforced == FRAME_REINFORCED_WELDED && legs && body) usable_qualities += QUALITY_SCREW_DRIVING var/tool_type = I.get_tool_type(user, usable_qualities, src) @@ -225,7 +225,7 @@ // Final construction step if(QUALITY_SCREW_DRIVING) // Check for basic components. - if(!(arms && legs && head && body)) + if(!(legs && body)) to_chat(user, SPAN_WARNING("There are still parts missing from \the [src].")) return @@ -251,7 +251,7 @@ if(!I.use_tool(user, src, WORKTIME_INSTANT, tool_type, FAILCHANCE_ZERO)) return - if(is_reinforced < FRAME_REINFORCED_WELDED || is_wired < FRAME_WIRED_ADJUSTED || !(arms && legs && head && body)) + if(is_reinforced < FRAME_REINFORCED_WELDED || is_wired < FRAME_WIRED_ADJUSTED || !(legs && body)) return // We're all done. Finalize the exosuit and pass the frame to the new system. @@ -318,6 +318,9 @@ // Installing basic components. if(istype(I, /obj/item/mech_component/manipulators)) + if(istype(body, /obj/item/mech_component/chassis/forklift)) + to_chat(user, SPAN_WARNING("\The [src]'s chassis can not support manipulators!")) + return if(arms) to_chat(user, SPAN_WARNING("\The [src] already has manipulators installed.")) return @@ -330,12 +333,18 @@ if(legs) to_chat(user, SPAN_WARNING("\The [src] already has a propulsion system installed.")) return + if(istype(body, /obj/item/mech_component/chassis/forklift) && !istype(I, /obj/item/mech_component/propulsion/wheels)) + to_chat(user, SPAN_WARNING("\The [src]'s chassis can not support this type of propulsation, only wheels!")) + return if(install_component(I, user)) if(legs) user.unEquip(I, loc) return legs = I else if(istype(I, /obj/item/mech_component/sensors)) + if(istype(body, /obj/item/mech_component/chassis/forklift)) + to_chat(user, SPAN_WARNING("\The [src]'s chassis can not support sensors!")) + return if(head) to_chat(user, SPAN_WARNING("\The [src] already has a sensor array installed.")) return @@ -369,6 +378,16 @@ if(!user.unEquip(I)) return I.forceMove(src) + if(istype(MC, /obj/item/mech_component/chassis/forklift)) + if(arms) + arms.forceMove(get_turf(src)) + arms = null + if(head) + head.forceMove(get_turf(src)) + head = null + if(legs && !istype(legs, /obj/item/mech_component/propulsion/wheels)) + legs.forceMove(get_turf(src)) + legs = null visible_message(SPAN_NOTICE("\The [user] installs \the [I] into \the [src].")) playsound(user.loc, 'sound/machines/click.ogg', 50, 1) return 1 diff --git a/code/modules/mechs/components/head.dm b/code/modules/mechs/components/head.dm index d18ebd0684c..eb1d7d55a9c 100644 --- a/code/modules/mechs/components/head.dm +++ b/code/modules/mechs/components/head.dm @@ -6,6 +6,8 @@ has_hardpoints = list(HARDPOINT_HEAD) power_use = 15 matter = list(MATERIAL_STEEL = 5, MATERIAL_GLASS = 4) + can_gib = TRUE + gib_hits_needed = 5 var/vision_flags = NONE var/see_invisible = 0 var/active_sensors = FALSE @@ -32,18 +34,19 @@ radio = locate() in src camera = locate() in src -/obj/item/mech_component/sensors/proc/get_sight() +/obj/item/mech_component/sensors/proc/get_sight(powered) var/flags = 0 - if(total_damage >= 0.8 * max_damage) + var/mob/living/exosuit/mech = loc + if(total_damage >= 0.8 * max_damage || (!powered && mech.hatch_closed)) flags |= BLIND else if(active_sensors) flags |= vision_flags return flags -/obj/item/mech_component/sensors/proc/get_invisible() +/obj/item/mech_component/sensors/proc/get_invisible(powered) var/invisible = 0 - if((total_damage <= 0.8 * max_damage) && active_sensors) + if((total_damage <= 0.8 * max_damage) && active_sensors && powered) invisible = see_invisible return invisible diff --git a/code/modules/mechs/components/legs.dm b/code/modules/mechs/components/legs.dm index 6e987ab8c5a..980e2ee5252 100644 --- a/code/modules/mechs/components/legs.dm +++ b/code/modules/mechs/components/legs.dm @@ -106,3 +106,17 @@ power_use = 100 matter = list(MATERIAL_STEEL = 20, MATERIAL_URANIUM = 8) can_climb = FALSE + +/obj/item/mech_component/propulsion/wheels + name = "wheels" + exosuit_desc_string = "wheels" + desc = "A pair of wheels for any mobile vehicle" + icon_state = "wheels" + move_delay = 1.5 + turn_delay = 4 + max_damage = 60 + stomp_damage = 15 + power_use = 10 + can_strafe = FALSE + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTIC = 16) + can_climb = FALSE diff --git a/code/modules/mechs/equipment/_equipment.dm b/code/modules/mechs/equipment/_equipment.dm index d7dc768d600..aec638bad08 100644 --- a/code/modules/mechs/equipment/_equipment.dm +++ b/code/modules/mechs/equipment/_equipment.dm @@ -19,6 +19,17 @@ var/active_power_use = 1 KILOWATTS // How much does it consume to perform and accomplish usage var/passive_power_use = 0 // For gear that for some reason takes up power even if it's supposedly doing nothing (mech will idly consume power) var/mech_layer = MECH_COCKPIT_LAYER //For the part where it's rendered as mech gear + var/active = FALSE + var/equipment_flags = 0 + +/obj/item/mech_equipment/proc/activate() + active = TRUE + +/obj/item/mech_equipment/proc/deactivate() + active = FALSE + +/obj/item/mech_equipment/proc/pretick() + return FALSE /obj/item/mech_equipment/attack() //Generally it's not desired to be able to attack with items return 0 @@ -38,6 +49,8 @@ if(target in owner.contents) return FALSE var/obj/item/cell/C = owner.get_cell() + if(!C && active_power_use == 0) + return TRUE if(!(C && C.check_charge(active_power_use * CELLRATE))) to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]")) return FALSE @@ -55,6 +68,8 @@ /obj/item/mech_equipment/attack_self(var/mob/user) if (owner && loc == owner && ((user in owner.pilots) || user == owner)) var/obj/item/cell/C = owner.get_cell() + if(C && active_power_use == 0) + return TRUE if(!(C && C.check_charge(active_power_use * CELLRATE))) to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]")) return FALSE @@ -130,7 +145,7 @@ /obj/item/mech_equipment/mounted_system/resolve_attackby(atom/A, mob/user, params) // foward attackbys only when we are installed . if(ismech(loc)) - return holding.attackby(A, user, params) + return A.attackby(holding, user, params) else ..() /obj/item/mech_equipment/mounted_system/Destroy() diff --git a/code/modules/mechs/equipment/combat.dm b/code/modules/mechs/equipment/combat.dm index 950bb31934e..8d5b57928c1 100644 --- a/code/modules/mechs/equipment/combat.dm +++ b/code/modules/mechs/equipment/combat.dm @@ -813,6 +813,8 @@ icon_state = "mech_atmoshield" restricted_hardpoints = list(HARDPOINT_BACK) origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 6, TECH_PLASMA = 5) + // so it has update icon called everytime it moves + equipment_flags = EQUIPFLAG_UPDTMOVE /// Defines the amount of power drained per hit thats blocked var/damage_to_power_drain = 30 /// Are we toggled on ? @@ -830,8 +832,6 @@ visual_bluff.icon_state = "shield_null" visual_bluff.vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_ID | VIS_INHERIT_PLANE visual_bluff.layer = ABOVE_ALL_MOB_LAYER - // the mech default offset is -8 , this neeeds 8 for some reason. - visual_bluff.pixel_x = 8 /obj/item/mech_equipment/shield_generator/Destroy() . = ..() @@ -840,6 +840,14 @@ mech.vis_contents.Remove(visual_bluff) QDEL_NULL(visual_bluff) +/obj/item/mech_equipment/shield_generator/uninstalled() + owner.vis_contents.Remove(visual_bluff) + if(on) + on = FALSE + update_icon() + . = ..() + + /obj/item/mech_equipment/shield_generator/attack_self(mob/user) . = ..() if(.) @@ -848,13 +856,6 @@ last_toggle = world.time update_icon() -/obj/item/mech_equipment/shield_generator/proc/updateVisualBluff(targetDir) - visual_bluff.dir = targetDir - if(targetDir == NORTH) - visual_bluff.layer = MECH_UNDER_LAYER - else - visual_bluff.layer = MECH_ABOVE_LAYER - // Used to tell how effective we are against damage, /obj/item/mech_equipment/shield_generator/proc/getEffectiveness() return on @@ -870,6 +871,11 @@ return if(!(visual_bluff in mech.vis_contents)) mech.vis_contents.Add(visual_bluff) + visual_bluff.dir = mech.dir + if(visual_bluff.dir == NORTH) + visual_bluff.layer = MECH_UNDER_LAYER + else + visual_bluff.layer = MECH_ABOVE_LAYER if(last_toggle > world.time - 1 SECOND) if(on) flick("shield_raise", visual_bluff) @@ -918,7 +924,7 @@ if(!(visual_bluff in _owner.vis_contents)) _owner.vis_contents.Add(visual_bluff) visual_bluff.icon_state = "mech_shield_[hardpoint]" - updateVisualBluff(_owner.dir) + update_icon() /obj/item/mech_equipment/shield_generator/ballistic/uninstalled() owner.vis_contents.Remove(visual_bluff) @@ -937,50 +943,48 @@ playsound(get_turf(src), 'sound/weapons/shield/shieldblock.ogg', 50, 8) return damages -/obj/item/mech_equipment/shield_generator/ballistic/updateVisualBluff(targetDir) - visual_bluff.dir = targetDir +/obj/item/mech_equipment/shield_generator/ballistic/update_icon() + /// Not needed since we already have handling for visual bluffs layering + /// and since we dont use a shield. + + ..(skip = TRUE) + var/mob/living/exosuit/mech = loc + if(!istype(mech)) + return + if(!(visual_bluff in mech.vis_contents)) + mech.vis_contents.Add(visual_bluff) + visual_bluff.dir = mech.dir + visual_bluff.icon_state = "mech_shield_[on ? "on_" : ""][get_hardpoint()]" switch(get_hardpoint()) if(HARDPOINT_RIGHT_HAND) // i used a switch before and it doesnt work as intended for some fucking reason FOR EAST AND WEST >:( -SPCR - if(targetDir == NORTH) + if(visual_bluff.dir == NORTH) visual_bluff.layer = MECH_UNDER_LAYER - if(targetDir == EAST) + if(visual_bluff.dir == EAST) visual_bluff.layer = MECH_ABOVE_LAYER - if(targetDir == SOUTH) + if(visual_bluff.dir == SOUTH) visual_bluff.layer = MECH_ABOVE_LAYER - if(targetDir == WEST) + if(visual_bluff.dir == WEST) visual_bluff.layer = MECH_UNDER_LAYER return if(HARDPOINT_LEFT_HAND) - if(targetDir == NORTH) + if(visual_bluff.dir == NORTH) visual_bluff.layer = MECH_UNDER_LAYER - if(targetDir == EAST) + if(visual_bluff.dir == EAST) visual_bluff.layer = MECH_UNDER_LAYER - if(targetDir == SOUTH) + if(visual_bluff.dir == SOUTH) visual_bluff.layer = MECH_ABOVE_LAYER - if(targetDir == WEST) + if(visual_bluff.dir == WEST) visual_bluff.layer = MECH_ABOVE_LAYER return - -/obj/item/mech_equipment/shield_generator/ballistic/update_icon() - /// Not needed since we already have handling for visual bluffs layering - /// and since we dont use a shield. - - ..(skip = TRUE) - var/mob/living/exosuit/mech = loc - if(!istype(mech)) - return - if(!(visual_bluff in mech.vis_contents)) - mech.vis_contents.Add(visual_bluff) - visual_bluff.icon_state = "mech_shield_[get_hardpoint()]" - /obj/item/mech_equipment/shield_generator/ballistic/attack_self(mob/user) var/mob/living/exosuit/mech = loc if(!istype(mech)) return to_chat(user , SPAN_NOTICE("[on ? "Retracting" : "Deploying"] \the [src]...")) - if(do_after(user, 3 SECOND, src, FALSE)) + var/time = on ? 0.5 SECONDS : 3 SECONDS + if(do_after(user, time, src, FALSE)) on = !on to_chat(user, "You [on ? "deploy" : "retract"] \the [src].") mech.visible_message(SPAN_DANGER("\The [mech] [on ? "deploys" : "retracts"] \the [src]!"), "", "You hear the sound of a heavy metal plate hitting the floor!", 8) diff --git a/code/modules/mechs/equipment/medical.dm b/code/modules/mechs/equipment/medical.dm index 7371290f795..a44242c794b 100644 --- a/code/modules/mechs/equipment/medical.dm +++ b/code/modules/mechs/equipment/medical.dm @@ -77,3 +77,150 @@ user.visible_message("\The [user] removes \the [beaker] from \the [src].", "You remove \the [beaker] from \the [src].") beaker = I user.visible_message("\The [user] adds \a [I] to \the [src].", "You add \a [I] to \the [src].") + +/obj/item/mech_equipment/sleeper/upgraded + name = "\improper MK2 mounted sleeper" + desc = "An exosuit-mounted sleeper designed to heal patients" + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 3, TECH_BIO = 5) + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 10, MATERIAL_GLASS = 5, MATERIAL_SILVER = 3, MATERIAL_PLATINUM = 1) + +/obj/item/mech_equipment/sleeper/upgraded/Initialize() + . = ..() + // delete old one + qdel(sleeper) + sleeper = new /obj/machinery/sleeper/mounted/upgraded(src) + sleeper.forceMove(src) + +/obj/machinery/sleeper/mounted/upgraded + name = "\improper MK2 mounted sleeper" + available_chemicals = list("inaprovaline2" = "Synth-Inaprovaline", + "quickclot" = "Quick-Clot", + "stoxin" = "Soporific", + "tramadol" = "Tramadol", + "anti_toxin" = "Dylovene", + "dexalin" = "Dexalin", + "tricordrazine" = "Tricordrazine", + "polystem" = "PolyStem") + +/obj/item/mech_equipment/auto_mender + name = "\improper exosuit auto-mender" + desc = "A mech-designed and equipped medical system for fast and automatic application of advanced trauma treatments to pacients. Makes use of medical gear found in trauma kits." + icon_state = "mech_mender" + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_MEDICAL) + equipment_delay = 10 //don't spam it on people pls + active_power_use = 0 //Usage doesn't really require power. + origin_tech = list(TECH_DATA = 3, TECH_BIO = 5, TECH_ENGINEERING = 3) + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 10, MATERIAL_SILVER = 8, MATERIAL_GLASS = 5) + passive_power_use = 1.5 KILOWATTS + var/mob/living/carbon/human/mending_target = null + var/mob/living/exosuit/mech = null + var/obj/item/organ/external/affecting = null + var/trauma_charges_stored = 0 + var/trauma_storage_max = 30 + +/obj/item/mech_equipment/auto_mender/afterattack(atom/target, mob/living/user, inrange, params) + . = ..() + if(. && ishuman(target)) + if(mending_target == target) + mending_target = null + to_chat(user, SPAN_NOTICE("You cancel \the [src]'s mending on [target].")) + return + if(mending_target) + to_chat(user, SPAN_NOTICE("\The [src] is already mending someone,you can stop it by clicking the person again!")) + return + if(!target.Adjacent(mech)) + to_chat(user, SPAN_NOTICE("You need to be next to \the [target] to start mending them!")) + mending_target = target + mending_loop() + +/obj/item/mech_equipment/auto_mender/attackby(obj/item/I, mob/living/user, params) + . = ..() + if(istype(I, /obj/item/stack/medical/advanced/bruise_pack)) + var/obj/item/stack/medical/advanced/bruise_pack/pack = I + var/substract = clamp(pack.amount, 0, trauma_storage_max - trauma_charges_stored) + if(substract && pack.use(substract)) + trauma_charges_stored += substract + to_chat(user, SPAN_NOTICE("You restock \the [src]'s internal medicine storage with \the [I], using [substract] charges.")) + + +/obj/item/mech_equipment/auto_mender/installed(mob/living/exosuit/_owner, hardpoint) + . = ..() + mech = _owner + +/obj/item/mech_equipment/auto_mender/uninstalled() + . = ..() + mech = null + +/obj/item/mech_equipment/auto_mender/proc/mending_loop() + if(!mending_target || !mech) + return + if(!mech.Adjacent(mending_target)) + mending_target = null + affecting = null + return + var/obj/item/organ/external/checking + if(!affecting || (affecting && affecting.is_bandaged())) + for(var/zone in BP_ALL_LIMBS) + checking = mending_target.organs_by_name[zone] + if(checking.is_bandaged() && checking.damage < 1) + continue + if(affecting) + if(checking.damage > affecting.damage) + affecting = checking + else + affecting = checking + + if(!affecting) + mending_target = null + + return + + for(var/datum/wound/W in affecting.wounds) + if(!mech.Adjacent(mending_target)) + mending_target = null + affecting = null + return + //if(W.internal || W.bandaged) + // continue + if(W.damage < 1) + continue + if(!trauma_charges_stored) + break + if(!do_mob(mech.get_mob(), mending_target, W.damage/5)) + to_chat(mech.get_mob(), SPAN_NOTICE("You must stand still to bandage wounds.")) + mending_target = null + affecting = null + break + //if(W.internal || W.bandaged) + // continue + if (W.current_stage <= W.max_bleeding_stage) + mech.visible_message( + SPAN_NOTICE("\The [mech] cleans \a [W.desc] on [mending_target]'s [affecting.name] and seals the edges with bioglue."), + SPAN_NOTICE("You clean and seal \a [W.desc] on [mending_target]'s [affecting.name].") + ) + else if (W.damage_type == BRUISE) + mech.visible_message( + SPAN_NOTICE("\The [mech] places a medical patch over \a [W.desc] on [mending_target]'s [affecting.name]."), + SPAN_NOTICE("You place a medical patch over \a [W.desc] on [mending_target]'s [affecting.name].") + ) + else + mech.visible_message( + SPAN_NOTICE("\The [mech] smears some bioglue over \a [W.desc] on [mending_target]'s [affecting.name]."), + SPAN_NOTICE("You smear some bioglue over \a [W.desc] on [mending_target]'s [affecting.name].") + ) + W.bandage() + W.heal_damage(10) + // If it doesn't cancel or run out of kits just repeat for every external organ. + if(affecting.is_bandaged() && affecting.damage < 1) + affecting = null + mending_loop() + + + diff --git a/code/modules/mechs/equipment/utility.dm b/code/modules/mechs/equipment/utility.dm index a1d4ee83dd9..269457e6244 100644 --- a/code/modules/mechs/equipment/utility.dm +++ b/code/modules/mechs/equipment/utility.dm @@ -465,3 +465,595 @@ /obj/item/extinguisher/mech/get_hardpoint_status_value() return reagents.total_volume/max_water + +/obj/item/mech_equipment/power_generator + name = "debug power generator" + desc = "If you see this tell coders to fix code!" + icon_state = "mech_power" + restricted_hardpoints = list(HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) + restricted_software = list(MECH_SOFTWARE_UTILITY) + equipment_flags = EQUIPFLAG_PRETICK + spawn_blacklisted = TRUE + var/obj/item/cell/internal_cell + /// 50 power per mech life tick , adjust for cell RATE + var/generation_rate = 50 + +/obj/item/mech_equipment/power_generator/Initialize() + . = ..() + internal_cell = new /obj/item/cell/small + internal_cell.matter = list() + +/obj/item/mech_equipment/power_generator/attackby(obj/item/I, mob/living/user, params) + . = ..() + if(istype(I, /obj/item/cell) && !internal_cell) + user.drop_from_inventory(I) + I.forceMove(src) + internal_cell = I + to_chat(user, SPAN_NOTICE("You replace [src]'s cell!")) + return + +/obj/item/mech_equipment/power_generator/pretick() + var/ungiven_power = internal_cell?.give(generation_rate) + if(owner && internal_cell) + var/obj/item/cell/batt = owner.get_cell(TRUE) + if(batt && batt != internal_cell) + batt.give(internal_cell.use(batt.maxcharge - batt.charge)) + + return ungiven_power + +/obj/item/mech_equipment/power_generator/fueled + name = "fueled debug power generator" + // YES WE NEED VISCONTENTS FOR THE ANIMATIONS + equipment_flags = EQUIPFLAG_UPDTMOVE | EQUIPFLAG_PRETICK + var/fuel_amount = 0 + var/fuel_max = 1000 + var/fuel_usage_per_tick = 5 + var/mode = 0 + var/datum/repeating_sound/sound_loop = null + var/obj/visual_bluff = null + spawn_blacklisted = TRUE + +/obj/item/mech_equipment/power_generator/fueled/Initialize() + . = ..() + visual_bluff = new(src) + visual_bluff.forceMove(src) + visual_bluff.icon = MECH_WEAPON_OVERLAYS_ICON + visual_bluff.layer = MECH_ABOVE_LAYER + +/obj/item/mech_equipment/power_generator/fueled/pretick() + // for when we arențt on + if(!mode) + sound_loop?.stop() + return + if(fuel_amount > fuel_usage_per_tick) + . = ..() + /// if we had a extremely minimal use + if(. > generation_rate - generation_rate * 0.01 || . == null) + return + else + fuel_amount -= fuel_usage_per_tick + if(QDELETED(sound_loop)) + sound_loop = new(_interval = 2 SECONDS, duration = 10 SECONDS, interval_variance = 0, + _source = owner, _soundin = 'sound/mechs/mech_generator.ogg' , _vol = 25 * mode, _vary = 0, _extrarange = mode * 3, + _falloff = 0, _is_global = FALSE, _use_pressure = TRUE) + else + // extend it artificially. + sound_loop.end_time = world.time + 10 SECONDS + sound_loop.vol = mode * 25 + sound_loop.extrarange = mode * 3 + +/obj/item/mech_equipment/power_generator/fueled/installed(mob/living/exosuit/_owner, hardpoint) + . = ..() + _owner.tickers.Add(src) + _owner.vis_contents.Add(visual_bluff) + +/obj/item/mech_equipment/power_generator/fueled/uninstalled() + . = ..() + owner.tickers.Remove(src) + owner.vis_contents.Remove(visual_bluff) + +/obj/item/mech_equipment/power_generator/fueled/update_icon() + ..() + icon_state = "[initial(icon_state)]" + visual_bluff.icon_state = "[initial(icon_state)]_[mode ? "on" : ""]_[get_hardpoint()]" + if(owner) + visual_bluff.dir = owner.dir + +/obj/item/mech_equipment/power_generator/fueled/attack_self(mob/user) + . = ..() + if(. && owner) + switch(mode) + /// Eco mode , very slow generation but doubled power output ( 20% of power production at cost of 10% of fuel usage) + if(0) + mode = 1 + fuel_usage_per_tick = initial(fuel_usage_per_tick) * 0.1 + generation_rate = initial(generation_rate) * 0.2 + to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to ECO. 10% Fuel usage, 20% power output.")) + /// Default + if(1) + mode = 2 + fuel_usage_per_tick = initial(fuel_usage_per_tick) + generation_rate = initial(generation_rate) + to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to NORMAL. 100% Fuel usage, 100% power output.")) + /// Turbo mode, 2x fuel usage at 1.6x power output + if(2) + mode = 3 + fuel_usage_per_tick = initial(fuel_usage_per_tick) * 2 + generation_rate = initial(generation_rate) * 1.6 + to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to TURBO. 200% Fuel usage, 160% power output.")) + /// back to eco. + if(3) + mode = 0 + fuel_usage_per_tick = initial(fuel_usage_per_tick) + generation_rate = initial(generation_rate) + to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to OFF. 0% Fuel usage, 0% power output.")) + update_icon() + + +/obj/item/mech_equipment/power_generator/fueled/get_hardpoint_maptext() + return "[fuel_amount]/[fuel_max] - [fuel_usage_per_tick]" + +/obj/item/mech_equipment/power_generator/fueled/plasma + name = "plasma powered mech-mountable power generator" + desc = "a plasma-fueled mech power generator, creates 5 KW out of 1 sheet of plasma at a rate of 0.25 KW. Fully stocked it generates 35 KW in total." + icon_state = "mech_generator_plasma" + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_GLASS = 6, MATERIAL_PLASTIC = 3, MATERIAL_SILVER = 2, MATERIAL_GOLD = 3, MATERIAL_STEEL = 4) + origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 5, TECH_POWER = 3) + generation_rate = 250 + // each sheet is 5000 watts + fuel_usage_per_tick = 50 + // 1 sheet = 1000 fuel + // 35000 max power out of a fully loaded generator + fuel_max = 7000 + +/obj/item/mech_equipment/power_generator/fueled/plasma/attackby(obj/item/I, mob/living/user, params) + . = ..() + if(istype(I, /obj/item/stack/material/plasma)) + var/obj/item/stack/material/plasma/stck = I + var/amount_to_use = round((fuel_max - fuel_amount)/1000) + amount_to_use = clamp(stck.amount, 0, amount_to_use) + if(amount_to_use && stck.use(amount_to_use)) + fuel_amount += amount_to_use * 1000 + +/obj/item/mech_equipment/power_generator/fueled/welding + name ="welding fuel powered mech-mountable power generator" + desc = "a mech mounted generator that runs off welding fuel, creates 1 KW out of 10 units of welding fuel, at a rate of 0.1 KW. Fully stocked it generates 20 KW in total." + icon_state = "mech_generator_welding" + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_GLASS = 3, MATERIAL_PLASTIC = 3, MATERIAL_SILVER = 2, MATERIAL_STEEL = 4) + origin_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 3, TECH_POWER = 2) + generation_rate = 100 + fuel_usage_per_tick = 1 + reagent_flags = DRAINABLE | REFILLABLE + /// can generate 20000 power + fuel_max = 200 + /// The "explosion" chamber , used for when the fuel is mixed with something else + var/datum/reagents/chamberReagent = null + +/obj/item/mech_equipment/power_generator/fueled/welding/Initialize() + . = ..() + // max volume + create_reagents(200) + chamberReagent = new(1, src) + + +/obj/item/mech_equipment/power_generator/fueled/welding/attackby(obj/item/I, mob/living/user, params) + . = ..() + /// Only needed when we attack from outside + if(owner) + if(I.is_drainable() && I.reagents.total_volume) + to_chat(user, SPAN_NOTICE("You transfer 10 units of substance from \the [I] to \the [src]'s internal fuel storage.")) + I.reagents.trans_to_holder(reagents, 10, 1, FALSE) + else if(I.reagents && I.reagent_flags & REFILLABLE && user.a_intent == I_GRAB) + to_chat(user, SPAN_NOTICE("You drain 10 units of substance from \the [src] to \the [I].")) + reagents.trans_to_holder(I.reagents, 10, 1, FALSE) + else + to_chat(user, SPAN_NOTICE("You need to be on GRAB intent to drain from \the [src].")) + else if(I.is_refillable() && reagents.total_volume && user.a_intent == I_GRAB) + return FALSE + else + to_chat(user, SPAN_NOTICE("You need to be on GRAB intent to drain from \the [src].")) + + +/obj/item/mech_equipment/power_generator/fueled/welding/pretick() + // dont run if we aren't on + if(!mode) + sound_loop?.stop() + return + chamberReagent.clear_reagents() + reagents.trans_to_holder(chamberReagent, 1, 1, FALSE) + if(chamberReagent.has_reagent("fuel")) + var/fuel = chamberReagent.get_reagent_amount("fuel") + // for the future just add any other reagent here with + * explosion_power_multiplier + var/explosives = chamberReagent.get_reagent_amount("plasma") * 3 + if(explosives > 0.5) + // if its full plasma if just fucking blows instantly + health -= maxHealth * (explosives / 3) + if(health < 1) + owner.remove_system(src, null, TRUE) + qdel(src) + return + // min needed for combustion + if(fuel > 0.25) + var/amountUsed = internal_cell?.give(generation_rate * fuel) + // refund if none of it gets turned into power for qol reasons (its never exact returnal due to float errors) + if(amountUsed < generation_rate * 0.1) + chamberReagent.trans_to_holder(reagents, 1, 1, FALSE) + if(fuel > fuel_usage_per_tick) + chamberReagent.trans_id_to(reagents, "fuel", chamberReagent.total_volume - fuel_usage_per_tick, TRUE) + if(internal_cell && owner) + var/obj/item/cell/batt = owner.get_cell(TRUE) + if(batt && batt != internal_cell) + batt.give(internal_cell.use(batt.maxcharge - batt.charge)) + if(QDELETED(sound_loop)) + sound_loop = new(_interval = 2 SECONDS, duration = 10 SECONDS, interval_variance = 0, + _source = owner, _soundin = 'sound/mechs/mech_generator.ogg' , _vol = 25 * mode, _vary = 0, _extrarange = mode * 3, + _falloff = 0, _is_global = FALSE, _use_pressure = TRUE) + else + // extend it artificially. + sound_loop.end_time = world.time + 10 SECONDS + sound_loop.vol = mode * 25 + sound_loop.extrarange = mode * 3 + fuel_amount = reagents.total_volume + +/obj/item/mech_equipment/towing_hook + name = "mounted towing hook" + desc = "A mech mounted towing hook, usually found in cars. Can hook to anything that isn't anchored down." + icon_state = "mech_tow" + restricted_hardpoints = list(HARDPOINT_BACK) + restricted_software = list(MECH_SOFTWARE_UTILITY) + origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 4) + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 10) + var/atom/movable/currentlyTowing = null + +/obj/item/mech_equipment/towing_hook/installed(mob/living/exosuit/_owner, hardpoint) + . = ..() + RegisterSignal(_owner, COMSIG_MOVABLE_MOVED, PROC_REF(onMechMove)) + +/obj/item/mech_equipment/towing_hook/uninstalled() + UnregisterSignal(owner, COMSIG_MOVABLE_MOVED) + if(currentlyTowing) + UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + currentlyTowing = null + . = ..() + +/// Yes you can hook onto other mechs that are hooked onto you, and yes it won't break anything , SPCR-2023 +/obj/item/mech_equipment/towing_hook/proc/onTowingMove(atom/movable/mover, atom/oldLocation, atom/newLocation) + SIGNAL_HANDLER + if(newLocation.Adjacent(src)) + return + UnregisterSignal(mover, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + to_chat(owner.get_mob(), SPAN_NOTICE("You lose your hook ono \the [currentlyTowing]!")) + currentlyTowing = null + +/obj/item/mech_equipment/towing_hook/proc/onMechMove(atom/movable/mover, atom/oldLocation, atom/newLocation) + SIGNAL_HANDLER + if(!currentlyTowing) + return + if(!oldLocation.Adjacent(currentlyTowing)) + UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + to_chat(owner.get_mob(), SPAN_NOTICE("You lose your hook ono \the [currentlyTowing]!")) + currentlyTowing = null + return + // Protection against move loops caused by 2 mechs towing eachother. + if(COMSIG_PULL_CANCEL == SEND_SIGNAL(src, COMSIG_ATTEMPT_PULLING)) + UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + to_chat(owner.get_mob(), SPAN_NOTICE("You lose your hook ono \the [currentlyTowing]!")) + currentlyTowing = null + return + // If we move up a z-level we want to instantly pull it up with us as to prevent possible abuse. + // Protection against move loops caused by 2 mechs towing eachother walking diagonally + // this gets triggered by z-moves too ,so inbuilt check for that + /* + if(lastMove > world.time - 0.1 SECONDS) + UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + currentlyTowing = null + return + */ + if(oldLocation == newLocation) + return + if(oldLocation.z != newLocation.z) + currentlyTowing.forceMove(newLocation) + else + currentlyTowing.Move(oldLocation) + +/// We get supreme priority on pulling +/obj/item/mech_equipment/towing_hook/proc/onTowingPullAttempt() + SIGNAL_HANDLER + return COMSIG_PULL_CANCEL + +/obj/item/mech_equipment/towing_hook/afterattack(atom/movable/target, mob/living/user, inrange, params) + . = ..() + if(!owner || target == owner) + return + if(!istype(target)) + to_chat(user, SPAN_NOTICE("You cannot hook onto this!")) + return + if(!currentlyTowing) + if(target.Adjacent(src.owner) && !target.anchored) + to_chat(user, SPAN_NOTICE("You hook \the [src] onto \the [target]!")) + currentlyTowing = target + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(onTowingMove)) + RegisterSignal(target, COMSIG_ATTEMPT_PULLING, PROC_REF(onTowingPullAttempt)) + else if(currentlyTowing == target) + to_chat(user, SPAN_NOTICE("You unhook \the [src] from \the [target].")) + UnregisterSignal(currentlyTowing,list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + currentlyTowing = null + else + to_chat(user, SPAN_NOTICE("You are already towing \the [currentlyTowing]. Unhook from it first by attacking it again!")) + +/obj/item/mech_equipment/mounted_system/toolkit + name = "mounted toolkit" + desc = "A automatic suite of tools suited for installation on a mech." + icon_state = "mech_tools" + holding_type = /obj/item/tool/mech_kit + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_UTILITY) + origin_tech = list(TECH_ENGINEERING = 5, TECH_MAGNET = 2, TECH_MATERIAL = 2) + matter = list(MATERIAL_PLASTEEL = 25, MATERIAL_PLASTIC = 10, MATERIAL_SILVER = 5) + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + +/obj/item/tool/mech_kit + name = "mech toolkit" + desc = "A robust selection of mech-sized tools." + icon_state = "engimplant" + force = WEAPON_FORCE_DANGEROUS + worksound = WORKSOUND_DRIVER_TOOL + flags = CONDUCT + tool_qualities = list( + QUALITY_SCREW_DRIVING = 70, + QUALITY_BOLT_TURNING = 70, + QUALITY_DRILLING = 10, + QUALITY_WELDING = 100, + QUALITY_CAUTERIZING = 5, + QUALITY_PRYING = 100, + QUALITY_DIGGING = 50, + QUALITY_PULSING = 50, + QUALITY_WIRE_CUTTING = 100, + QUALITY_HAMMERING = 75) + degradation = 0 + workspeed = 1 + max_upgrades = 1 + spawn_blacklisted = TRUE + +/// Fancy way to move someone up a z-level if you think about it.. +/obj/item/mech_equipment/forklifting_system + name = "forklifting bars" + desc = "a set of forklifts bars. Can be used to elevate crates above by a level.. or people! You can forklift a z-level up by attacking this with itself." + icon_state = "forklift" + restricted_hardpoints = list(HARDPOINT_FRONT) + origin_tech = list(TECH_ENGINEERING = 3, TECH_MATERIAL = 2) + spawn_frequency = 80 + spawn_blacklisted = FALSE + spawn_tags = SPAWN_MECH_QUIPMENT + matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_STEEL = 15, MATERIAL_PLASTIC = 10) + equipment_flags = EQUIPFLAG_UPDTMOVE + var/atom/movable/currentlyLifting = null + var/obj/structure/forklift_platform/platform = null + var/lastZ = null + var/lastDir = null + var/lifted = FALSE + +/obj/item/mech_equipment/forklifting_system/Initialize() + . = ..() + platform = new(NULLSPACE) + platform.master = src + platform.forceMove(src) + +/obj/item/mech_equipment/forklifting_system/Destroy() + if(currentlyLifting) + ejectLifting(get_turf(src)) + if(platform) + QDEL_NULL(platform) + . = ..() + + +/obj/item/mech_equipment/forklifting_system/proc/ejectLifting(atom/target) + currentlyLifting.forceMove(target) + currentlyLifting.transform = null + currentlyLifting.pixel_x = initial(currentlyLifting.pixel_x) + currentlyLifting.pixel_y = initial(currentlyLifting.pixel_y) + currentlyLifting.mouse_opacity = initial(currentlyLifting.mouse_opacity) + owner.vis_contents.Remove(currentlyLifting) + var/mob/targ = currentlyLifting + targ.update_icon() + targ.update_plane() + targ.layer = initial(targ.layer) + if(ismob(targ) && targ.client) + targ.client.perspective = MOB_PERSPECTIVE + targ.client.eye = src + currentlyLifting = null + update_icon() + +/obj/item/mech_equipment/forklifting_system/proc/startLifting(atom/movable/target) + currentlyLifting = target + // No clicking this whilst lifted + currentlyLifting.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + currentlyLifting.forceMove(src) + var/mob/targ = currentlyLifting + if(ismob(targ) && targ.client) + targ.client.perspective = EYE_PERSPECTIVE + targ.client.eye = src + to_chat(targ, SPAN_DANGER("You can resist out of the forklift to instantly get out!")) + update_icon() + +/obj/item/mech_equipment/forklifting_system/uninstalled() + . = ..() + if(currentlyLifting) + ejectLifting(get_turf(owner)) + + +/obj/structure/forklift_platform + layer = TURF_LAYER + 0.5 + icon = MECH_EQUIPMENT_ICON + icon_state = "forklift_platform" + name = "forklift platform" + desc = "A fun way to reach new horizons. Mind the gap between.. small things fall through." + density = FALSE + anchored = TRUE + health = 200 + var/obj/item/mech_equipment/forklifting_system/master = null + +/obj/structure/forklift_platform/Destroy() + if(master) + master.platform = null + master.update_icon() + if(master.owner) + master.owner.update_icon() + master = null + . = ..() + +/// We can prevent the fall of humans and structures , but everything else will just fall down +/obj/structure/forklift_platform/can_prevent_fall(above, atom/movable/mover) + if(!above) + if(ishuman(mover)) + return TRUE + if(isstructure(mover)) + return TRUE + return FALSE + + +/obj/item/mech_equipment/forklifting_system/update_icon() + . = ..() + if(owner) + if(!platform) + icon_state = "forklift_platformless" + return + if(lifted) + icon_state = "forklift_lifted" + else + icon_state = "forklift" + if(currentlyLifting) + if(!locate(currentlyLifting) in owner.vis_contents) + owner.vis_contents.Add(currentlyLifting) + if(owner.dir != lastDir) + lastDir = owner.dir + currentlyLifting.dir = owner.dir + if(lastDir == NORTH) + currentlyLifting.pixel_x = 8 + currentlyLifting.pixel_y = 10 + currentlyLifting.layer = MECH_UNDER_LAYER + if(lastDir == EAST) + currentlyLifting.pixel_x = 33 + currentlyLifting.pixel_y = 8 + currentlyLifting.layer = MECH_ABOVE_LAYER + if(lastDir == SOUTH) + currentlyLifting.pixel_x = 8 + currentlyLifting.pixel_y = 0 + currentlyLifting.layer = MECH_ABOVE_LAYER + if(lastDir == WEST) + currentlyLifting.pixel_x = -15 + currentlyLifting.pixel_y = 8 + currentlyLifting.layer = MECH_ABOVE_LAYER + if(owner.z != lastZ) + lastZ = owner.z + currentlyLifting.z = owner.z + currentlyLifting.update_plane() + +/obj/item/mech_equipment/forklifting_system/attack_self(mob/user) + . = ..() + if(!owner) + return + if(platform) + if(!lifted) + /// We are checking the turf above first + var/turf/aboveSpace = GetAbove(get_turf(owner)) + if(!aboveSpace) + to_chat(user, SPAN_NOTICE("The universe runs out of fabric here! You cannot possibly elevate something here.")) + return + if(!istype(aboveSpace, /turf/simulated/open) || locate(/obj/structure/catwalk) in aboveSpace) + to_chat(user, SPAN_NOTICE("Something dense prevents lifting up.")) + return + /// Then the one infront + above + aboveSpace = get_step(owner, owner.dir) + aboveSpace = GetAbove(aboveSpace) + if(!aboveSpace) + to_chat(user, SPAN_NOTICE("The universe runs out of fabric here! You cannot possibly elevate something here.")) + return + if(!istype(aboveSpace, /turf/simulated/open) || locate(/obj/structure/catwalk) in aboveSpace) + to_chat(user, SPAN_NOTICE("Something dense prevents lifting up.")) + return + to_chat(user, SPAN_NOTICE("You start elevating \the [src] platform.")) + if(do_after(user, 2 SECONDS, owner, TRUE)) + to_chat(user, SPAN_NOTICE("You elevate \the [src]'s platform")) + platform.dir = owner.dir + platform.forceMove(aboveSpace) + owner.update_icon() + if(currentlyLifting) + ejectLifting(aboveSpace) + lifted = TRUE + else + to_chat(user, SPAN_NOTICE("You start retracting the forklift!")) + var/turf/targ = get_turf(platform) + if(do_after(user, 2 SECONDS, owner, TRUE)) + if(!platform) + return + to_chat(user, SPAN_NOTICE("You retract the forklift!")) + lifted = FALSE + platform.forceMove(src) + owner.update_icon() + var/atom/whoWeBringingBack + /// Pick up the first mob , else just get the last atom returned + for(var/atom/movable/A in targ) + if(A == platform) + continue + if(A.anchored) + continue + if(ismob(A)) + whoWeBringingBack = A + break + whoWeBringingBack = A + if(whoWeBringingBack) + startLifting(whoWeBringingBack) + else + to_chat(user, SPAN_NOTICE("You can't lift without a platform!")) + +/obj/item/mech_equipment/forklifting_system/afterattack(atom/movable/target, mob/living/user, inrange, params) + . = ..() + if(.) + if(currentlyLifting && isturf(target) && inrange) + for(var/atom/A in target) + if(A.density) + to_chat(user, SPAN_NOTICE("[A] is taking up space, preventing you from dropping \the [currentlyLifting] here!")) + return + ejectLifting(target) + return + if(currentlyLifting) + to_chat(user, SPAN_NOTICE("You are already lifting something!")) + return + if(!platform) + to_chat(user, SPAN_NOTICE("There is no forklift platform to lift on! You should get it replaced")) + return + if(lifted) + to_chat(user, SPAN_NOTICE("You can't lift someone whilst the forklift is lifted!")) + return + if(inrange && istype(target)) + if(target.anchored) + to_chat(user, SPAN_NOTICE("\The [target] is anchored!")) + return + if(ismob(target)) + var/mob/living/trg = target + if(trg.mob_size >= MOB_HUGE) + to_chat(user, SPAN_NOTICE("\The [target] is far too big to fit on the forklift clamps!")) + return + to_chat(user, SPAN_NOTICE("You start lifting \the [target] onto the hooks.")) + if(do_after(user, 2 SECONDS, target)) + startLifting(target) + update_icon() + + + + + + + diff --git a/code/modules/mechs/interface/_mech_HUD.dm b/code/modules/mechs/interface/_mech_HUD.dm index 37f919e9b92..fbaea551813 100644 --- a/code/modules/mechs/interface/_mech_HUD.dm +++ b/code/modules/mechs/interface/_mech_HUD.dm @@ -55,9 +55,13 @@ /mob/living/exosuit/proc/update_mech_hud_4(var/mob/living/M) if(M.client && M != src && HUDneed.len) if(M in pilots) - for(var/i in HUDneed) if(HUDneed[i]) M.client.screen |= HUDneed[i] + for(var/i in HUDneed) + if(HUDneed[i]) + M.client.screen |= HUDneed[i] + var/obj/screen/movable/exosuit/thing = HUDneed[i] + thing.update_icon() M.reset_view(src) else for(var/i in HUDneed) if(HUDneed[i]) M.client.screen -= HUDneed[i] M.update_hud() - M.check_HUD() \ No newline at end of file + M.check_HUD() diff --git a/code/modules/mechs/interface/datum_HUD.dm b/code/modules/mechs/interface/datum_HUD.dm index f6a6f3c1909..c22a0096cda 100644 --- a/code/modules/mechs/interface/datum_HUD.dm +++ b/code/modules/mechs/interface/datum_HUD.dm @@ -9,6 +9,7 @@ "mech radio" = list("type" = /obj/screen/movable/exosuit/radio, "loc" = "WEST:4,CENTER-3:58"), "rename mech" = list("type" = /obj/screen/movable/exosuit/rename, "loc" = "WEST:4,CENTER-3:69"), "mech camera" = list("type" = /obj/screen/movable/exosuit/toggle/camera, "loc" = "WEST:4,CENTER-3:80"), + "mech power switch" = list("type" = /obj/screen/movable/exosuit/toggle/power_control, "loc" = "WEST:4,CENTER-3:-12"), "mech health" = list("type" = /obj/screen/movable/exosuit/health, "loc" = "WEST:4,BOTTOM+3"), "mech power" = list("type" = /obj/screen/movable/exosuit/power, "loc" = "WEST+1:4,BOTTOM+3"), "strafe" = list("type" = /obj/screen/movable/exosuit/toggle/strafe, "loc" = "WEST:4,CENTER-3:92"), diff --git a/code/modules/mechs/interface/screen_objects.dm b/code/modules/mechs/interface/screen_objects.dm index 48acaff5c43..ceffb89b6e6 100644 --- a/code/modules/mechs/interface/screen_objects.dm +++ b/code/modules/mechs/interface/screen_objects.dm @@ -1,8 +1,11 @@ // Screen objects hereon out. + +#define MECH_UI_STYLE(X) "" + X + "" + /obj/screen/movable/exosuit name = "hardpoint" icon = MECH_HUD_ICON - icon_state = "hardpoint" + icon_state = "base" var/mob/living/exosuit/owner /obj/screen/movable/exosuit/proc/on_handle_hud(var/mob/living/exosuit/E) @@ -13,7 +16,10 @@ /obj/screen/movable/exosuit/radio name = "radio" - icon_state = "radio" + //icon_state = "radio" + maptext = MECH_UI_STYLE("RADIO") + maptext_x = 5 + maptext_y = 12 /obj/screen/movable/exosuit/radio/Click() if(..()) @@ -22,6 +28,7 @@ /obj/screen/movable/exosuit/hardpoint name = "hardpoint" + icon_state = "hardpoint" desc = "To activate additional hardpoint's options click on it with shift-button." var/hardpoint_tag var/obj/item/holding @@ -44,6 +51,7 @@ if(holding) holding.screen_loc = screen_loc /obj/screen/movable/exosuit/hardpoint/proc/update_system_info() + maptext = null // No point drawing it if we have no item to use or nobody to see it. if(!holding || !owner) @@ -120,7 +128,9 @@ var/modifiers = params2list(params) if(modifiers["ctrl"]) if(owner.hardpoints_locked) to_chat(usr, SPAN_WARNING("Hardpoint ejection system is locked.")) - else if(owner.remove_system(hardpoint_tag)) to_chat(usr, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint.")) + else if(owner.remove_system(hardpoint_tag)) + update_system_info() + to_chat(usr, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint.")) else to_chat(usr, SPAN_DANGER("You fail to remove the system mounted to your [hardpoint_tag] hardpoint.")) else if(modifiers["shift"] && holding) holding.attack_self(usr) else if(owner.selected_hardpoint == hardpoint_tag) @@ -128,16 +138,38 @@ owner.clear_selected_hardpoint() else if(owner.set_hardpoint(hardpoint_tag)) icon_state = "hardpoint_selected" + +/obj/screen/movable/exosuit/toggle/power_control + name = "Power control" + icon_state = "small_important" + maptext = MECH_UI_STYLE("POWER") + maptext_x = 3 + maptext_y = 13 + +/obj/screen/movable/exosuit/toggle/power_control/toggled() + . = ..() + owner.toggle_power(usr) + +/obj/screen/movable/exosuit/toggle/power_control/update_icon() + toggled = (owner.power == MECH_POWER_ON) + . = ..() + /obj/screen/movable/exosuit/eject name = "eject" - icon_state = "eject" + //icon_state = "eject" + maptext = MECH_UI_STYLE("EJECT") + maptext_x = 5 + maptext_y = 12 /obj/screen/movable/exosuit/eject/Click() if(..()) owner.eject(usr) /obj/screen/movable/exosuit/rename name = "rename" - icon_state = "rename" + //icon_state = "rename" + maptext = MECH_UI_STYLE("RENAME") + maptext_x = 1 + maptext_y = 12 /obj/screen/movable/exosuit/power name = "power" @@ -146,33 +178,46 @@ maptext_width = 64 maptext_x = 2 maptext_y = 20 - maptext = "power" + /obj/screen/movable/exosuit/power/on_handle_hud(var/mob/living/exosuit/E) . = ..() if(owner) var/obj/item/cell/C = owner.get_cell() - if(C && istype(C)) maptext = "[round(C.charge)]/[round(C.maxcharge)]" - else maptext = "CHECK POWER" + if(C && istype(C)) maptext = MECH_UI_STYLE("[round(C.charge)]/[round(C.maxcharge)]") + else maptext = MECH_UI_STYLE("CHECK POWER") /obj/screen/movable/exosuit/rename/Click() if(..()) owner.rename(usr) /obj/screen/movable/exosuit/toggle name = "toggle" - var/toggled + var/toggled = FALSE + +/obj/screen/movable/exosuit/toggle/LateInitialize() + . = ..() + update_icon() + +/obj/screen/movable/exosuit/toggle/update_icon() + . = ..() + icon_state = "[initial(icon_state)][toggled ? "_enabled" : ""]" + maptext = FONT_COLORED(toggled ? COLOR_WHITE : COLOR_GRAY, initial(maptext)) /obj/screen/movable/exosuit/toggle/Click() if(..()) toggled() /obj/screen/movable/exosuit/toggle/proc/toggled() toggled = !toggled - icon_state = "[initial(icon_state)][toggled ? "_enabled" : ""]" + update_icon() return toggled /obj/screen/movable/exosuit/toggle/air name = "air" - icon_state = "air" + //icon_state = "air" + icon_state = "small_important" + maptext = MECH_UI_STYLE("AIR") + maptext_x = 9 + maptext_y = 13 /obj/screen/movable/exosuit/toggle/air/toggled() owner.use_air = ..() @@ -180,7 +225,11 @@ /obj/screen/movable/exosuit/toggle/maint name = "toggle maintenance protocol" - icon_state = "maint" + //icon_state = "maint" + icon_state = "small" + maptext = MECH_UI_STYLE("MAINT") + maptext_x = 5 + maptext_y = 13 /obj/screen/movable/exosuit/toggle/maint/toggled() owner.maintenance_protocols = ..() @@ -188,7 +237,10 @@ /obj/screen/movable/exosuit/toggle/hardpoint name = "toggle hardpoint lock" - icon_state = "hardpoint_lock" + //icon_state = "hardpoint_lock" + maptext = MECH_UI_STYLE("GEAR") + maptext_x = 5 + maptext_y = 12 /obj/screen/movable/exosuit/toggle/hardpoint/toggled() owner.hardpoints_locked = ..() @@ -196,7 +248,10 @@ /obj/screen/movable/exosuit/toggle/hatch name = "toggle hatch lock" - icon_state = "hatch_lock" + //icon_state = "hatch_lock" + maptext = MECH_UI_STYLE("LOCK") + maptext_x = 5 + maptext_y = 12 /obj/screen/movable/exosuit/toggle/hatch/toggled() if(!owner.hatch_locked && !owner.hatch_closed) @@ -205,20 +260,39 @@ if(owner.body && owner.body.total_damage >= owner.body.max_damage) to_chat(usr, SPAN_WARNING("\The body of [owner] is far too damaged to close its hatch!")) return - owner.hatch_locked = ..() + owner.hatch_locked = owner.toggle_hatch_lock() to_chat(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked.")) + update_icon() + +/obj/screen/movable/exosuit/toggle/hatch/update_icon() + toggled = owner.hatch_locked + . = ..() /obj/screen/movable/exosuit/toggle/hatch_open name = "open or close hatch" - icon_state = "hatch_status" + //icon_state = "hatch_status" + maptext = MECH_UI_STYLE("CLOSE") + maptext_x = 4 + maptext_y = 12 /obj/screen/movable/exosuit/toggle/hatch_open/toggled() if(owner.hatch_locked && owner.hatch_closed) to_chat(usr, SPAN_WARNING("You cannot open the hatch while it is locked.")) return - owner.hatch_closed = ..() + owner.hatch_closed = owner.toggle_hatch() to_chat(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ].")) owner.update_icon() + update_icon() + +/obj/screen/movable/exosuit/toggle/hatch_open/update_icon() + toggled = owner.hatch_closed + . = ..() + if(toggled) + maptext = MECH_UI_STYLE("OPEN") + maptext_x = 5 + else + maptext = MECH_UI_STYLE("CLOSE") + maptext_x = 4 // This is basically just a holder for the updates the exosuit does. /obj/screen/movable/exosuit/health @@ -268,7 +342,11 @@ //Controls if cameras set the vision flags /obj/screen/movable/exosuit/toggle/camera name = "toggle camera matrix" - icon_state = "camera" + //icon_state = "camera" + icon_state = "small_important" + maptext = MECH_UI_STYLE("SENSOR") + maptext_x = 1 + maptext_y = 13 /obj/screen/movable/exosuit/toggle/camera/toggled() if(!owner.head) @@ -277,8 +355,15 @@ if(!owner.head.vision_flags) to_chat(usr, SPAN_WARNING("Alternative sensor configurations not found. Contact manufacturer for more details.")) return - owner.head.active_sensors = ..() + owner.head.active_sensors = owner.toggle_sensors() to_chat(usr, SPAN_NOTICE("[owner.head.name] advanced sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active.")) + update_icon() + +/obj/screen/movable/exosuit/toggle/camera/update_icon() + if(owner.head) + toggled = owner.head.active_sensors + else toggled = FALSE + . = ..() /obj/screen/movable/exosuit/needle vis_flags = VIS_INHERIT_ID diff --git a/code/modules/mechs/mech.dm b/code/modules/mechs/mech.dm index 8fa752ca3bf..8aca6d835c4 100644 --- a/code/modules/mechs/mech.dm +++ b/code/modules/mechs/mech.dm @@ -50,6 +50,8 @@ var/list/hardpoints = list() var/hardpoints_locked var/maintenance_protocols + /// For equipment that has a process based on mech Life tick + var/list/obj/item/mech_equipment/tickers = list() // Material var/material/material = MATERIAL_STEEL @@ -73,6 +75,8 @@ var/obj/screen/movable/exosuit/toggle/power_control/hud_power_control var/obj/screen/movable/exosuit/toggle/camera/hud_camera + var/power = MECH_POWER_OFF + // Strafing - Is the mech currently strafing? var/strafing = FALSE @@ -80,6 +84,26 @@ for(var/mob/i in pilots) to_chat(i, msg) +/mob/living/exosuit/proc/toggle_power(mob/living/user) + if(power == MECH_POWER_TRANSITION) + to_chat(user, SPAN_NOTICE("Power transition in progress. Please wait.")) + else if(power == MECH_POWER_ON) //Turning it off is instant + playsound(src, 'sound/mechs/mech-shutdown.ogg', 100, 0) + power = MECH_POWER_OFF + else if(get_cell(TRUE)) + //Start power up sequence + power = MECH_POWER_TRANSITION + playsound(src, 'sound/mechs/powerup.ogg', 50, 0) + if(do_after(user, 1.5 SECONDS, src) && power == MECH_POWER_TRANSITION) + playsound(src, 'sound/mechs/nominal.ogg', 50, 0) + power = MECH_POWER_ON + else + to_chat(user, SPAN_WARNING("You abort the powerup sequence.")) + power = MECH_POWER_OFF + //hud_power_control?.queue_icon_update() + else + to_chat(user, SPAN_WARNING("Error: No power cell was detected.")) + /* @@ -138,6 +162,9 @@ if(head && head.radio) radio = new(src) + if(body) + opacity = body.opaque_chassis + if(LAZYLEN(component_descriptions)) desc = "[desc] It has been built with [english_list(component_descriptions)]." @@ -197,12 +224,30 @@ to_chat(user, "It menaces with reinforcements of [material].") to_chat(user, SPAN_NOTICE("You can remove people inside by HARM intent clicking with your hand. The hatch must be opened.")) - to_chat(user, SPAN_NOTICE("You can insert ammo into any ballistic weapon by attacking this with ammunition")) + to_chat(user, SPAN_NOTICE("You can eject any module from its UI by CtrlClicking the hardpoint button.")) + if(body.storage_compartment) + to_chat(user, SPAN_NOTICE("You can acces its internal storage by click-dragging onto your character.")) + if(body && body.cell_charge_rate) + to_chat(user, SPAN_NOTICE("This mech can recharge any cell storaged in its internal storage at a rate of [body.cell_charge_rate].")) + if(arms && arms.can_force_doors) + to_chat(user, SPAN_NOTICE("The arms on this mech can force open any unbolted door.")) + if(locate(/obj/item/mech_equipment/mounted_system/ballistic) in contents) + to_chat(user, SPAN_NOTICE("You can insert ammo into any ballistic weapon by attacking this with ammunition.")) + if(locate(/obj/item/mech_equipment/auto_mender) in contents) + to_chat(user, SPAN_NOTICE("You can refill its auto mender by attacking the mech with trauma kits.")) + if(locate(/obj/item/mech_equipment/forklifting_system) in contents) + to_chat(user, SPAN_NOTICE("You can remove objects from this mech's forklifting system by using grab intent.")) + if(locate(/obj/item/mech_equipment/towing_hook) in contents) + to_chat(user, SPAN_NOTICE("You can remove objects from this mech's towing system by using grab intent.")) + if(locate(/obj/item/mech_equipment/power_generator/fueled) in contents) + to_chat(user, SPAN_NOTICE("You can refill the mounted power generators by attacking \the [src] with the fuel they use.")) + if(locate(/obj/item/mech_equipment/power_generator/fueled/welding) in contents) + to_chat(user, SPAN_NOTICE("You can drain from the mounted fuel welding fuel generator by attacking with a beaker on GRAB intent")) /mob/living/exosuit/return_air() if(src && loc) - if(ispath(body) || !hatch_closed) + if(ispath(body) || !hatch_closed || body.pilot_coverage < 100) var/turf/current_loc = get_turf(src) return current_loc.return_air() if(body.pilot_coverage >= 100 && hatch_closed) @@ -212,14 +257,6 @@ /mob/living/exosuit/GetIdCard() return access_card -/mob/living/exosuit/set_dir() - . = ..() - if(.) - update_pilots() - for(var/obj/item/mech_equipment/shield_generator/gen in contents) - if(gen && gen.visual_bluff) - gen.updateVisualBluff(dir) - /mob/living/exosuit/proc/return_temperature() return bodytemperature diff --git a/code/modules/mechs/mech_construction.dm b/code/modules/mechs/mech_construction.dm index 900a9690d75..600780d1690 100644 --- a/code/modules/mechs/mech_construction.dm +++ b/code/modules/mechs/mech_construction.dm @@ -128,9 +128,10 @@ user.visible_message(SPAN_NOTICE("\The [user] begins trying to remove \the [system] from \the [src].")) if(!do_after(user, delay, src) || hardpoints[system_hardpoint] != system) return 0 - hardpoints[system_hardpoint] = null - if(system_hardpoint == selected_hardpoint) clear_selected_hardpoint() + hardpoints[system_hardpoint] = null + // Remove this from screens. Would just be left on a player screen before , SPCR - 2023 + system.screen_loc = null var/obj/item/mech_equipment/ME = system if(istype(ME)) ME.uninstalled() diff --git a/code/modules/mechs/mech_damage.dm b/code/modules/mechs/mech_damage.dm index 4ac5b950af8..dfb30a50d74 100644 --- a/code/modules/mechs/mech_damage.dm +++ b/code/modules/mechs/mech_damage.dm @@ -83,7 +83,12 @@ /mob/living/exosuit/adjustFireLoss(amount, obj/item/mech_component/MC = null) if(!MC) - MC = pick(list(arms, legs, body, head)) + var/list/picklist = list() + if(arms) picklist.Add(arms) + if(legs) picklist.Add(legs) + if(head) picklist.Add(head) + if(body) picklist.Add(body) + MC = pick(picklist) if(amount < 1) return FALSE MC.take_burn_damage(amount) @@ -91,7 +96,12 @@ /mob/living/exosuit/adjustBruteLoss(amount, obj/item/mech_component/MC = null) if(!MC) - MC = pick(list(arms, legs, body, head)) + var/list/picklist = list() + if(arms) picklist.Add(arms) + if(legs) picklist.Add(legs) + if(head) picklist.Add(head) + if(body) picklist.Add(body) + MC = pick(picklist) if(amount < 1) return FALSE MC.take_brute_damage(amount) @@ -124,6 +134,9 @@ /mob/living/exosuit/bullet_act(obj/item/projectile/P, var/def_zone) var/hit_dir = get_dir(P.starting, src) def_zone = zoneToComponent(def_zone) + /// aiming for soemthing the mech doesnt have + if(!def_zone) + return PROJECTILE_FORCE_MISS if (P.is_hot() >= HEAT_MOBIGNITE_THRESHOLD) IgniteMob() diff --git a/code/modules/mechs/mech_interaction.dm b/code/modules/mechs/mech_interaction.dm index aee217d58ed..fee206731ea 100644 --- a/code/modules/mechs/mech_interaction.dm +++ b/code/modules/mechs/mech_interaction.dm @@ -49,15 +49,19 @@ if(A.loc != src && !(get_dir(src, A) & dir)) return - if(!arms) - to_chat(user, SPAN_WARNING("\The [src] has no manipulators!")) - setClickCooldown(3) - return - - if(!arms.motivator || !arms.motivator.is_functional()) - to_chat(user, SPAN_WARNING("Your motivators are damaged! You can't use your manipulators!")) - setClickCooldown(15) - return + if(!selected_system) + if(arms) + if(!get_cell()?.checked_use(arms.power_use * CELLRATE)) + to_chat(user, power == MECH_POWER_ON ? SPAN_WARNING("Error: Power levels insufficient.") : SPAN_WARNING("\The [src] is powered off.")) + return + if(!arms.motivator || !arms.motivator.is_functional()) + to_chat(user, SPAN_WARNING("Your motivators are damaged! You can't use your manipulators!")) + setClickCooldown(15) + return + else + to_chat(user, SPAN_WARNING("\The [src] has no manipulators!")) + setClickCooldown(3) + return var/obj/item/cell/cell = get_cell() if(!cell) @@ -65,11 +69,6 @@ setClickCooldown(3) return - if(!cell.checked_use(arms.power_use * CELLRATE)) - to_chat(user, SPAN_WARNING("Error: Power levels insufficient.")) - setClickCooldown(3) - return - if(istype(selected_system, /obj/item/mech_equipment) && !check_equipment_software(selected_system)) to_chat(user, SPAN_WARNING("Error: No control software was found for [selected_system].")) setClickCooldown(3) @@ -110,7 +109,7 @@ var/resolved if(adj) - resolved = selected_system.resolve_attackby(A, src, params) + resolved = selected_system.resolve_attackby(A, user, params) if(!resolved && A && selected_system) selected_system.afterattack(A,user,adj,params) @@ -124,11 +123,23 @@ if(A == src) setClickCooldown(5) return attack_self(user) - else if(adj) + else if(adj && arms) setClickCooldown(arms_action_delay()) playsound(src.loc, arms.punch_sound, 45 + 25 * (arms.melee_damage / 50), -1) - if(arms) + if(user.a_intent == I_HURT) return A.attack_generic(src, arms.melee_damage, "attacked") + else if(user.a_intent == I_DISARM && arms.can_force_doors) + if(istype(A, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/door = A + if(!door.locked) + to_chat(user, SPAN_NOTICE("You start forcing \the [door] open!")) + visible_message(SPAN_WARNING("\The [src] starts forcing \the [door] open!")) + playsound(src, 'sound/machines/airlock_creaking.ogg', 100, 1, 5,5) + if(do_after(user, 3 SECONDS, A, FALSE)) + door.open(TRUE) + return + else + return A.attackby(arms, user, params) /// Checks the mech for places to store the ore. /mob/living/exosuit/proc/getOreCarrier() @@ -266,6 +277,7 @@ to_chat(user, SPAN_WARNING("\The [I] could not be installed in that hardpoint.")) return + /// Gun reloading handling if(istype(I, /obj/item/ammo_magazine)|| istype(I, /obj/item/ammo_casing)) if(!maintenance_protocols) to_chat(user, SPAN_NOTICE("\The [src] needs to be in maintenance mode to reload its guns!")) @@ -281,21 +293,87 @@ chosen = loadable_guns[chosen] else chosen = loadable_guns[loadable_guns[1]] - switch(chosen.loadMagazine(I,user)) - if(-1) - to_chat(user, SPAN_NOTICE("\The [chosen] does not accept this type of magazine.")) - if(0) - to_chat(user, SPAN_NOTICE("\The [chosen] has no slots left in its ammunition storage.")) - if(1) - to_chat(user, SPAN_NOTICE("You load \the [I] into \the [chosen].")) - if(2) - to_chat(user, SPAN_NOTICE("You partially reload one of the existing ammo magazines inside of \the [chosen].")) - - else if(user.a_intent != I_HURT) + if(chosen) + switch(chosen.loadMagazine(I,user)) + if(-1) + to_chat(user, SPAN_NOTICE("\The [chosen] does not accept this type of magazine.")) + if(0) + to_chat(user, SPAN_NOTICE("\The [chosen] has no slots left in its ammunition storage.")) + if(1) + to_chat(user, SPAN_NOTICE("You load \the [I] into \the [chosen].")) + if(2) + to_chat(user, SPAN_NOTICE("You partially reload one of the existing ammo magazines inside of \the [chosen].")) + + /// Medical mender handling + if(istype(I, /obj/item/stack/medical/advanced/bruise_pack)) + var/list/choices = list() + for(var/hardpoint in hardpoints) + if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/auto_mender)) + var/obj/item/mech_equipment/auto_mender/mend = hardpoints[hardpoint] + choices["[hardpoint] - [mend.trauma_charges_stored]/[mend.trauma_storage_max] charges"] = mend + var/obj/item/mech_equipment/auto_mender/choice = null + if(!length(choices)) + return + if(length(choices) == 1) + choice = choices[choices[1]] + else + var/chosenMender = input("Select mech mender to refill") as null|anything in choices + if(chosenMender) + choice = choices[chosenMender] + if(choice) + choice.attackby(I, user) + return + + /// Plasma generator handling + if(istype(I, /obj/item/stack/material/plasma)) + var/list/choices = list() + for(var/hardpoint in hardpoints) + if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/power_generator/fueled/plasma)) + var/obj/item/mech_equipment/power_generator/fueled/plasma/gen = hardpoints[hardpoint] + choices["[hardpoint] - [gen.fuel_amount]/[gen.fuel_max]"] = gen + var/obj/item/mech_equipment/power_generator/fueled/plasma/chosen = null + if(!length(choices)) + return + if(length(choices)==1) + chosen = choices[choices[1]] + else + var/chosenGen = input("Select generator to refill") as null|anything in choices + if(chosenGen) + chosen = choices[chosenGen] + if(chosen) + chosen.attackby(I, user) + return + + /// Welding generator handling + /// Double negation to turn into 0/1 format since if its more than 1 it doesn't count as true. + if(I.is_drainable()) + if(!maintenance_protocols) + to_chat(user, SPAN_NOTICE("\The [src] needs to be in maintenance mode for you to refill its internal generator!")) + return + var/list/choices = list() + for(var/hardpoint in hardpoints) + if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/power_generator/fueled/welding)) + var/obj/item/mech_equipment/power_generator/fueled/welding/gen = hardpoints[hardpoint] + choices["[hardpoint] - [gen.fuel_amount]/[gen.fuel_max]"] = gen + var/obj/item/mech_equipment/power_generator/fueled/welding/chosen = null + if(!length(choices)) + return + if(length(choices)==1) + chosen = choices[choices[1]] + else + var/chosenGen = input("Select generator to refill") as null|anything in choices + if(chosenGen) + chosen = choices[chosenGen] + if(chosen) + chosen.attackby(I, user) + return + + + else if(user.a_intent != I_HELP) if(attack_tool(I, user)) return // we use BP_CHEST cause we dont need to convert targeted organ to mech format def zoning - else if(user.a_intent == I_HURT && !hatch_closed && get_dir(user, src) == reverse_dir[dir] && get_mob() && !(user in pilots) && user.targeted_organ == BP_CHEST) + else if(user.a_intent != I_HELP && !hatch_closed && get_dir(user, src) == reverse_dir[dir] && get_mob() && !(user in pilots) && user.targeted_organ == BP_CHEST) var/mob/living/target = get_mob() target.attackby(I, user) return @@ -306,8 +384,10 @@ if(!maintenance_protocols) to_chat(user, SPAN_WARNING("The power cell bay is locked while maintenance protocols are disabled.")) return TRUE - - var/obj/item/cell/cell = get_cell() + if(!body) + to_chat(user, SPAN_NOTICE("\The [src] has no slot for a battery to be installed unto!")) + return + var/obj/item/cell/cell = body.cell if(cell) to_chat(user, SPAN_WARNING("\The [src] already has [cell] installed!")) return TRUE @@ -445,13 +525,17 @@ if(QUALITY_PRYING) - var/obj/item/cell/cell = get_cell() + if(!body) + to_chat(user, SPAN_NOTICE("\The [src] has no body to pry out a cell from!")) + return + var/obj/item/cell/cell = body.cell if(cell) if(!maintenance_protocols) to_chat(user, SPAN_WARNING("The power cell bay is locked while maintenance protocols are disabled.")) return TRUE to_chat(user, SPAN_NOTICE("You start removing [cell] from \the [src].")) if(do_mob(user, src, 30) && cell == body.cell && body.eject_item(cell, user)) + power = MECH_POWER_OFF body.cell = null return @@ -469,9 +553,56 @@ if(ABORT_CHECK) return +/// Used by hatch lock UI button +/mob/living/exosuit/proc/toggle_hatch_lock() + if(hatch_locked) + hatch_locked = FALSE + else + if(body && body.total_damage >= body.max_damage) + return FALSE + hatch_locked = TRUE + return hatch_locked + +/// Used by hatch toggle mech UI button +/mob/living/exosuit/proc/toggle_hatch() + if(hatch_locked) + return hatch_closed + else + hatch_closed = !hatch_closed + return hatch_closed + +/// Used by camera toglge UI button +/mob/living/exosuit/proc/toggle_sensors() + if(head) + if(!head.active_sensors) + if(get_cell().drain_power(0,0,head.power_use)) + head.active_sensors = TRUE + return TRUE + return FALSE + else + head.active_sensors = FALSE + return FALSE + return FALSE /mob/living/exosuit/attack_hand(mob/living/user) // Drag the pilot out if possible. + if(user.a_intent == I_GRAB) + for(var/obj/item/mech_equipment/towing_hook/towing in contents) + if(towing.currentlyTowing) + to_chat(user, SPAN_NOTICE("You start removing \the [towing.currentlyTowing] from \the [src]'s towing hook.")) + if(do_after(user, 3 SECONDS, src, TRUE)) + to_chat(user, SPAN_NOTICE("You remove \the [towing.currentlyTowing] from \the [src]'s towing hook.")) + towing.UnregisterSignal(towing.currentlyTowing,list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING)) + towing.currentlyTowing = null + return + for(var/obj/item/mech_equipment/forklifting_system/fork in contents) + if(fork.currentlyLifting) + to_chat(user, SPAN_NOTICE("You start removing \the [fork.currentlyLifting] from \the [src]'s forklift.")) + if(do_after(user, 3 SECONDS ,src , TRUE)) + to_chat(user, SPAN_NOTICE("You remove \the [fork.currentlyLifting] from \the [src]'s forklift!")) + fork.ejectLifting(get_turf(user)) + return + if(user.a_intent == I_HURT) if(!LAZYLEN(pilots)) to_chat(user, SPAN_WARNING("There is nobody inside \the [src].")) diff --git a/code/modules/mechs/mech_life.dm b/code/modules/mechs/mech_life.dm index 74cb759ce44..4354609b478 100644 --- a/code/modules/mechs/mech_life.dm +++ b/code/modules/mechs/mech_life.dm @@ -13,23 +13,64 @@ update_pilots() if(radio) - radio.on = (head && head.radio && head.radio.is_functional()) + radio.on = (head && head.radio && head.radio.is_functional() && get_cell()) - body.update_air(hatch_closed && use_air) + var/powered = FALSE + var/obj/item/cell/mech_cell = get_cell() + for(var/hardpoint in hardpoints) + var/obj/item/mech_equipment/equip = hardpoints[hardpoint] + if(QDELETED(equip)) + continue + if(!(equip.equipment_flags & EQUIPFLAG_PRETICK)) + continue + equip.pretick() + + if(mech_cell) + powered = mech_cell.drain_power(0, 0, calc_power_draw()) > 0 + + if(!powered) + //Shut down all systems + if(head) + head.active_sensors = FALSE + for(var/hardpoint in hardpoints) + var/obj/item/mech_equipment/M = hardpoints[hardpoint] + if(istype(M) && M.active && M.passive_power_use) + M.deactivate() + // for chassis charging cells + var/chargeUsed = 0 + if(powered && body && body.cell_charge_rate && mech_cell.charge > 1000) + for(var/obj/item/cell/to_charge in body.storage_compartment) + if(mech_cell.charge < 1000) + break + if(chargeUsed > body.cell_charge_rate) + break + var/chargeNeeded = min(to_charge.maxcharge - to_charge.charge, body.cell_charge_rate) + if(!chargeNeeded) + continue + chargeUsed += to_charge.give(mech_cell.drain_power(0,0, chargeNeeded / CELLRATE)) - if((client || LAZYLEN(pilots)) && get_cell()) - var/obj/item/cell/c = get_cell() - c.drain_power(0, 0, calc_power_draw()) + + body.update_air(hatch_closed && use_air) updatehealth() if(health <= 0 && stat != DEAD) death() . = ..() //Handles stuff like environment lying = FALSE // Fuck off, carp. - handle_vision() + handle_vision(powered) + +/mob/living/exosuit/get_cell(force) + RETURN_TYPE(/obj/item/cell) + + if(power == MECH_POWER_ON || force) //For most intents we can assume that a powered off exosuit acts as if it lacked a cell + . = body ? body.cell : null + if(!.) + for(var/obj/item/mech_equipment/power_generator/gen in tickers) + if(!. && gen.internal_cell) + . = gen.internal_cell + return . + return null -/mob/living/exosuit/get_cell() - return body?.get_cell() /mob/living/exosuit/proc/calc_power_draw() //Passive power stuff here. You can also recharge cells or hardpoints if those make sense @@ -38,7 +79,8 @@ var/obj/item/mech_equipment/I = hardpoints[hardpoint] if(!istype(I)) continue - total_draw += I.passive_power_use + + total_draw += I.active ? I.active_power_use : I.passive_power_use if(head && head.active_sensors) total_draw += head.power_use @@ -77,14 +119,18 @@ var/obj/wreck = new wreckage_path(drop_location(), src, gibbed) wreck.name = "wreckage of \the [name]" if(!gibbed) - if(arms.loc != src) - arms = null - if(legs.loc != src) - legs = null - if(head.loc != src) - head = null - if(body.loc != src) - body = null + if(arms) + if(arms.loc != src) + arms = null + if(legs) + if(legs.loc != src) + legs = null + if(head) + if(head.loc != src) + head = null + if(body) + if(body.loc != src) + body = null // Handle the rest of things. ..(gibbed, (gibbed ? "explodes!" : "grinds to a halt before collapsing!")) @@ -116,10 +162,12 @@ qdel(src) return -/mob/living/exosuit/handle_vision() +/mob/living/exosuit/handle_vision(powered) if(head) - sight = head.get_sight() - see_invisible = head.get_invisible() + sight = head.get_sight(powered) + see_invisible = head.get_invisible(powered) + else if(hatch_closed) + sight &= BLIND if(body && (body.pilot_coverage < 100 || body.transparent_cabin) || !hatch_closed) sight &= ~BLIND diff --git a/code/modules/mechs/mech_movement.dm b/code/modules/mechs/mech_movement.dm index dac935b20b4..40663ce6d1c 100644 --- a/code/modules/mechs/mech_movement.dm +++ b/code/modules/mechs/mech_movement.dm @@ -40,6 +40,25 @@ victim.forceMove(theDepths) visible_message("The [src] pushes [victim] downwards.") occupant_message("You can feel \the [src] step onto something.") + for(var/hardpoint in hardpoints) + if(!hardpoints[hardpoint]) + continue + var/obj/item/mech_equipment/thing = hardpoints[hardpoint] + if(!(thing.equipment_flags & EQUIPFLAG_UPDTMOVE)) + continue + thing.update_icon() + +/mob/living/exosuit/set_dir() + . = ..() + if(.) + update_pilots() + for(var/hardpoint in hardpoints) + if(!hardpoints[hardpoint]) + continue + var/obj/item/mech_equipment/thing = hardpoints[hardpoint] + if(!(thing.equipment_flags & EQUIPFLAG_UPDTMOVE)) + continue + thing.update_icon() /mob/living/exosuit/get_jetpack() for(var/hardpoint_thing in hardpoints) @@ -178,11 +197,17 @@ /mob/living/exosuit/proc/moveBlocked() for(var/hardpoint in hardpoints) - var/obj/item/mech_equipment/shield_generator/ballistic/blocker = hardpoints[hardpoint] - if(!istype(blocker)) - continue - if(blocker.on) - return "\The [blocker] is deployed! Immobilizing you. " + var/obj/item/mech_equipment/equip = hardpoints[hardpoint] + if(equip) + switch(equip.type) + if(/obj/item/mech_equipment/shield_generator/ballistic) + var/obj/item/mech_equipment/shield_generator/ballistic/blocker = equip + if(blocker.on) + return "\The [blocker] is deployed! Immobilizing you. " + if(/obj/item/mech_equipment/forklifting_system) + var/obj/item/mech_equipment/forklifting_system/fork = equip + if(fork.lifted) + return "\The [fork] is lifted, locking you in place!" return "" diff --git a/code/modules/mechs/premade/_premade.dm b/code/modules/mechs/premade/_premade.dm index 5f36892beb3..49ddd4f4df3 100644 --- a/code/modules/mechs/premade/_premade.dm +++ b/code/modules/mechs/premade/_premade.dm @@ -26,10 +26,14 @@ /mob/living/exosuit/premade/Initialize() - arms = new arms(src) - body = new body(src) - head = new head(src) - legs = new legs(src) + if(arms) + arms = new arms(src) + if(body) + body = new body(src) + if(head) + head = new head(src) + if(legs) + legs = new legs(src) for(var/obj/item/mech_component/C in list(arms, legs, head, body)) if(decal) diff --git a/code/modules/mechs/premade/powerloader.dm b/code/modules/mechs/premade/powerloader.dm index 4475beb9411..c94f8775d30 100644 --- a/code/modules/mechs/premade/powerloader.dm +++ b/code/modules/mechs/premade/powerloader.dm @@ -44,3 +44,21 @@ HARDPOINT_RIGHT_HAND = /obj/item/mech_equipment/mounted_system/extinguisher, HARDPOINT_HEAD = /obj/item/mech_equipment/light, ) + +/mob/living/exosuit/premade/forklift + name = "Aster's Guild \"Forklift\"" + desc = "A modernized forklift for usage on space-ships. Are you ready to lift?" + rarity_value = 40 + material = MATERIAL_PLASTIC + installed_armor = /obj/item/robot_parts/robot_component/armour/exosuit/plain + exosuit_color = "#c6c37b" + body = /obj/item/mech_component/chassis/forklift + legs = /obj/item/mech_component/propulsion/wheels + arms = null + head = null + installed_software_boards = list( + /obj/item/electronics/circuitboard/exosystem/utility + ) + installed_systems = list( + HARDPOINT_FRONT = /obj/item/mech_equipment/forklifting_system + ) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 9f6e69b5ade..36764b163a6 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -112,6 +112,10 @@ process_glasses(G,TRUE) /mob/living/carbon/human/reset_layer() + /// The forklift handles it for us here. + if(istype(loc, /obj/item/mech_equipment/forklifting_system)) + if(lying) set_plane(LYING_HUMAN_PLANE) + return if(hiding) set_plane(HIDING_MOB_PLANE) layer = HIDING_MOB_LAYER diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm index d3604bcf7eb..0c0c56467d9 100644 --- a/code/modules/mob/living/carbon/resist.dm +++ b/code/modules/mob/living/carbon/resist.dm @@ -14,6 +14,11 @@ escape_inventory(src.loc) return + if(istype(loc, /obj/item/mech_equipment/forklifting_system)) + var/obj/item/mech_equipment/forklifting_system/fork = loc + fork.ejectLifting(get_turf(fork)) + return + //unbuckling yourself if(buckled) if (buckled.resist_buckle(src)) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 68d451ddc45..30b67f081e2 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -91,8 +91,8 @@ messageturfs += turf - - + + for(var/mob/M in getMobsInRangeChunked(get_turf(src), range, FALSE, TRUE)) if(!M.client) continue @@ -610,6 +610,11 @@ to_chat(src, "It won't budge!") return + if(SEND_SIGNAL(AM, COMSIG_ATTEMPT_PULLING) == COMSIG_PULL_CANCEL) + to_chat(src, SPAN_WARNING("It won't budge!")) + return + + var/mob/M = AM if(ismob(AM)) diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm index 17377ed1302..59ad0902313 100644 --- a/code/modules/multiz/structures.dm +++ b/code/modules/multiz/structures.dm @@ -242,6 +242,10 @@ icon_state = "ramptop" layer = 2.4 +/obj/structure/multiz/stairs/can_prevent_fall(above) + return above ? FALSE : TRUE + + /obj/structure/multiz/stairs/enter icon_state = "ramptop" diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index 57f1b12bc1f..da01d672368 100755 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -90,14 +90,14 @@ see multiz/movement.dm for some info. if(!below) return - if(catwalk != (locate(/obj/structure/catwalk) in src)) - return - - if(locate(/obj/structure/multiz/stairs) in src) - return + /// If anything on our turf stops falls downwards + for(var/atom/A in contents) + if(A.can_prevent_fall(FALSE, null)) + return + /// If anything below stops falls from above for(var/atom/A in below) - if(A.can_prevent_fall()) + if(A.can_prevent_fall(TRUE,null)) return return TRUE @@ -117,6 +117,10 @@ see multiz/movement.dm for some info. P.height = HEIGHT_LOW // We are shooting from above, this protects windows from damage return // We are done here + for(var/atom/A in contents) + if(A.can_prevent_fall(FALSE, mover)) + return + if(!mover.can_fall()) return diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index d47f4372d37..70987683fec 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -135,7 +135,6 @@ explode() return FALSE - if(maxcharge < amount) return FALSE var/amount_used = min(maxcharge-charge,amount) charge += amount_used update_icon() diff --git a/code/modules/research/designs/mechs2/exosuits_components.dm b/code/modules/research/designs/mechs2/exosuits_components.dm index c3be59c7d8b..38fe446e2c7 100644 --- a/code/modules/research/designs/mechs2/exosuits_components.dm +++ b/code/modules/research/designs/mechs2/exosuits_components.dm @@ -86,6 +86,9 @@ /datum/design/research/item/mechfab/exosuit/chassis/pod build_path = /obj/item/mech_component/chassis/pod +/datum/design/research/item/mechfab/exosuit/chassis/forklift + build_path = /obj/item/mech_component/chassis/forklift + //Manipulators /datum/design/research/item/mechfab/exosuit/manipulators category = "Exosuit Manipulators" @@ -124,3 +127,6 @@ /datum/design/research/item/mechfab/exosuit/propulsion/tracks build_path = /obj/item/mech_component/propulsion/tracks + +/datum/design/research/item/mechfab/exosuit/propulsion/wheels + build_path = /obj/item/mech_component/propulsion/wheels diff --git a/code/modules/research/designs/mechs2/exosuits_equipment.dm b/code/modules/research/designs/mechs2/exosuits_equipment.dm index bd0fc4305d9..ee9afd41de1 100644 --- a/code/modules/research/designs/mechs2/exosuits_equipment.dm +++ b/code/modules/research/designs/mechs2/exosuits_equipment.dm @@ -88,13 +88,40 @@ name = "mounted ion thrusters" build_path = /obj/item/mech_equipment/thrusters +/datum/design/research/item/exosuit/forklift + name = "forklift clamps" + build_path = /obj/item/mech_equipment/forklifting_system + +/datum/design/research/item/exosuit/fuel_generator + name = "welding fuel mech generator" + build_path = /obj/item/mech_equipment/power_generator/fueled/welding + +/datum/design/research/item/exosuit/plasma_generator + name = "plasma mech generator" + build_path = /obj/item/mech_equipment/power_generator/fueled/plasma + +/datum/design/research/item/exosuit/towing_hook + name = "mech towing hook" + build_path = /obj/item/mech_equipment/towing_hook + //MEDICAL /datum/design/research/item/exosuit/sleeper name = "mounted sleeper" build_path = /obj/item/mech_equipment/sleeper +/datum/design/research/item/exosuit/sleeper/upgraded + name = "mounted sleeper MK2" + build_path = /obj/item/mech_equipment/sleeper/upgraded + +/datum/design/research/item/exosuit/automender + name = "mech auto-mender" + build_path = /obj/item/mech_equipment/auto_mender //ENGINEERING /datum/design/research/item/exosuit/rcd name = "mounted RCD" build_path = /obj/item/mech_equipment/mounted_system/rcd + +/datum/design/research/item/exosuit/toolkit + name = "mounted toolkit" + build_path = /obj/item/mech_equipment/mounted_system/toolkit diff --git a/code/modules/research/nodes/robotics.dm b/code/modules/research/nodes/robotics.dm index d7c8377b1ce..94bd7401670 100644 --- a/code/modules/research/nodes/robotics.dm +++ b/code/modules/research/nodes/robotics.dm @@ -60,7 +60,9 @@ /datum/design/research/item/mechfab/exosuit/sensors/light, /datum/design/research/item/mechfab/exosuit/chassis/light, /datum/design/research/item/mechfab/exosuit/manipulators/light, - /datum/design/research/item/mechfab/exosuit/propulsion/light + /datum/design/research/item/mechfab/exosuit/propulsion/light, + /datum/design/research/item/mechfab/exosuit/propulsion/wheels, + /datum/design/research/item/mechfab/exosuit/chassis/forklift ) @@ -205,7 +207,9 @@ unlocks_designs = list( /datum/design/research/circuit/exosuit/medical, - /datum/design/research/item/exosuit/sleeper + /datum/design/research/item/exosuit/sleeper, + /datum/design/research/item/exosuit/sleeper/upgraded, + /datum/design/research/item/exosuit/automender ) /datum/technology/mech_utility_modules @@ -231,7 +235,13 @@ /datum/design/research/item/mechfab/exosuit/drillbit/steel, /datum/design/research/item/mechfab/exosuit/drillbit/plasteel, /datum/design/research/item/mechfab/exosuit/drillbit/diamond, - /datum/design/research/item/exosuit/ion_thruster + /datum/design/research/item/exosuit/ion_thruster, + /datum/design/research/item/exosuit/forklift, + /datum/design/research/item/exosuit/fuel_generator, + /datum/design/research/item/exosuit/plasma_generator, + /datum/design/research/item/exosuit/towing_hook, + /datum/design/research/item/exosuit/rcd, + /datum/design/research/item/exosuit/toolkit ) /datum/technology/mech_teleporter_modules diff --git a/icons/mechs/bshield.dmi b/icons/mechs/bshield.dmi index dda9fa60bc9..2f998c7a7f3 100644 Binary files a/icons/mechs/bshield.dmi and b/icons/mechs/bshield.dmi differ diff --git a/icons/mechs/mech_equipment.dmi b/icons/mechs/mech_equipment.dmi index 78cddcd85c4..0c2c6540a36 100644 Binary files a/icons/mechs/mech_equipment.dmi and b/icons/mechs/mech_equipment.dmi differ diff --git a/icons/mechs/mech_hud.dmi b/icons/mechs/mech_hud.dmi index 029be31e2e4..2d86a4aaef9 100644 Binary files a/icons/mechs/mech_hud.dmi and b/icons/mechs/mech_hud.dmi differ diff --git a/icons/mechs/mech_parts.dmi b/icons/mechs/mech_parts.dmi index 581b5456b67..218142a2e95 100644 Binary files a/icons/mechs/mech_parts.dmi and b/icons/mechs/mech_parts.dmi differ diff --git a/icons/mechs/mech_parts_held.dmi b/icons/mechs/mech_parts_held.dmi index 0276b3fb0aa..76494a5d865 100644 Binary files a/icons/mechs/mech_parts_held.dmi and b/icons/mechs/mech_parts_held.dmi differ diff --git a/icons/mechs/mech_weapon_overlays.dmi b/icons/mechs/mech_weapon_overlays.dmi index 28f0eb261bc..c5f97e07556 100644 Binary files a/icons/mechs/mech_weapon_overlays.dmi and b/icons/mechs/mech_weapon_overlays.dmi differ diff --git a/icons/mechs/shield.dmi b/icons/mechs/shield.dmi index a2d5131a605..c46b5a5ac62 100644 Binary files a/icons/mechs/shield.dmi and b/icons/mechs/shield.dmi differ diff --git a/sound/mechs/mech-shutdown.ogg b/sound/mechs/mech-shutdown.ogg new file mode 100644 index 00000000000..9733bb26df5 Binary files /dev/null and b/sound/mechs/mech-shutdown.ogg differ diff --git a/sound/mechs/mech_generator.ogg b/sound/mechs/mech_generator.ogg new file mode 100644 index 00000000000..16b178d05ce Binary files /dev/null and b/sound/mechs/mech_generator.ogg differ