From f0d00759a3fba22496f833e560d24b74335692f6 Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 21:04:00 -0400 Subject: [PATCH 01/41] Initial commit, only repaths --- beestation.dme | 56 +++---- code/__DEFINES/cooldowns.dm | 7 +- .../dcs/signals/signals_obj/signals_mech.dm | 6 +- code/__DEFINES/is_helpers.dm | 2 +- code/__DEFINES/vehicles.dm | 8 + code/_onclick/ai.dm | 4 - code/_onclick/click.dm | 4 - code/_onclick/hud/human.dm | 2 +- code/datums/components/armor_plate.dm | 2 +- code/game/atoms.dm | 4 - code/game/data_huds.dm | 8 +- .../game/gamemodes/clown_ops/clown_weapons.dm | 10 +- code/game/machinery/doors/door.dm | 13 +- code/game/machinery/doors/windowdoor.dm | 12 +- .../machinery/porta_turret/portable_turret.dm | 12 +- code/game/objects/effects/effects.dm | 3 - code/game/objects/items.dm | 3 - code/game/objects/items/devices/camera_bug.dm | 2 +- code/game/objects/obj_defense.dm | 21 --- code/game/objects/structures/window.dm | 5 - code/game/turfs/closed/walls.dm | 18 --- .../scriptures/sigil_transmission.dm | 2 +- .../heretic/magic/ash_ascension.dm | 2 +- code/modules/cargo/bounties/mech.dm | 18 +-- code/modules/fields/timestop.dm | 8 +- code/modules/mob/living/brain/MMI.dm | 2 +- code/modules/mob/living/brain/brain.dm | 11 +- code/modules/mob/living/carbon/human/death.dm | 5 - .../mob/living/carbon/human/human_defense.dm | 37 ----- code/modules/mob/living/living_defense.dm | 28 ---- code/modules/mob/living/silicon/ai/ai.dm | 4 +- code/modules/mob/living/silicon/ai/life.dm | 2 +- .../living/simple_animal/hostile/hostile.dm | 8 +- .../simple_animal/hostile/mecha_pilot.dm | 145 +++++++++--------- .../simple_animal/hostile/megafauna/drake.dm | 8 +- .../hostile/megafauna/hierophant.dm | 13 +- .../hostile/retaliate/retaliate.dm | 10 +- .../simple_animal/hostile/space_dragon.dm | 6 +- .../living/simple_animal/hostile/statue.dm | 8 +- .../mob/living/simple_animal/simple_animal.dm | 4 +- code/modules/mob/mob.dm | 2 +- code/modules/ninja/suit/ninjaDrainAct.dm | 4 +- .../projectiles/projectile/special/rocket.dm | 2 +- code/modules/recycling/disposal/bin.dm | 2 +- code/modules/shuttle/supply.dm | 2 +- code/modules/shuttle/white_ship.dm | 2 +- code/modules/uplink/uplink_items.dm | 6 +- code/modules/vehicles/_vehicle.dm | 7 +- .../vehicles}/mecha/combat/combat.dm | 0 .../vehicles}/mecha/combat/durand.dm | 0 .../vehicles}/mecha/combat/gygax.dm | 0 .../vehicles}/mecha/combat/honker.dm | 0 .../vehicles}/mecha/combat/marauder.dm | 0 .../vehicles}/mecha/combat/phazon.dm | 0 .../vehicles}/mecha/combat/reticence.dm | 0 .../mecha/equipment/mecha_equipment.dm | 0 .../mecha/equipment/tools/medical_tools.dm | 0 .../mecha/equipment/tools/mining_tools.dm | 0 .../mecha/equipment/tools/other_tools.dm | 0 .../mecha/equipment/tools/weapon_bay.dm | 0 .../mecha/equipment/tools/work_tools.dm | 0 .../mecha/equipment/weapons/weapons.dm | 0 .../vehicles}/mecha/mech_bay.dm | 0 .../vehicles/mecha/mech_melee_attack.dm | 0 .../{game => modules/vehicles}/mecha/mecha.dm | 0 .../vehicles}/mecha/mecha_actions.dm | 0 .../mecha/mecha_construction_paths.dm | 0 .../vehicles}/mecha/mecha_control_console.dm | 0 .../vehicles}/mecha/mecha_defense.dm | 0 .../vehicles}/mecha/mecha_parts.dm | 0 .../vehicles}/mecha/mecha_topic.dm | 0 .../vehicles}/mecha/mecha_wreckage.dm | 0 .../vehicles}/mecha/medical/medical.dm | 0 .../vehicles}/mecha/medical/odysseus.dm | 0 .../vehicles}/mecha/working/ripley.dm | 0 .../vehicles}/mecha/working/working.dm | 0 code/modules/vehicles/sealed.dm | 4 +- 77 files changed, 216 insertions(+), 338 deletions(-) rename code/{game => modules/vehicles}/mecha/combat/combat.dm (100%) rename code/{game => modules/vehicles}/mecha/combat/durand.dm (100%) rename code/{game => modules/vehicles}/mecha/combat/gygax.dm (100%) rename code/{game => modules/vehicles}/mecha/combat/honker.dm (100%) rename code/{game => modules/vehicles}/mecha/combat/marauder.dm (100%) rename code/{game => modules/vehicles}/mecha/combat/phazon.dm (100%) rename code/{game => modules/vehicles}/mecha/combat/reticence.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/mecha_equipment.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/tools/medical_tools.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/tools/mining_tools.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/tools/other_tools.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/tools/weapon_bay.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/tools/work_tools.dm (100%) rename code/{game => modules/vehicles}/mecha/equipment/weapons/weapons.dm (100%) rename code/{game => modules/vehicles}/mecha/mech_bay.dm (100%) create mode 100644 code/modules/vehicles/mecha/mech_melee_attack.dm rename code/{game => modules/vehicles}/mecha/mecha.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_actions.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_construction_paths.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_control_console.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_defense.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_parts.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_topic.dm (100%) rename code/{game => modules/vehicles}/mecha/mecha_wreckage.dm (100%) rename code/{game => modules/vehicles}/mecha/medical/medical.dm (100%) rename code/{game => modules/vehicles}/mecha/medical/odysseus.dm (100%) rename code/{game => modules/vehicles}/mecha/working/ripley.dm (100%) rename code/{game => modules/vehicles}/mecha/working/working.dm (100%) diff --git a/beestation.dme b/beestation.dme index fa0cc518924a6..8f5d4e19d2d10 100644 --- a/beestation.dme +++ b/beestation.dme @@ -1160,33 +1160,6 @@ #include "code\game\machinery\telecomms\machines\receiver.dm" #include "code\game\machinery\telecomms\machines\relay.dm" #include "code\game\machinery\telecomms\machines\server.dm" -#include "code\game\mecha\mech_bay.dm" -#include "code\game\mecha\mecha.dm" -#include "code\game\mecha\mecha_actions.dm" -#include "code\game\mecha\mecha_construction_paths.dm" -#include "code\game\mecha\mecha_control_console.dm" -#include "code\game\mecha\mecha_defense.dm" -#include "code\game\mecha\mecha_parts.dm" -#include "code\game\mecha\mecha_topic.dm" -#include "code\game\mecha\mecha_wreckage.dm" -#include "code\game\mecha\combat\combat.dm" -#include "code\game\mecha\combat\durand.dm" -#include "code\game\mecha\combat\gygax.dm" -#include "code\game\mecha\combat\honker.dm" -#include "code\game\mecha\combat\marauder.dm" -#include "code\game\mecha\combat\phazon.dm" -#include "code\game\mecha\combat\reticence.dm" -#include "code\game\mecha\equipment\mecha_equipment.dm" -#include "code\game\mecha\equipment\tools\medical_tools.dm" -#include "code\game\mecha\equipment\tools\mining_tools.dm" -#include "code\game\mecha\equipment\tools\other_tools.dm" -#include "code\game\mecha\equipment\tools\weapon_bay.dm" -#include "code\game\mecha\equipment\tools\work_tools.dm" -#include "code\game\mecha\equipment\weapons\weapons.dm" -#include "code\game\mecha\medical\medical.dm" -#include "code\game\mecha\medical\odysseus.dm" -#include "code\game\mecha\working\ripley.dm" -#include "code\game\mecha\working\working.dm" #include "code\game\objects\buckling.dm" #include "code\game\objects\empulse.dm" #include "code\game\objects\items.dm" @@ -3984,6 +3957,35 @@ #include "code\modules\vehicles\wheelchair.dm" #include "code\modules\vehicles\cars\car.dm" #include "code\modules\vehicles\cars\clowncar.dm" +#include "code\modules\vehicles\mecha\_mecha.dm" +#include "code\modules\vehicles\mecha\mech_bay.dm" +#include "code\modules\vehicles\mecha\mech_fabricator.dm" +#include "code\modules\vehicles\mecha\mech_melee_attack.dm" +#include "code\modules\vehicles\mecha\mecha_actions.dm" +#include "code\modules\vehicles\mecha\mecha_construction_paths.dm" +#include "code\modules\vehicles\mecha\mecha_control_console.dm" +#include "code\modules\vehicles\mecha\mecha_defense.dm" +#include "code\modules\vehicles\mecha\mecha_parts.dm" +#include "code\modules\vehicles\mecha\mecha_topic.dm" +#include "code\modules\vehicles\mecha\mecha_wreckage.dm" +#include "code\modules\vehicles\mecha\combat\combat.dm" +#include "code\modules\vehicles\mecha\combat\durand.dm" +#include "code\modules\vehicles\mecha\combat\gygax.dm" +#include "code\modules\vehicles\mecha\combat\honker.dm" +#include "code\modules\vehicles\mecha\combat\marauder.dm" +#include "code\modules\vehicles\mecha\combat\phazon.dm" +#include "code\modules\vehicles\mecha\combat\reticence.dm" +#include "code\modules\vehicles\mecha\equipment\mecha_equipment.dm" +#include "code\modules\vehicles\mecha\equipment\tools\medical_tools.dm" +#include "code\modules\vehicles\mecha\equipment\tools\mining_tools.dm" +#include "code\modules\vehicles\mecha\equipment\tools\other_tools.dm" +#include "code\modules\vehicles\mecha\equipment\tools\weapon_bay.dm" +#include "code\modules\vehicles\mecha\equipment\tools\work_tools.dm" +#include "code\modules\vehicles\mecha\equipment\weapons\mecha_ammo.dm" +#include "code\modules\vehicles\mecha\equipment\weapons\weapons.dm" +#include "code\modules\vehicles\mecha\medical\odysseus.dm" +#include "code\modules\vehicles\mecha\working\ripley.dm" +#include "code\modules\vehicles\mecha\working\working.dm" #include "code\modules\vending\_vending.dm" #include "code\modules\vending\assist.dm" #include "code\modules\vending\autodrobe.dm" diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 6db88cc37d951..029b849c11629 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -37,7 +37,12 @@ #define COOLDOWN_CIRCUIT_PATHFIND_DIF "circuit_pathfind_different" #define COOLDOWN_CIRCUIT_TARGET_INTERCEPT "circuit_target_intercept" - +//Mecha cooldowns +#define COOLDOWN_MECHA_MESSAGE "mecha_message" +#define COOLDOWN_MECHA_EQUIPMENT "mecha_equipment" +#define COOLDOWN_MECHA_ARMOR "mecha_armor" +#define COOLDOWN_MECHA_MELEE_ATTACK "mecha_melee" +#define COOLDOWN_MECHA_SMOKE "mecha_smoke" //TIMER COOLDOWN MACROS diff --git a/code/__DEFINES/dcs/signals/signals_obj/signals_mech.dm b/code/__DEFINES/dcs/signals/signals_obj/signals_mech.dm index 568b56ca8f860..21d78398d8e05 100644 --- a/code/__DEFINES/dcs/signals/signals_obj/signals_mech.dm +++ b/code/__DEFINES/dcs/signals/signals_obj/signals_mech.dm @@ -2,5 +2,7 @@ // When the signal is called: (signal arguments) // All signals send the source datum of the signal as the first argument -// /obj/mecha signals -#define COMSIG_MECHA_ACTION_ACTIVATE "mecha_action_activate" //sent from mecha action buttons to the mecha they're linked to +// /obj/vehicle/sealed/mecha signals + +///sent from mecha action buttons to the mecha they're linked to +#define COMSIG_MECHA_ACTION_TRIGGER "mecha_action_activate" diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index fbb6dc398b428..c157cd69e39d1 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -244,7 +244,7 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list( #define ismachinery(A) (istype(A, /obj/machinery)) -#define ismecha(A) (istype(A, /obj/mecha)) +#define ismecha(A) (istype(A, /obj/vehicle/sealed/mecha)) #define is_cleanable(A) (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/rune)) //if something is cleanable diff --git a/code/__DEFINES/vehicles.dm b/code/__DEFINES/vehicles.dm index 224375211363d..3c14abc593895 100644 --- a/code/__DEFINES/vehicles.dm +++ b/code/__DEFINES/vehicles.dm @@ -4,6 +4,14 @@ #define VEHICLE_CONTROL_DRIVE 2 #define VEHICLE_CONTROL_KIDNAPPED 4 //! Can't leave vehicle voluntarily, has to resist. +//Mech flags +#define ADDING_ACCESS_POSSIBLE (1<<0) +#define ADDING_MAINT_ACCESS_POSSIBLE (1<<1) +#define CANSTRAFE (1<<2) +#define LIGHTS_ON (1<<3) +#define SILICON_PILOT (1<<4) +#define IS_ENCLOSED (1<<5) +#define HAS_LIGHTS (1<<6) //Car trait flags #define CAN_KIDNAP 1 diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index fd0da7cf49cf6..f69f0471932a0 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -59,10 +59,6 @@ if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlShiftClickOn(A) return - if(LAZYACCESS(modifiers, MIDDLE_CLICK)) - if(controlled_mech) //Are we piloting a mech? Placed here so the modifiers are not overridden. - controlled_mech.click_action(A, src, params) //Override AI normal click behavior. - return if(LAZYACCESS(modifiers, SHIFT_CLICK)) ShiftClickOn(A) return diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index e8aac70c8206d..83d607f51196e 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -109,10 +109,6 @@ if(!LAZYACCESS(modifiers, "catcher") && A.IsObscured()) return - if(ismecha(loc)) - var/obj/mecha/M = loc - return M.click_action(A,src,params) - if(restrained()) changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow RestrainedClickOn(A) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 6f673b6f5cccc..5db86b5337e8a 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -29,7 +29,7 @@ /atom/movable/screen/human/equip/Click() if(ismecha(usr.loc)) // stops inventory actions in a mech - return 1 + return TRUE var/mob/living/carbon/human/H = usr H.quick_equip() diff --git a/code/datums/components/armor_plate.dm b/code/datums/components/armor_plate.dm index f721f84324bfe..31e00be857a26 100644 --- a/code/datums/components/armor_plate.dm +++ b/code/datums/components/armor_plate.dm @@ -69,7 +69,7 @@ O.armor = O.armor.attachArmor(added_armor) if(ismecha(O)) - var/obj/mecha/R = O + var/obj/vehicle/sealed/mecha/R = O R.update_icon() to_chat(user, "You strengthen [R], improving its resistance against melee, bullet and laser damage.") else diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 42f6b8153845a..d753341651c9e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1076,10 +1076,6 @@ setDir(newdir) return TRUE -///Handle melee attack by a mech -/atom/proc/mech_melee_attack(obj/mecha/M) - return - /** * Called when the atom log's in or out * diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 965f51f1ca5c8..c3700470764fc 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -396,14 +396,14 @@ /*~~~~~~~~~~~~~~~~~~~~ BIG STOMPY MECHS ~~~~~~~~~~~~~~~~~~~~~*/ -/obj/mecha/proc/diag_hud_set_mechhealth() +/obj/vehicle/sealed/mecha/proc/diag_hud_set_mechhealth() var/image/holder = hud_list[DIAG_MECH_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size holder.icon_state = "huddiag[RoundDiagBar(obj_integrity/max_integrity)]" -/obj/mecha/proc/diag_hud_set_mechcell() +/obj/vehicle/sealed/mecha/proc/diag_hud_set_mechcell() var/image/holder = hud_list[DIAG_BATT_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size @@ -414,7 +414,7 @@ holder.icon_state = "hudnobatt" -/obj/mecha/proc/diag_hud_set_mechstat() +/obj/vehicle/sealed/mecha/proc/diag_hud_set_mechstat() var/image/holder = hud_list[DIAG_STAT_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size @@ -422,7 +422,7 @@ if(internal_damage) holder.icon_state = "hudwarn" -/obj/mecha/proc/diag_hud_set_mechtracking() //Shows tracking beacons on the mech +/obj/vehicle/sealed/mecha/proc/diag_hud_set_mechtracking() //Shows tracking beacons on the mech var/image/holder = hud_list[DIAG_TRACK_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm index f0c7dabdc45b8..63babc558d09e 100644 --- a/code/game/gamemodes/clown_ops/clown_weapons.dm +++ b/code/game/gamemodes/clown_ops/clown_weapons.dm @@ -257,7 +257,7 @@ projectiles = 8 projectile_energy_cost = 1000 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana/can_attach(obj/vehicle/sealed/mecha/combat/honker/M) if(..()) if(istype(M)) return TRUE @@ -275,13 +275,13 @@ equip_cooldown = 60 det_time = 20 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache/can_attach(obj/vehicle/sealed/mecha/combat/honker/M) if(..()) if(istype(M)) return TRUE return FALSE -/obj/mecha/combat/honker/dark +/obj/vehicle/sealed/mecha/combat/honker/dark desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. This one has been painted black for maximum fun. HONK!" name = "\improper Dark H.O.N.K" icon_state = "darkhonker" @@ -295,14 +295,14 @@ wreckage = /obj/structure/mecha_wreckage/honker/dark max_equip = 4 -/obj/mecha/combat/honker/dark/add_cell(obj/item/stock_parts/cell/C) +/obj/vehicle/sealed/mecha/combat/honker/dark/add_cell(obj/item/stock_parts/cell/C) if(C) C.forceMove(src) cell = C return cell = new /obj/item/stock_parts/cell/hyper(src) -/obj/mecha/combat/honker/dark/loaded/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/honker/dark/loaded/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index c3087a4e3e4c4..362cc4d79c96c 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -109,17 +109,6 @@ bumpopen(M) return - if(ismecha(AM)) - var/obj/mecha/mecha = AM - if(density) - if(mecha.occupant) - if(world.time - mecha.occupant.last_bumped <= 10) - return - mecha.occupant.last_bumped = world.time - if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access))) - open() - else - do_animate("deny") return if(isitem(AM)) @@ -381,7 +370,7 @@ //add_blood doesn't work for borgs/xenos, but add_blood_floor does. L.add_splatter_floor(location) log_combat(src, L, "crushed") - for(var/obj/mecha/M in get_turf(src)) + for(var/obj/vehicle/sealed/mecha/M in get_turf(src)) M.take_damage(DOOR_CRUSH_DAMAGE) log_combat(src, M, "crushed") /obj/machinery/door/proc/autoclose() diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 7321d5a7aa380..8b7ce2988545c 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -78,11 +78,13 @@ return if(!ismob(AM)) if(ismecha(AM)) - var/obj/mecha/mecha = AM - if(mecha.occupant && allowed(mecha.occupant)) - open_and_close() - else - do_animate("deny") + var/obj/vehicle/sealed/mecha/mecha = AM + for(var/O in mecha.occupants) + var/mob/living/occupant = O + if(allowed(occupant)) + open_and_close() + return + do_animate("deny") return if(!SSticker) return diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 93cb744a7e5ef..16d183f64e064 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -451,11 +451,13 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/porta_turret) if(!in_faction(C)) targets += C for(var/A in GLOB.mechas_list) - if((get_dist(A, T) < scan_range) && can_see(T, A, scan_range)) - var/obj/mecha/Mech = A - if(Mech.occupant && !in_faction(Mech.occupant)) //If there is a user and they're not in our faction - if(assess_perp(Mech.occupant) >= 4) - targets += Mech + if((get_dist(A, base) < scan_range) && can_see(base, A, scan_range)) + var/obj/vehicle/sealed/mecha/mech = A + for(var/O in mech.occupants) + var/mob/living/occupant = O + if(!in_faction(occupant)) //If there is a user and they're not in our faction + if(assess_perp(occupant) >= 4) + targets += mech if(check_anomalies && GLOB.blobs.len && (mode == TURRET_LETHAL)) for(var/obj/structure/blob/B in view(scan_range, T)) diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index 07d3b6ada8697..872d6c6ccd41d 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -28,9 +28,6 @@ /obj/effect/acid_act() return -/obj/effect/mech_melee_attack(obj/mecha/M) - return 0 - /obj/effect/blob_act(obj/structure/blob/B) return diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 2740ed4653b32..9d2ff6f2f2efa 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -977,9 +977,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) return ..() return 0 -/obj/item/mech_melee_attack(obj/mecha/M) - return 0 - /obj/item/burn() if(!QDELETED(src)) var/turf/T = get_turf(src) diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm index 1fcc30d2b0c9d..e3ba5227963ef 100644 --- a/code/game/objects/items/devices/camera_bug.dm +++ b/code/game/objects/items/devices/camera_bug.dm @@ -170,7 +170,7 @@ dat += " (Stage [stage])" dat += " \[Track\]
" - for(var/obj/mecha/M in seen) + for(var/obj/vehicle/sealed/mecha/M in seen) if(M.name in names) names[M.name]++ dat += "[M.name] ([names[M.name]])" diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 52fdb93c3f106..de778fb134f2c 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -156,27 +156,6 @@ damage *= 1.1 attack_generic(M, damage, MELEE, 1) -/obj/mech_melee_attack(obj/mecha/M) - M.do_attack_animation(src) - var/play_soundeffect = 0 - var/mech_damtype = M.damtype - if(M.selected) - mech_damtype = M.selected.damtype - play_soundeffect = 1 - else - switch(M.damtype) - if(BRUTE) - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - if(BURN) - playsound(src, 'sound/items/welder.ogg', 50, 1) - if(TOX) - playsound(src, 'sound/effects/spray2.ogg', 50, 1) - return 0 - else - return 0 - M.visible_message("[M.name] hits [src]!", "You hit [src]!", null, COMBAT_MESSAGE_RANGE) - return take_damage(M.force*3, mech_damtype, MELEE, play_soundeffect, get_dir(src, M)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs. - /obj/singularity_act() SSexplosions.high_mov_atom += src if(src && !QDELETED(src)) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 9b4ccdb196164..32cccadffb133 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -253,11 +253,6 @@ /obj/structure/window/proc/check_state_and_anchored(checked_state, checked_anchored) return check_state(checked_state) && check_anchored(checked_anchored) -/obj/structure/window/mech_melee_attack(obj/mecha/M) - if(!can_be_reached()) - return - ..() - /obj/structure/window/proc/can_be_reached(mob/user) if(fulltile) return TRUE diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 716660669e0b6..3133b2e8815ee 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -114,24 +114,6 @@ else add_dent(WALL_DENT_HIT) -/turf/closed/wall/mech_melee_attack(obj/mecha/M) - M.do_attack_animation(src) - switch(M.damtype) - if(BRUTE) - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - M.visible_message("[M.name] hits [src]!", \ - "You hit [src]!", null, COMBAT_MESSAGE_RANGE) - if(prob(hardness + M.force) && M.force > 20) - dismantle_wall(1) - playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1) - else - add_dent(WALL_DENT_HIT) - if(BURN) - playsound(src, 'sound/items/welder.ogg', 100, 1) - if(TOX) - playsound(src, 'sound/effects/spray2.ogg', 100, 1) - return FALSE - /turf/closed/wall/attack_paw(mob/living/user) user.changeNext_move(CLICK_CD_MELEE) return attack_hand(user) diff --git a/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm b/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm index 05a3956cbe491..8c55f34b89556 100644 --- a/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm +++ b/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm @@ -55,7 +55,7 @@ /obj/structure/destructible/clockwork/sigil/transmission/apply_effects(atom/movable/AM) if(istype(AM, /obj/mecha)) - var/obj/mecha/M = AM + var/obj/vehicle/sealed/mecha/M = AM var/mob/living/O = M.occupant var/obj/item/stock_parts/cell/C = M.cell if(!C) diff --git a/code/modules/antagonists/heretic/magic/ash_ascension.dm b/code/modules/antagonists/heretic/magic/ash_ascension.dm index 30bb757fa47d7..4b4d2ef267ed8 100644 --- a/code/modules/antagonists/heretic/magic/ash_ascension.dm +++ b/code/modules/antagonists/heretic/magic/ash_ascension.dm @@ -136,7 +136,7 @@ new /obj/effect/hotspot(T) T.hotspot_expose(700,50,1) // deals damage to mechs - for(var/obj/mecha/M in T.contents) + for(var/obj/vehicle/sealed/mecha/M in T.contents) if(M in hit_list) continue hit_list += M diff --git a/code/modules/cargo/bounties/mech.dm b/code/modules/cargo/bounties/mech.dm index 62c846ea96a32..053c4817724df 100644 --- a/code/modules/cargo/bounties/mech.dm +++ b/code/modules/cargo/bounties/mech.dm @@ -5,8 +5,8 @@ /datum/bounty/item/mech/ship(obj/O) if(!applies_to(O)) return - if(istype(O, /obj/mecha)) - var/obj/mecha/M = O + if(istype(O, /obj/vehicle/sealed/mecha)) + var/obj/vehicle/sealed/mecha/M = O M.wreckage = null // So the mech doesn't explode. ..() @@ -16,29 +16,29 @@ /datum/bounty/item/mech/ripleymkii name = "APLU MK-II \"Ripley\"" reward = 13000 - wanted_types = list(/obj/mecha/working/ripley/mkii) + wanted_types = list(/obj/vehicle/sealed/mecha/working/ripley/mkii) /datum/bounty/item/mech/firefighter name = "APLU \"Firefighter\"" reward = 18000 - wanted_types = list(/obj/mecha/working/ripley/firefighter) + wanted_types = list(/obj/vehicle/sealed/mecha/working/ripley/firefighter) /datum/bounty/item/mech/odysseus name = "Odysseus" reward = 11000 - wanted_types = list(/obj/mecha/medical/odysseus) + wanted_types = list(/obj/vehicle/sealed/mecha/medical/odysseus) /datum/bounty/item/mech/gygax name = "Gygax" reward = 28000 - wanted_types = list(/obj/mecha/combat/gygax) + wanted_types = list(/obj/vehicle/sealed/mecha/combat/gygax) /datum/bounty/item/mech/durand name = "Durand" reward = 20000 - wanted_types = list(/obj/mecha/combat/durand) + wanted_types = list(/obj/vehicle/sealed/mecha/combat/durand) /datum/bounty/item/mech/phazon name = "Phazon" - reward = 50000 - wanted_types = list(/obj/mecha/combat/phazon) + reward = 100000 + wanted_types = list(/obj/vehicle/sealed/mecha/combat/phazon) diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index 6de103dda0fa5..7b27d3609fb2d 100644 --- a/code/modules/fields/timestop.dm +++ b/code/modules/fields/timestop.dm @@ -84,7 +84,7 @@ freeze_mob(A) else if(istype(A, /obj/projectile)) freeze_projectile(A) - else if(istype(A, /obj/mecha)) + else if(istype(A, /obj/vehicle/sealed/mecha)) freeze_mecha(A) else frozen = FALSE @@ -116,7 +116,7 @@ unfreeze_mob(A) else if(istype(A, /obj/projectile)) unfreeze_projectile(A) - else if(istype(A, /obj/mecha)) + else if(istype(A, /obj/vehicle/sealed/mecha)) unfreeze_mecha(A) UnregisterSignal(A, COMSIG_MOVABLE_PRE_MOVE) @@ -127,10 +127,10 @@ global_frozen_atoms -= A -/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/M) +/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/vehicle/sealed/mecha/M) M.completely_disabled = TRUE -/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/M) +/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/vehicle/sealed/mecha/M) M.completely_disabled = FALSE diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 4714edc6ee7a9..1755df54f3b51 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -8,7 +8,7 @@ var/obj/item/radio/radio = null //Let's give it a radio. var/mob/living/brain/brainmob = null //The current occupant. var/mob/living/silicon/robot = null //Appears unused. - var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm. + var/obj/vehicle/sealed/mecha = null //This does not appear to be used outside of reference in mecha.dm. var/obj/item/organ/brain/brain = null //The actual brain var/datum/ai_laws/laws = new() var/force_replace_ai_name = FALSE diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index 3536574d11252..4d41913254288 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -36,7 +36,7 @@ return ..() /mob/living/brain/update_mobility() - if(in_contents_of(/obj/mecha)) + if(in_contents_of(/obj/vehicle/sealed/mecha)) mobility_flags = MOBILITY_FLAGS_DEFAULT else mobility_flags = NONE @@ -66,13 +66,6 @@ if(stored_dna) stored_dna.real_name = real_name -/mob/living/brain/ClickOn(atom/A, params) - ..() - if(container) - var/obj/mecha/M = container.mecha - if(istype(M)) - return M.click_action(A,src,params) - /mob/living/brain/forceMove(atom/destination) if(container) return container.forceMove(destination) @@ -93,7 +86,7 @@ if(!container) return if (container.mecha) - var/obj/mecha/M = container.mecha + var/obj/vehicle/sealed/mecha/M = container.mecha if(M.mouse_pointer) client.mouse_pointer_icon = M.mouse_pointer if (client && ranged_ability && ranged_ability.ranged_mousepointer) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 0de5ea66f2428..6d52c5b5eb0a9 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -61,11 +61,6 @@ dizziness = 0 jitteriness = 0 - if(ismecha(loc)) - var/obj/mecha/M = loc - if(M.occupant == src) - M.go_out() - if(!QDELETED(dna)) //The gibbed param is bit redundant here since dna won't exist at this point if they got deleted. dna.species.spec_death(gibbed, src) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 46103244cabed..9a6b0c3aca5c8 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -350,43 +350,6 @@ var/armor_block = run_armor_check(affecting, MELEE) apply_damage(damage, BRUTE, affecting, armor_block) -/mob/living/carbon/human/mech_melee_attack(obj/mecha/M) - - if(M.occupant.a_intent == INTENT_HARM) - M.do_attack_animation(src) - if(M.damtype == BRUTE) - step_away(src,M,15) - var/obj/item/bodypart/temp = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD)) - if(temp) - var/update = 0 - var/dmg = rand(M.force/2, M.force) - switch(M.damtype) - if(BRUTE) - if(M.force > 35) // durand and other heavy mechas - Unconscious(20) - else if(M.force > 20 && !IsKnockdown()) // lightweight mechas like gygax - Knockdown(40) - update |= temp.receive_damage(dmg, 0) - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - if(FIRE) - update |= temp.receive_damage(0, dmg) - playsound(src, 'sound/items/welder.ogg', 50, 1) - if(TOX) - M.mech_toxin_damage(src) - else - return - if(update) - update_damage_overlays() - updatehealth() - - visible_message("[M.name] hits [src]!", \ - "[M.name] hits you!", null, COMBAT_MESSAGE_RANGE) - log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") - - else - ..() - - /mob/living/carbon/human/ex_act(severity, target, origin) if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) return diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index bfc9b490d2a8e..4a34320d2c1ec 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -128,34 +128,6 @@ playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) ..(AM, skipcatch, hitpush, blocked, throwingdatum) - -/mob/living/mech_melee_attack(obj/mecha/M) - if(M.occupant.a_intent == INTENT_HARM) - M.do_attack_animation(src) - if(M.damtype == BRUTE) - step_away(src,M,15) - switch(M.damtype) - if(BRUTE) - Knockdown(20) - take_overall_damage(rand(M.force/2, M.force)) - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - if(BURN) - take_overall_damage(0, rand(M.force/2, M.force)) - playsound(src, 'sound/items/welder.ogg', 50, 1) - if(TOX) - M.mech_toxin_damage(src) - else - return - updatehealth() - visible_message("[M.name] hits [src]!", \ - "[M.name] hits you!", null, COMBAT_MESSAGE_RANGE) - log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") - else - step_away(src,M) - log_combat(M.occupant, src, "pushed", M) - visible_message("[M] pushes [src] out of the way.", \ - "[M] pushes you out of the way.", null, 5) - /mob/living/fire_act() adjust_fire_stacks(3) IgniteMob() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 9c1feb3d3e157..e51eb713c1413 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -41,7 +41,7 @@ var/requires_power = POWER_REQ_ALL var/can_be_carded = TRUE var/icon/holo_icon //Default is assigned when AI is created. - var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye. + var/obj/vehicle/sealed/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye. var/radio_enabled = TRUE //Determins if a carded AI can speak with its built in radio or not. radiomod = ";" //AIs will, by default, state their laws on the internal radio. var/obj/item/multitool/aiMulti @@ -478,7 +478,7 @@ return if (href_list["ai_take_control"]) //Mech domination - var/obj/mecha/M = locate(href_list["ai_take_control"]) in GLOB.mechas_list + var/obj/vehicle/sealed/mecha/M = locate(href_list["ai_take_control"]) in GLOB.mechas_list if (!M) return diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 21fbb6684b727..711069b48d5f1 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -58,7 +58,7 @@ if(NONE) return FALSE if(POWER_REQ_ALL) - return !T || !A || ((!A.power_equip || isspaceturf(T)) && !is_type_in_list(loc, list(/obj/item, /obj/mecha))) + return !T || !A || ((!A.power_equip || isspaceturf(T)) && !is_type_in_list(loc, list(/obj/item, /obj/vehicle/sealed/mecha))) /mob/living/silicon/ai/updatehealth() if(status_flags & GODMODE) diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 3273d02408ac6..377b58e4e0aa8 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -218,9 +218,9 @@ return TRUE if(ismecha(the_target)) - var/obj/mecha/M = the_target - if(M.occupant)//Just so we don't attack empty mechs - if(CanAttack(M.occupant)) + var/obj/vehicle/sealed/mecha/M = the_target + for(var/occupant in M.occupants) + if(CanAttack(occupant)) return TRUE if(istype(the_target, /obj/machinery/porta_turret)) @@ -574,7 +574,7 @@ toggle_ai(AI_ON) /mob/living/simple_animal/hostile/proc/ListTargetsLazy(var/_Z)//Step 1, find out what we can see - var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha)) + var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) . = list() for (var/I in SSmobs.clients_by_zlevel[_Z]) var/mob/M = I diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm index 7b4369fe9640e..a7afb760b183f 100644 --- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm +++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm @@ -25,8 +25,8 @@ search_objects = 0 mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) - var/spawn_mecha_type = /obj/mecha/combat/marauder/mauler/loaded - var/obj/mecha/mecha //Ref to pilot's mecha instance + var/spawn_mecha_type = /obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded + var/obj/vehicle/sealed/mecha/mecha //Ref to pilot's mecha instance var/required_mecha_charge = 7500 //If the pilot doesn't have a mecha, what charge does a potential Grand Theft Mecha need? (Defaults to half a battery) var/mecha_charge_evacuate = 50 //Amount of charge at which the pilot tries to abandon the mecha @@ -42,7 +42,7 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/no_mech/Initialize(mapload) . = ..() - wanted_objects = typecacheof(/obj/mecha/combat, TRUE) + wanted_objects = typecacheof(/obj/vehicle/sealed/mecha/combat, TRUE) /mob/living/simple_animal/hostile/syndicate/mecha_pilot/nanotrasen //nanotrasen are syndies! no it's just a weird path. name = "\improper Nanotrasen Mecha Pilot" @@ -50,7 +50,7 @@ icon_living = "nanotrasen" icon_state = "nanotrasen" faction = list("nanotrasen") - spawn_mecha_type = /obj/mecha/combat/marauder/loaded + spawn_mecha_type = /obj/vehicle/sealed/mecha/combat/marauder/loaded /mob/living/simple_animal/hostile/syndicate/mecha_pilot/no_mech/nanotrasen name = "\improper Nanotrasen Mecha Pilot" @@ -63,12 +63,12 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/Initialize(mapload) . = ..() if(spawn_mecha_type) - var/obj/mecha/M = new spawn_mecha_type (get_turf(src)) + var/obj/vehicle/sealed/mecha/M = new spawn_mecha_type (get_turf(src)) if(istype(M)) enter_mecha(M) -/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/enter_mecha(obj/mecha/M) +/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/enter_mecha(obj/vehicle/sealed/mecha/M) if(!M) return 0 LoseTarget() //Target was our mecha, so null it out @@ -89,11 +89,11 @@ ranged = 0 wanted_objects = list() search_objects = 0 - if(mecha?.lights_action) //an AI mecha is an EVIL EVIL thing, so let's not hide them in the dark - mecha.lights_action.Activate() + if(LAZYACCESSASSOC(mecha.occupant_actions, src, /datum/action/vehicle/sealed/mecha/mech_defense_mode) && !mecha.defense_mode) + var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_defense_mode] + action.Trigger(TRUE) - -/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/exit_mecha(obj/mecha/M) +/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/exit_mecha(obj/vehicle/sealed/mecha/M) if(!M) return 0 @@ -102,9 +102,9 @@ targets_from = null //Find a new mecha - wanted_objects = typecacheof(/obj/mecha/combat, TRUE) + wanted_objects = typecacheof(/obj/vehicle/sealed/mecha/combat, TRUE) var/search_aggressiveness = 2 - for(var/obj/mecha/combat/C in view(vision_range,src)) + for(var/obj/vehicle/sealed/mecha/combat/C in view(vision_range,src)) if(is_valid_mecha(C)) GiveTarget(C) search_aggressiveness = 3 //We can see a mech? RUN FOR IT, IGNORE MOBS! @@ -116,23 +116,23 @@ SSmove_manager.stop_looping(src)//end any lingering movement loops, to prevent the haunted mecha bug //Checks if a mecha is valid for theft -/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/is_valid_mecha(obj/mecha/M) +/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/is_valid_mecha(obj/vehicle/sealed/mecha/M) if(!M) - return 0 - if(M.occupant) - return 0 + return FALSE + if(LAZYLEN(M.occupants)) + return FALSE if(!M.has_charge(required_mecha_charge)) - return 0 + return FALSE if(M.obj_integrity < M.max_integrity*0.5) - return 0 - return 1 + return FALSE + return TRUE /mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/mecha_face_target(atom/A) if(mecha) var/dirto = get_dir(mecha,A) if(mecha.dir != dirto) //checking, because otherwise the mecha makes too many turn noises - mecha.mechturn(dirto) + mecha.vehicle_move(dirto, TRUE) @@ -163,8 +163,7 @@ var/list/possible_weapons = get_mecha_equip_by_flag(MECHA_RANGED) if(possible_weapons.len) var/obj/item/mecha_parts/mecha_equipment/ME = pick(possible_weapons) //so we don't favor mecha.equipment[1] forever - if(ME.action(A)) - ME.start_cooldown() + if(ME.action(src,A)) return else @@ -177,16 +176,15 @@ if(possible_weapons.len) var/obj/item/mecha_parts/mecha_equipment/ME = pick(possible_weapons) mecha_face_target(target) - if(ME.action(target)) - ME.start_cooldown() + if(ME.action(src,target)) return - if(mecha.melee_can_hit) + if(!TIMER_COOLDOWN_CHECK(mecha, COOLDOWN_MECHA_MELEE_ATTACK)) mecha_face_target(target) - target.mech_melee_attack(mecha) + target.mech_melee_attack(mecha, src) else if(ismecha(target)) - var/obj/mecha/M = target + var/obj/vehicle/sealed/mecha/M = target if(is_valid_mecha(M)) enter_mecha(M) return @@ -199,49 +197,52 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/handle_automated_action() - if(..()) - if(!mecha) - for(var/obj/mecha/combat/C in view(vision_range, src)) - if(is_valid_mecha(C)) - GiveTarget(C) //Let's nab it! - minimum_distance = 1 - ranged = 0 - break - if(mecha) - var/list/L = PossibleThreats() - var/threat_count = L.len + . = ..() + if(!.) + return + if(!mecha) + for(var/obj/vehicle/sealed/mecha/combat/mecha_in_range in view(vision_range, src)) + if(is_valid_mecha(mecha_in_range)) + target = mecha_in_range //Let's nab it! + minimum_distance = 1 + ranged = 0 + break + if(mecha) + var/list/L = PossibleThreats() + var/threat_count = L.len - //Low Charge - Eject - if(!mecha.has_charge(mecha_charge_evacuate)) - exit_mecha(mecha) - return + //Low Charge - Eject + if(!mecha.has_charge(mecha_charge_evacuate)) + exit_mecha(mecha) + return - //Too Much Damage - Eject - if(mecha.obj_integrity < mecha.max_integrity*0.1) - exit_mecha(mecha) - return + //Too Much Damage - Eject + if(mecha.obj_integrity < mecha.max_integrity*0.1) + exit_mecha(mecha) + return - //Smoke if there's too many targets - Smoke Power - if(threat_count >= threat_use_mecha_smoke && prob(smoke_chance)) - if(mecha.smoke_action && mecha.smoke_action.owner && mecha.smoke) - mecha.smoke_action.Activate() + //Smoke if there's too many targets - Smoke Power + if(threat_count >= threat_use_mecha_smoke && prob(smoke_chance)) + if(LAZYACCESSASSOC(mecha.occupant_actions, src, /datum/action/vehicle/sealed/mecha/mech_smoke) && !mecha.smoke_charges) + var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_smoke] + action.Trigger() - //Heavy damage - Defense Power or Retreat - if(mecha.obj_integrity < mecha.max_integrity*0.25) - if(prob(defense_mode_chance)) - if(mecha.defense_action && mecha.defense_action.owner && !mecha.defense_mode) - mecha.leg_overload_mode = 0 - mecha.defense_action.Activate(TRUE) - addtimer(CALLBACK(mecha.defense_action, TYPE_PROC_REF(/datum/action/innate/mecha/mech_defense_mode, Activate), FALSE), 100) //10 seconds of defense, then toggle off + //Heavy damage - Defense Power or Retreat + if(mecha.obj_integrity < mecha.max_integrity*0.25) + if(prob(defense_mode_chance)) + if(LAZYACCESSASSOC(mecha.occupant_actions, src, /datum/action/vehicle/sealed/mecha/mech_defense_mode) && !mecha.defense_mode) + var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_defense_mode] + action.Trigger(TRUE) + addtimer(CALLBACK(action, /datum/action/vehicle/sealed/mecha/mech_defense_mode.proc/Trigger, FALSE), 100) //10 seconds of defense, then toggle off - else if(prob(retreat_chance)) - //Speed boost if possible - if(mecha.overload_action && mecha.overload_action.owner && !mecha.leg_overload_mode) - mecha.overload_action.Activate(TRUE) - addtimer(CALLBACK(mecha.overload_action, TYPE_PROC_REF(/datum/action/innate/mecha/mech_defense_mode, Activate), FALSE), 100) //10 seconds of speeeeed, then toggle off + else if(prob(retreat_chance)) + //Speed boost if possible + if(mecha.overload_action && mecha.overload_action.owner && !mecha.leg_overload_mode) + mecha.overload_action.Activate(TRUE) + addtimer(CALLBACK(mecha.overload_action, TYPE_PROC_REF(/datum/action/vehicle/sealed/mecha/mech_defense_mode, Activate), FALSE), 100) //10 seconds of speeeeed, then toggle off - retreat_distance = 50 - addtimer(VARSET_CALLBACK(src, retreat_distance, 0), 100) + retreat_distance = 50 + addtimer(VARSET_CALLBACK(src, retreat_distance, 0), 100) @@ -260,17 +261,17 @@ //~simple animals~ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/CanAttack(atom/the_target) if(ismecha(the_target)) - var/obj/mecha/M = the_target + var/obj/vehicle/sealed/mecha/M = the_target if(mecha) - if(M == mecha || !CanAttack(M.occupant)) - return 0 + if(M == mecha) //Dont kill yourself + return FALSE else //we're not in a mecha, so we check if we can steal it instead. if(is_valid_mecha(M)) - return 1 - else if (M.occupant && CanAttack(M.occupant)) - return 1 - else - return 0 + return TRUE + for(var/occupant in M.occupants) + if(CanAttack(occupant)) + return TRUE + return FALSE . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 06263dcb17e68..2283df70f0a52 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -200,7 +200,7 @@ Difficulty: Medium if(L.client) empty += pick(((RANGE_TURFS(2, L) - RANGE_TURFS(1, L)) & turfs) - empty) // picks a turf within 2 of the creature not outside or in the shield any_attack = 1 - for(var/obj/mecha/M in T.contents) + for(var/obj/vehicle/sealed/mecha/M in T.contents) empty += pick(((RANGE_TURFS(2, M) - RANGE_TURFS(1, M)) & turfs) - empty) any_attack = 1 if(!any_attack) @@ -276,7 +276,7 @@ Difficulty: Medium to_chat(L, "You're hit by [source]'s fire breath!") // deals damage to mechs - for(var/obj/mecha/M in T.contents) + for(var/obj/vehicle/sealed/mecha/M in T.contents) if(M in hit_list) continue hit_list += M @@ -363,7 +363,7 @@ Difficulty: Medium var/throwtarget = get_edge_target_turf(src, throw_dir) L.throw_at(throwtarget, 3) visible_message("[L] is thrown clear of [src]!") - for(var/obj/mecha/M in orange(1, src)) + for(var/obj/vehicle/sealed/mecha/M in orange(1, src)) M.take_damage(75, BRUTE, MELEE, 1) for(var/mob/M in range(7, src)) @@ -435,7 +435,7 @@ Difficulty: Medium to_chat(L, "You fall directly into the pool of lava!") // deals damage to mechs - for(var/obj/mecha/M in T.contents) + for(var/obj/vehicle/sealed/mecha/M in T.contents) M.take_damage(45, BRUTE, MELEE, 1) // changes turf to lava temporarily diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 435716e38ab0e..df9f62a12fe8f 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -677,14 +677,15 @@ Difficulty: Hard L.adjustBruteLoss(damage) if(caster) log_combat(caster, L, "struck with a [name]") - for(var/obj/mecha/M in T.contents - hit_things) //also damage mechs. + for(var/obj/vehicle/sealed/mecha/M in T.contents - hit_things) //also damage mechs. hit_things += M - if(M.occupant) - if(friendly_fire_check && caster && caster.faction_check_mob(M.occupant)) + for(var/O in M.occupants) + var/mob/living/occupant = O + if(friendly_fire_check && caster && caster.faction_check_mob(occupant)) continue - to_chat(M.occupant, "Your [M.name] is struck by a [name]!") - playsound(M,'sound/weapons/sear.ogg', 50, 1, -4) - M.take_damage(damage, BURN, 0, 0) + to_chat(occupant, "Your [M.name] is struck by a [name]!") + playsound(M,'sound/weapons/sear.ogg', 50, TRUE, -4) + M.take_damage(damage, BURN, 0, 0) /obj/effect/temp_visual/hierophant/blast/vortex damage = 25 diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm index dd58dd1f90cb5..d272657c8dfac 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm @@ -9,8 +9,8 @@ else remove_enemy(L) else if(ismecha(A)) - var/obj/mecha/M = A - if(M.occupant) + var/obj/vehicle/sealed/mecha/M = A + if(LAZYLEN(M.occupants)) return A /mob/living/simple_animal/hostile/retaliate/ListTargets() @@ -31,10 +31,10 @@ if(attack_same && H.attack_same) H.add_enemies(enemies) else if(ismecha(A)) - var/obj/mecha/M = A - if(M.occupant) + var/obj/vehicle/sealed/mecha/M = A + if(LAZYLEN(M.occupants)) add_enemy(M) - add_enemy(M.occupant) + add_enemy(M.occupants) return FALSE /mob/living/simple_animal/hostile/retaliate/adjustHealth(amount, updating_health = TRUE, forced = FALSE) diff --git a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm index 46463b6a1677c..f41c67c07a40a 100644 --- a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm +++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm @@ -147,8 +147,8 @@ is_swallowing = FALSE return . = ..() - if(istype(target, /obj/mecha)) - var/obj/mecha/M = target + if(istype(target, /obj/vehicle/sealed/mecha)) + var/obj/vehicle/sealed/mecha/M = target M.take_damage(50, BRUTE, MELEE, 1) /mob/living/simple_animal/hostile/space_dragon/Move() @@ -304,7 +304,7 @@ L.adjustFireLoss(30) to_chat(L, "You're hit by [src]'s fire breath!") // deals damage to mechs - for(var/obj/mecha/M in T.contents) + for(var/obj/vehicle/sealed/mecha/M in T.contents) if(M in hit_list) continue hit_list += M diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index 7cdf51b8f5425..0062fa8bd96a9 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -126,9 +126,11 @@ for(var/mob/living/M in viewers(getexpandedview(world.view, 1, 1), check)) if(M != src && M.client && CanAttack(M) && !M.has_unlimited_silicon_privilege && !M.is_blind()) return M - for(var/obj/mecha/M in view(getexpandedview(world.view, 1, 1), check)) //assuming if you can see them they can see you - if(M.occupant?.client && !M.occupant.is_blind()) - return M.occupant + for(var/obj/vehicle/sealed/mecha/M in view(getexpandedview(world.view, 1, 1), check)) //assuming if you can see them they can see you + for(var/O in M.occupants) + var/mob/mechamob = O + if(mechamob?.client && !mechamob.is_blind()) + return mechamob return null // Cannot talk diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 2d8af223958c7..798eee835397a 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -388,8 +388,8 @@ if(L.stat != CONSCIOUS) return FALSE if (ismecha(the_target)) - var/obj/mecha/M = the_target - if (M.occupant) + var/obj/vehicle/sealed/mecha/M = the_target + if(LAZYLEN(M.occupants)) return FALSE return TRUE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 93c52ca742422..ea6a674f06cf9 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1090,7 +1090,7 @@ return client.mouse_pointer_icon = initial(client.mouse_pointer_icon) if (ismecha(loc)) - var/obj/mecha/M = loc + var/obj/vehicle/sealed/mecha/M = loc if(M.mouse_pointer) client.mouse_pointer_icon = M.mouse_pointer else if (istype(loc, /obj/vehicle/sealed)) diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm index 9ee61a741305c..bec385c68cc8a 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -191,7 +191,7 @@ They *could* go in their appropriate files, but this is supposed to be modular S.spark_system.start() //MECH// -/obj/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) +/obj/vehicle/sealed/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) if(!S || !H || !G) return INVALID_DRAIN @@ -199,7 +199,7 @@ They *could* go in their appropriate files, but this is supposed to be modular var/drain = 0 //Drain amount . = 0 - occupant_message("Warning: Unauthorized access through sub-route 4, block H, detected.") + to_chat(occupants, "[icon2html(src, occupants)]Warning: Unauthorized access through sub-route 4, block H, detected.") if(get_charge()) while(G.candrain && cell.charge > 0 && !maxcapacity) drain = rand(G.mindrain,G.maxdrain) diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm index dab7113e5ac06..b90ce9b380b20 100644 --- a/code/modules/projectiles/projectile/special/rocket.dm +++ b/code/modules/projectiles/projectile/special/rocket.dm @@ -22,7 +22,7 @@ explosion(target, -1, 1, 3, 1, 0, flame_range = 4) if(ismecha(target)) - var/obj/mecha/M = target + var/obj/vehicle/sealed/mecha/M = target M.take_damage(anti_armour_damage) if(issilicon(target)) var/mob/living/silicon/S = target diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 620ef6993d01d..1fa203d0e2cc7 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -478,7 +478,7 @@ /obj/effect/CanEnterDisposals() return -/obj/mecha/CanEnterDisposals() +/obj/vehicle/sealed/mecha/CanEnterDisposals() return /obj/structure/spacevine/CanEnterDisposals() diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index dfbf1c1db9d44..b71fe9a568471 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -189,7 +189,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( continue if(bounty_ship_item_and_contents(AM, dry_run = FALSE)) matched_bounty = TRUE - if(!AM.anchored || istype(AM, /obj/mecha)) + if(!AM.anchored || istype(AM, /obj/vehicle/sealed/mecha)) export_item_and_contents(AM, export_categories , dry_run = FALSE, external_report = ex) else if(!ismachinery(AM)) //Exports the contents of things but not the item itself, so you can have conveyor belt that won't get sold diff --git a/code/modules/shuttle/white_ship.dm b/code/modules/shuttle/white_ship.dm index bf404463d9de8..4e235731e2f19 100644 --- a/code/modules/shuttle/white_ship.dm +++ b/code/modules/shuttle/white_ship.dm @@ -20,6 +20,6 @@ /obj/effect/spawner/lootdrop/whiteship_cere_ripley name = "25% mech 75% wreckage ripley spawner" - loot = list(/obj/mecha/working/ripley/mining = 1, + loot = list(/obj/vehicle/sealed/mecha/working/ripley/mining = 1, /obj/structure/mecha_wreckage/ripley = 5) lootdoubles = FALSE diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index e9c6d1c287be9..601624afaad4e 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1411,13 +1411,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) name = "Dark Gygax Exosuit" desc = "A lightweight exosuit, painted in a dark scheme. Its speed and equipment selection make it excellent \ for hit-and-run style attacks. Features an incendiary carbine, flash bang launcher, teleporter, ion thrusters and a Tesla energy array." - item = /obj/mecha/combat/gygax/dark/loaded + item = /obj/vehicle/sealed/mecha/combat/gygax/dark/loaded cost = 80 /datum/uplink_item/support/honker name = "Dark H.O.N.K." desc = "A clown combat mech equipped with bombanana peel and tearstache grenade launchers, as well as the ubiquitous HoNkER BlAsT 5000." - item = /obj/mecha/combat/honker/dark/loaded + item = /obj/vehicle/sealed/mecha/combat/honker/dark/loaded cost = 80 purchasable_from = UPLINK_CLOWN_OPS @@ -1425,7 +1425,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) name = "Mauler Exosuit" desc = "A massive and incredibly deadly military-grade exosuit. Features long-range targeting, thrust vectoring \ and deployable smoke. Comes equipped with an LMG, scattershot carbine, missile rack, an antiprojectile armor booster and a Tesla energy array." - item = /obj/mecha/combat/marauder/mauler/loaded + item = /obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded cost = 140 // Stealth Items diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm index c12be8b778ab9..593c84a1f2d83 100644 --- a/code/modules/vehicles/_vehicle.dm +++ b/code/modules/vehicles/_vehicle.dm @@ -7,7 +7,8 @@ armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0) density = TRUE anchored = FALSE - var/list/mob/occupants //mob = bitflags of their control level. + COOLDOWN_DECLARE(cooldown_vehicle_move) + var/list/mob/occupants //mob = bitflags of their control level. var/max_occupants = 1 var/max_drivers = 1 var/movedelay = 2 @@ -131,9 +132,9 @@ return TRUE /obj/vehicle/proc/vehicle_move(direction) - if(lastmove + movedelay > world.time) + if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move)) return FALSE - lastmove = world.time + COOLDOWN_START(src, cooldown_vehicle_move, movedelay) if(trailer) var/dir_to_move = get_dir(trailer.loc, loc) var/did_move = step(src, direction) diff --git a/code/game/mecha/combat/combat.dm b/code/modules/vehicles/mecha/combat/combat.dm similarity index 100% rename from code/game/mecha/combat/combat.dm rename to code/modules/vehicles/mecha/combat/combat.dm diff --git a/code/game/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm similarity index 100% rename from code/game/mecha/combat/durand.dm rename to code/modules/vehicles/mecha/combat/durand.dm diff --git a/code/game/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm similarity index 100% rename from code/game/mecha/combat/gygax.dm rename to code/modules/vehicles/mecha/combat/gygax.dm diff --git a/code/game/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm similarity index 100% rename from code/game/mecha/combat/honker.dm rename to code/modules/vehicles/mecha/combat/honker.dm diff --git a/code/game/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm similarity index 100% rename from code/game/mecha/combat/marauder.dm rename to code/modules/vehicles/mecha/combat/marauder.dm diff --git a/code/game/mecha/combat/phazon.dm b/code/modules/vehicles/mecha/combat/phazon.dm similarity index 100% rename from code/game/mecha/combat/phazon.dm rename to code/modules/vehicles/mecha/combat/phazon.dm diff --git a/code/game/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm similarity index 100% rename from code/game/mecha/combat/reticence.dm rename to code/modules/vehicles/mecha/combat/reticence.dm diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm similarity index 100% rename from code/game/mecha/equipment/mecha_equipment.dm rename to code/modules/vehicles/mecha/equipment/mecha_equipment.dm diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm similarity index 100% rename from code/game/mecha/equipment/tools/medical_tools.dm rename to code/modules/vehicles/mecha/equipment/tools/medical_tools.dm diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm similarity index 100% rename from code/game/mecha/equipment/tools/mining_tools.dm rename to code/modules/vehicles/mecha/equipment/tools/mining_tools.dm diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm similarity index 100% rename from code/game/mecha/equipment/tools/other_tools.dm rename to code/modules/vehicles/mecha/equipment/tools/other_tools.dm diff --git a/code/game/mecha/equipment/tools/weapon_bay.dm b/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm similarity index 100% rename from code/game/mecha/equipment/tools/weapon_bay.dm rename to code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm similarity index 100% rename from code/game/mecha/equipment/tools/work_tools.dm rename to code/modules/vehicles/mecha/equipment/tools/work_tools.dm diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm similarity index 100% rename from code/game/mecha/equipment/weapons/weapons.dm rename to code/modules/vehicles/mecha/equipment/weapons/weapons.dm diff --git a/code/game/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm similarity index 100% rename from code/game/mecha/mech_bay.dm rename to code/modules/vehicles/mecha/mech_bay.dm diff --git a/code/modules/vehicles/mecha/mech_melee_attack.dm b/code/modules/vehicles/mecha/mech_melee_attack.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/game/mecha/mecha.dm b/code/modules/vehicles/mecha/mecha.dm similarity index 100% rename from code/game/mecha/mecha.dm rename to code/modules/vehicles/mecha/mecha.dm diff --git a/code/game/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm similarity index 100% rename from code/game/mecha/mecha_actions.dm rename to code/modules/vehicles/mecha/mecha_actions.dm diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm similarity index 100% rename from code/game/mecha/mecha_construction_paths.dm rename to code/modules/vehicles/mecha/mecha_construction_paths.dm diff --git a/code/game/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm similarity index 100% rename from code/game/mecha/mecha_control_console.dm rename to code/modules/vehicles/mecha/mecha_control_console.dm diff --git a/code/game/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm similarity index 100% rename from code/game/mecha/mecha_defense.dm rename to code/modules/vehicles/mecha/mecha_defense.dm diff --git a/code/game/mecha/mecha_parts.dm b/code/modules/vehicles/mecha/mecha_parts.dm similarity index 100% rename from code/game/mecha/mecha_parts.dm rename to code/modules/vehicles/mecha/mecha_parts.dm diff --git a/code/game/mecha/mecha_topic.dm b/code/modules/vehicles/mecha/mecha_topic.dm similarity index 100% rename from code/game/mecha/mecha_topic.dm rename to code/modules/vehicles/mecha/mecha_topic.dm diff --git a/code/game/mecha/mecha_wreckage.dm b/code/modules/vehicles/mecha/mecha_wreckage.dm similarity index 100% rename from code/game/mecha/mecha_wreckage.dm rename to code/modules/vehicles/mecha/mecha_wreckage.dm diff --git a/code/game/mecha/medical/medical.dm b/code/modules/vehicles/mecha/medical/medical.dm similarity index 100% rename from code/game/mecha/medical/medical.dm rename to code/modules/vehicles/mecha/medical/medical.dm diff --git a/code/game/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm similarity index 100% rename from code/game/mecha/medical/odysseus.dm rename to code/modules/vehicles/mecha/medical/odysseus.dm diff --git a/code/game/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm similarity index 100% rename from code/game/mecha/working/ripley.dm rename to code/modules/vehicles/mecha/working/ripley.dm diff --git a/code/game/mecha/working/working.dm b/code/modules/vehicles/mecha/working/working.dm similarity index 100% rename from code/game/mecha/working/working.dm rename to code/modules/vehicles/mecha/working/working.dm diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index d3af2d414cd20..052a32cdec398 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -56,10 +56,12 @@ mob_exit(M, silent, randomstep) /obj/vehicle/sealed/proc/mob_exit(mob/M, silent = FALSE, randomstep = FALSE) + SIGNAL_HANDLER if(!istype(M)) return FALSE remove_occupant(M) - M.forceMove(exit_location(M)) + if(!isAI(M))//This is the ONE mob we dont want to be moved to the vehicle that should be handeled when used + M.forceMove(exit_location(M)) if(randomstep) var/turf/target_turf = get_step(exit_location(M), pick(GLOB.cardinals)) M.throw_at(target_turf, 5, 10) From 4776b7b48197f04b81f45170acf4d45c7667cb6a Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 21:05:12 -0400 Subject: [PATCH 02/41] oops, rename --- code/modules/vehicles/mecha/{mecha.dm => _mecha.dm} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename code/modules/vehicles/mecha/{mecha.dm => _mecha.dm} (100%) diff --git a/code/modules/vehicles/mecha/mecha.dm b/code/modules/vehicles/mecha/_mecha.dm similarity index 100% rename from code/modules/vehicles/mecha/mecha.dm rename to code/modules/vehicles/mecha/_mecha.dm From 269f6f4a0791f8f4d37d7e7aa467b2392620a277 Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 22:41:11 -0400 Subject: [PATCH 03/41] _mecha 1st pass --- code/modules/vehicles/mecha/_mecha.dm | 1074 ++++++++++++------------- 1 file changed, 536 insertions(+), 538 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index a5bedff3ee04c..74c80f26f4ac4 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -1,136 +1,187 @@ -/obj/mecha +//////////////////WELCOME TO MECHA.DM, ENJOY YOUR STAY\\\\\\\\\\\\\\\\\ + +/** + * Mechs are now (finally) vehicles, this means you can make them multicrew + * They can also grant select ability buttons based on occupant bitflags + * + * Movement is handled through vehicle_move() which is called by relaymove + * Clicking is done by way of signals registering to the entering mob + * NOTE: MMIS are NOT mobs but instead contain a brain that is, so you need special checks + * AI also has special checks becaus it gets in and out of the mech differently + * Always call remove_occupant(mob) when leaving the mech so the mob is removed properly + * + * For multi-crew, you need to set how the occupants recieve ability bitflags corresponding to their status on the vehicle(i.e: driver, gunner etc) + * Abilities can then be set to only apply for certain bitflags and are assigned as such automatically + * + * Clicks are wither translated into mech_melee_attack (see mech_melee_attack.dm) + * Or are used to call action() on equipped gear + * Cooldown for gear is on the mech because exploits + */ +/obj/vehicle/sealed/mecha name = "mecha" desc = "Exosuit" icon = 'icons/mecha/mecha.dmi' - density = TRUE //Dense. To raise the heat. - move_force = MOVE_FORCE_VERY_STRONG - move_resist = MOVE_FORCE_EXTREMELY_STRONG resistance_flags = FIRE_PROOF | ACID_PROOF - layer = BELOW_MOB_LAYER//icon draw layer - infra_luminosity = 15 //byond implementation is bugged. - force = 5 + max_integrity = 300 + armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) + movedelay = 1 SECONDS + anchored = TRUE + emulate_door_bumps = TRUE + COOLDOWN_DECLARE(mecha_bump_smash) light_system = MOVABLE_LIGHT light_on = FALSE light_power = 1 light_range = 5 - var/ruin_mecha = FALSE //if the mecha starts on a ruin, don't automatically give it a tracking beacon to prevent metagaming. - var/can_move = 0 //time of next allowed movement - var/mob/living/carbon/occupant = null - var/step_in = 10 //make a step in step_in/10 sec. + ///What direction will the mech face when entered/powered on? Defaults to South. + var/dir_in = SOUTH + ///How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain. + var/normal_step_energy_drain = 10 + + /* + //Beestation stuff var/step_multiplier = 1 var/step_restricted = 0 //applied on_entered() by things which slow or restrict mech movement. Resets to zero at the end of every movement - var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South. - var/normal_step_energy_drain = 10 //How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain. + */ + + ///How much energy the mech will consume each time it moves. this is the current active energy consumed var/step_energy_drain = 10 + ///How much energy we drain each time we mechpunch someone var/melee_energy_drain = 15 + ///The minimum amount of energy charge consumed by leg overload var/overload_step_energy_drain_min = 100 - max_integrity = 300 //max_integrity is base health - var/deflect_chance = 10 //chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. - armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) + ///chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. + var/deflect_chance = 10 + ///Modifiers for directional armor var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 1.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 0.5) - var/equipment_disabled = 0 //disabled due to EMP + ///if we cant use our equipment(such as due to EMP) + var/equipment_disabled = FALSE var/obj/item/stock_parts/cell/cell ///Keeps track of the mech's cell var/obj/item/stock_parts/scanning_module/scanmod ///Keeps track of the mech's scanning module var/obj/item/stock_parts/capacitor/capacitor ///Keeps track of the mech's capacitor + ///Whether the mechs maintenance protocols are on or off var/construction_state = MECHA_LOCKED - var/last_message = 0 - var/add_req_access = 1 - var/maint_access = 0 - var/list/proc_res = list() //stores proc owners, like proc_res["functionname"] = owner reference + ///Contains flags for the mecha + var/mecha_flags = ADDING_ACCESS_POSSIBLE | CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS + ///Spark effects are handled by this datum var/datum/effect_system/spark_spread/spark_system = new - var/lights = FALSE + ///How powerful our lights are var/lights_power = 6 - var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference - var/completely_disabled = FALSE //stops the mech from doing anything - - var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it. - //inner atmos - var/use_internal_tank = 0 + ///Just stop the mech from doing anything + var/completely_disabled = FALSE + ///Whether this mech is allowed to move diagonally + var/allow_diagonal_movement = FALSE + ///Whether or not the mech destroys walls by running into it. + var/bumpsmash = FALSE + + ///////////ATMOS + ///Whether we are currrently drawing from the internal tank + var/use_internal_tank = FALSE + ///The setting of the valve on the internal tank var/internal_tank_valve = ONE_ATMOSPHERE + ///The internal air tank obj of the mech var/obj/machinery/portable_atmospherics/canister/internal_tank + ///Internal air mix datum var/datum/gas_mixture/cabin_air - var/obj/machinery/atmospherics/components/unary/portables_connector/connected_port = null + ///The connected air port, if we have one + var/obj/machinery/atmospherics/components/unary/portables_connector/connected_port + ///Special version of the radio, which is unsellable var/obj/item/radio/mech/radio var/list/trackers = list() var/max_temperature = 25000 - var/internal_damage_threshold = 50 //health percentage below which internal damage is possible - var/internal_damage = 0 //contains bitflags + ///health percentage below which internal damage is possible + var/internal_damage_threshold = 50 + ///Bitflags for internal damage + var/internal_damage = NONE - var/list/operation_req_access = list()//required access level for mecha operation - var/list/internals_req_access = list(ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE)//REQUIRED ACCESS LEVEL TO OPEN CELL COMPARTMENT + ///required access level for mecha operation + var/list/operation_req_access = list() + ///required access to change internal components + var/list/internals_req_access = list(ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE) + ///Typepath for the wreckage it spawns when destroyed var/wreckage var/list/equipment = new + ///Current active equipment var/obj/item/mecha_parts/mecha_equipment/selected + ///Current active equipment var/max_equip = 3 - var/datum/events/events - var/step_silent = FALSE //Used for disabling mech step sounds while using thrusters or pushing off lockers + ///Whether our steps are silent, for example in zero-G + var/step_silent = FALSE + ///Sound played when the mech moves var/stepsound = 'sound/mecha/mechstep.ogg' + ///Sound played when the mech walks var/turnsound = 'sound/mecha/mechturn.ogg' + ///Cooldown duration between melee punches var/melee_cooldown = 10 - var/melee_can_hit = 1 - - var/silicon_pilot = FALSE //set to true if an AI or MMI is piloting. - - var/enter_delay = 40 //Time taken to enter the mech - var/exit_delay = 20 //Time to exit mech - var/destruction_sleep_duration = 20 //Time that mech pilot is put to sleep for if mech is destroyed - var/enclosed = TRUE //Set to false for open-cockpit mechs - var/silicon_icon_state = null //if the mech has a different icon when piloted by an AI or MMI - var/is_currently_ejecting = FALSE //Mech cannot use equipment when true, set to true if pilot is trying to exit mech - - //Action datums - var/datum/action/innate/mecha/mech_eject/eject_action = new - var/datum/action/innate/mecha/mech_toggle_internals/internals_action = new - var/datum/action/innate/mecha/mech_cycle_equip/cycle_action = new - var/datum/action/innate/mecha/mech_toggle_lights/lights_action = new - var/datum/action/innate/mecha/mech_view_stats/stats_action = new - var/datum/action/innate/mecha/mech_defense_mode/defense_action = new - var/datum/action/innate/mecha/mech_overload_mode/overload_action = new - var/datum/effect_system/smoke_spread/smoke_system = new //not an action, but trigged by one - var/datum/action/innate/mecha/mech_smoke/smoke_action = new - var/datum/action/innate/mecha/mech_zoom/zoom_action = new - var/datum/action/innate/mecha/mech_switch_damtype/switch_damtype_action = new - var/datum/action/innate/mecha/mech_toggle_phasing/phasing_action = new - var/datum/action/innate/mecha/strafe/strafing_action = new - - //Action vars + + ///TIme taken to leave the mech + var/exit_delay = 2 SECONDS + ///Time you get slept for if you get forcible ejected by the mech exploding + var/destruction_sleep_duration = 2 SECONDS + ///Whether outside viewers can see the pilot inside + var/enclosed = TRUE + ///In case theres a different iconstate for AI/MMI pilot(currently only used for ripley) + var/silicon_icon_state = null + ///Currently ejecting, and unable to do things + var/is_currently_ejecting = FALSE + + var/datum/effect_system/smoke_spread/smoke_system = new + + ////Action vars + ///Ref to any active thrusters we might have + var/obj/item/mecha_parts/mecha_equipment/thrusters/active_thrusters + + ///Bool for energy shield on/off var/defense_mode = FALSE + + ///Bool for leg overload on/off var/leg_overload_mode = FALSE + ///Bool for leg overload on/off var/leg_overload_coeff = 100 + + //Bool for zoom on/off var/zoom_mode = FALSE - var/smoke = 5 - var/smoke_ready = 1 - var/smoke_cooldown = 100 + + ///Remaining smoke charges + var/smoke_charges = 5 + ///Cooldown between using smoke + var/smoke_cooldown = 10 SECONDS + + ///Bool for if the mech is currently phasing var/phasing = FALSE + ///Power we use every time we phaze through something var/phasing_energy_drain = 200 - var/phase_state = "" //icon_state when phasing - var/strafe = FALSE //If we are strafing + ///icon_state for flick() when phazing + var/phase_state = "" - var/nextsmash = 0 - var/smashcooldown = 3 //deciseconds + ///Whether we are strafing + var/strafe = FALSE - var/occupant_sight_flags = 0 //sight flags to give to the occupant (e.g. mech mining scanner gives meson-like vision) - var/mouse_pointer + ///Cooldown length between bumpsmashes + var/smashcooldown = 3 + + ///Bool for whether this mech can only be used on lavaland + var/lavaland_only = FALSE hud_possible = list (DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD) /obj/item/radio/mech //this has to go somewhere -/obj/mecha/Initialize(mapload) +/obj/vehicle/sealed/mecha/Initialize(mapload) . = ..() events = new - icon_state += "-open" add_radio() add_cabin() - if (enclosed) + if(enclosed) add_airtank() + RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE , .proc/disconnect_air) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, .proc/play_stepsound) spark_system.set_up(2, 0, src) spark_system.attach(src) smoke_system.set_up(3, src) @@ -150,74 +201,76 @@ diag_hud_set_mechstat() become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT) update_step_speed() + update_icon() -/obj/mecha/update_icon() - if (silicon_pilot && silicon_icon_state) - icon_state = silicon_icon_state - . = ..() - -/obj/mecha/get_cell() - return cell - -/obj/mecha/rust_heretic_act() - take_damage(500, BRUTE) - return TRUE - -/obj/mecha/Destroy() - if(occupant) - occupant.SetSleeping(destruction_sleep_duration) - go_out() - var/mob/living/silicon/ai/AI - for(var/mob/M in src) //Let's just be ultra sure - if(isAI(M)) - occupant = null - AI = M //AIs are loaded into the mech computer itself. When the mech dies, so does the AI. They can be recovered with an AI card from the wreck. +/obj/vehicle/sealed/mecha/Destroy() + for(var/M in occupants) + var/mob/living/occupant = M + if(isAI(occupant)) + occupant.gib() //No wreck, no AI to recover else - M.forceMove(loc) - for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) - E.detach(loc) - qdel(E) + occupant.forceMove(loc) + occupant.SetSleeping(destruction_sleep_duration) + if(LAZYLEN(equipment)) + for(var/E in equipment) + var/obj/item/mecha_parts/mecha_equipment/equip = E + equip.detach(loc) + qdel(equip) if(cell) - qdel(cell) + QDEL_NULL(cell) if(scanmod) - qdel(scanmod) + QDEL_NULL(scanmod) if(capacitor) - qdel(capacitor) + QDEL_NULL(capacitor) if(internal_tank) - qdel(internal_tank) - if(AI) - AI.gib() //No wreck, no AI to recover + QDEL_NULL(internal_tank) STOP_PROCESSING(SSobj, src) - equipment.Cut() - cell = null - scanmod = null - capacitor = null - internal_tank = null + LAZYCLEARLIST(equipment) assume_air(cabin_air) + if(loc) + loc.assume_air(cabin_air) + air_update_turf() + else + qdel(cabin_air) cabin_air = null - qdel(spark_system) - spark_system = null - qdel(smoke_system) - smoke_system = null + QDEL_NULL(spark_system) + QDEL_NULL(smoke_system) GLOB.mechas_list -= src //global mech list return ..() -/obj/mecha/proc/restore_equipment() - equipment_disabled = 0 - if(occupant) - SEND_SOUND(occupant, sound('sound/items/timer.ogg', volume=50)) - to_chat(occupant, "Equipment control unit has been rebooted successfuly.") - occupant.update_mouse_pointer() +/obj/vehicle/sealed/mecha/update_icon_state() + if((mecha_flags & SILICON_PILOT) && silicon_icon_state) + icon_state = silicon_icon_state + else if(LAZYLEN(occupants)) + icon_state = initial(icon_state) + else + icon_state = initial(icon_state)+ "-open" + + +/obj/vehicle/sealed/mecha/get_cell() + return cell + +/obj/vehicle/sealed/mecha/rust_heretic_act() + take_damage(500, BRUTE) + return TRUE + +/obj/vehicle/sealed/mecha/proc/restore_equipment() + equipment_disabled = FALSE + for(var/occupant in occupants) + var/mob/mob_occupant + SEND_SOUND(mob_occupant, sound('sound/items/timer.ogg', volume=50)) + to_chat(mob_occupant, "Equipment control unit has been rebooted successfully.") + mob_occupant.update_mouse_pointer() -/obj/mecha/CheckParts(list/parts_list) +/obj/vehicle/sealed/mecha/CheckParts(list/parts_list) ..() cell = locate(/obj/item/stock_parts/cell) in contents scanmod = locate(/obj/item/stock_parts/scanning_module) in contents capacitor = locate(/obj/item/stock_parts/capacitor) in contents update_part_values() -/obj/mecha/proc/update_part_values() ///Updates the values given by scanning module and capacitor tier, called when a part is removed or inserted. +/obj/vehicle/sealed/mecha/proc/update_part_values() ///Updates the values given by scanning module and capacitor tier, called when a part is removed or inserted. if(scanmod) normal_step_energy_drain = 20 - (5 * scanmod.rating) //10 is normal, so on lowest part its worse, on second its ok and on higher its real good up to 0 on best step_energy_drain = normal_step_energy_drain @@ -234,12 +287,12 @@ ////// Helpers ///////// //////////////////////// -/obj/mecha/proc/add_airtank() +/obj/vehicle/sealed/mecha/proc/add_airtank() internal_tank = new /obj/machinery/portable_atmospherics/canister/air(src) return internal_tank ///Adds a cell, for use in Map-spawned mechs, Nuke Ops mechs, and admin-spawned mechs. Mechs built by hand will replace this. -/obj/mecha/proc/add_cell(var/obj/item/stock_parts/cell/C=null) +/obj/vehicle/sealed/mecha/proc/add_cell(var/obj/item/stock_parts/cell/C=null) QDEL_NULL(cell) if(C) C.forceMove(src) @@ -248,7 +301,7 @@ cell = new /obj/item/stock_parts/cell/high/plus(src) ///Adds a scanning module, for use in Map-spawned mechs, Nuke Ops mechs, and admin-spawned mechs. Mechs built by hand will replace this. -/obj/mecha/proc/add_scanmod(var/obj/item/stock_parts/scanning_module/sm=null) +/obj/vehicle/sealed/mecha/proc/add_scanmod(var/obj/item/stock_parts/scanning_module/sm=null) QDEL_NULL(scanmod) if(sm) sm.forceMove(src) @@ -257,7 +310,7 @@ scanmod = new /obj/item/stock_parts/scanning_module(src) ///Adds a capacitor, for use in Map-spawned mechs, Nuke Ops mechs, and admin-spawned mechs. Mechs built by hand will replace this. -/obj/mecha/proc/add_capacitor(var/obj/item/stock_parts/capacitor/cap=null) +/obj/vehicle/sealed/mecha/proc/add_capacitor(var/obj/item/stock_parts/capacitor/cap=null) QDEL_NULL(capacitor) if(cap) cap.forceMove(src) @@ -265,7 +318,7 @@ return capacitor = new /obj/item/stock_parts/capacitor(src) -/obj/mecha/proc/add_cabin() +/obj/vehicle/sealed/mecha/proc/add_cabin() cabin_air = new cabin_air.set_temperature(T20C) cabin_air.set_volume(200) @@ -273,24 +326,22 @@ cabin_air.set_moles(GAS_N2, N2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature())) return cabin_air -/obj/mecha/proc/add_radio() +/obj/vehicle/sealed/mecha/proc/add_radio() radio = new(src) radio.name = "[src] radio" radio.icon = icon radio.icon_state = icon_state radio.subspace_transmission = TRUE -/obj/mecha/proc/can_use(mob/user) - if(user != occupant) - return 0 - if(user && ismob(user)) +/obj/vehicle/sealed/mecha/proc/can_use(mob/user) + if(istype(user) && is_occupant(user)) if(!user.incapacitated()) - return 1 - return 0 + return TRUE + return FALSE //////////////////////////////////////////////////////////////////////////////// -/obj/mecha/examine(mob/user) +/obj/vehicle/sealed/mecha/examine(mob/user) . = ..() var/integrity = obj_integrity*100/max_integrity switch(integrity) @@ -312,10 +363,11 @@ for(var/obj/item/mecha_parts/mecha_equipment/ME in visible_equipment) . += "[icon2html(ME, user)] \A [ME]." if(!enclosed) - if(silicon_pilot) + if(mecha_flags & SILICON_PILOT) . += "[src] appears to be piloting itself..." - else if(occupant && occupant != user) //!silicon_pilot implied - . += "You can see [occupant] inside." + else + for(var/occupante in occupants) + . += "You can see [occupante] inside." if(ishuman(user)) var/mob/living/carbon/human/H = user for(var/O in H.held_items) @@ -324,7 +376,7 @@ break //in case user is holding two guns //processing internal damage, temperature, air regulation, alert updates, lights power use. -/obj/mecha/process() +/obj/vehicle/sealed/mecha/process() var/internal_temp_regulation = 1 if(internal_damage) @@ -380,78 +432,81 @@ transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) cabin_air.transfer_to(t_air, transfer_moles) - if(occupant) - if(cell) - var/cellcharge = cell.maxcharge ? cell.charge / cell.maxcharge : 0 //Division by 0 protection - switch(cellcharge) - if(0.75 to INFINITY) - occupant.clear_alert("charge") - if(0.5 to 0.75) - occupant.throw_alert("charge", /atom/movable/screen/alert/lowcell, 1) - if(0.25 to 0.5) - occupant.throw_alert("charge", /atom/movable/screen/alert/lowcell, 2) - if(0.01 to 0.25) - occupant.throw_alert("charge", /atom/movable/screen/alert/lowcell, 3) + if(occupants) + for(var/i in occupants) + var/mob/living/occupant = i + if(cell) + var/cellcharge = cell.maxcharge ? cell.charge / cell.maxcharge : 0 //Division by 0 protection + switch(cellcharge) + if(0.75 to INFINITY) + occupant.clear_alert("charge") + if(0.5 to 0.75) + occupant.throw_alert("charge", /atom/movable/screen/alert/lowcell, 1) + if(0.25 to 0.5) + occupant.throw_alert("charge", /atom/movable/screen/alert/lowcell, 2) + if(0.01 to 0.25) + occupant.throw_alert("charge", /atom/movable/screen/alert/lowcell, 3) + else + occupant.throw_alert("charge", /atom/movable/screen/alert/emptycell) + + var/integrity = obj_integrity/max_integrity*100 + switch(integrity) + if(30 to 45) + occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 1) + if(15 to 35) + occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 2) + if(-INFINITY to 15) + occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 3) else - occupant.throw_alert("charge", /atom/movable/screen/alert/emptycell) - - var/integrity = obj_integrity/max_integrity*100 - switch(integrity) - if(30 to 45) - occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 1) - if(15 to 35) - occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 2) - if(-INFINITY to 15) - occupant.throw_alert("mech damage", /atom/movable/screen/alert/low_mech_integrity, 3) - else - occupant.clear_alert("mech damage") - var/atom/checking = occupant.loc - // recursive check to handle all cases regarding very nested occupants, - // such as brainmob inside brainitem inside MMI inside mecha - while (!isnull(checking)) - if (isturf(checking)) - // hit a turf before hitting the mecha, seems like they have - // been moved out - occupant.clear_alert("charge") - occupant.clear_alert("mech damage") - RemoveActions(occupant, human_occupant=1) - occupant = null - break - else if (checking == src) - break // all good - checking = checking.loc - - if(lights) + occupant.clear_alert("mech damage") + var/atom/checking = occupant.loc + // recursive check to handle all cases regarding very nested occupants, + // such as brainmob inside brainitem inside MMI inside mecha + while (!isnull(checking)) + if (isturf(checking)) + // hit a turf before hitting the mecha, seems like they have + // been moved out + occupant.clear_alert("charge") + occupant.clear_alert("mech damage") + occupant = null + break + else if (checking == src) + break // all good + checking = checking.loc + + if(mecha_flags & LIGHTS_ON) var/lights_energy_drain = 2 use_power(lights_energy_drain) - if(!enclosed && occupant?.incapacitated()) //no sides mean it's easy to just sorta fall out if you're incapacitated. - visible_message("[occupant] tumbles out of the cockpit!") - go_out() //Maybe we should install seat belts? + for(var/b in occupants) + var/mob/living/occupant = b + if(!enclosed && occupant?.incapacitated()) //no sides mean it's easy to just sorta fall out if you're incapacitated. + visible_message("[occupant] tumbles out of the cockpit!") + mob_exit(occupant) //bye bye //Diagnostic HUD updates diag_hud_set_mechhealth() diag_hud_set_mechcell() diag_hud_set_mechstat() -/obj/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech - . = ..() - if (occupant && !enclosed && !silicon_pilot) - if (occupant.fire_stacks < 5) - occupant.fire_stacks += 1 - occupant.IgniteMob() - -/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list()) +/obj/vehicle/sealed/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech . = ..() - if(speaker == occupant) - //flick speech bubble - var/list/speech_bubble_recipients = list() - for(var/mob/M as() in hearers(7,src)) - if(M.client) - speech_bubble_recipients.Add(M.client) - INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), image('icons/mob/talk.dmi', src, "machine[say_test(raw_message)]",MOB_LAYER+1), speech_bubble_recipients, 30) - -/obj/mecha/on_emag(mob/user) + if(LAZYLEN(occupants) && !enclosed && !(mecha_flags & SILICON_PILOT)) + for(var/M in occupants) + var/mob/living/cookedalive = M + if(cookedalive.fire_stacks < 5) + cookedalive.fire_stacks += 1 + cookedalive.IgniteMob() + +/obj/vehicle/sealed/mecha/proc/display_speech_bubble(datum/source, list/speech_args) + SIGNAL_HANDLER + var/list/speech_bubble_recipients = get_hearers_in_view(7,src) + for(var/mob/M as anything in speech_bubble_recipients) + if(M.client) + speech_bubble_recipients.Add(M.client) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), image('icons/mob/talk.dmi', src, "machine[say_test(raw_message)]",MOB_LAYER+1), speech_bubble_recipients, 30) + +/obj/vehicle/sealed/mecha/on_emag(mob/user) ..() playsound(src, "sparks", 100, 1) to_chat(user, "You short out the mech suit's internal controls.") @@ -463,23 +518,24 @@ ///// Action processing //// //////////////////////////// - -/obj/mecha/proc/click_action(atom/target,mob/user,params) - if(!occupant || occupant != user ) - return +/obj/vehicle/sealed/mecha/proc/on_mouseclick(mob/user, atom/target, params) + SIGNAL_HANDLER if(!locate(/turf) in list(target,target.loc)) // Prevents inventory from being drilled return if(completely_disabled) return if(is_currently_ejecting) return + var/list/mouse_control = params2list(params) + if(isAI(user) && !mouse_control["middle"])//AIs use MMB + return if(phasing) - occupant_message("Unable to interact with objects while phasing.") + to_chat(occupants, "[icon2html(src, occupants)]Unable to interact with objects while phasing.") return if(user.incapacitated()) return if(construction_state) - occupant_message("Maintenance protocols in effect.") + to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect.") return if(!get_charge()) return @@ -489,57 +545,57 @@ if(dir_to_target && !(dir_to_target & dir))//wrong direction return if(internal_damage & MECHA_INT_CONTROL_LOST) - target = safepick(view(3,target)) + target = pick(view(3,target)) if(!target) return var/mob/living/L = user - if(!Adjacent(target)) - if(selected && selected.is_ranged()) + if(selected) + if(!Adjacent(target) && (selected.range & MECHA_RANGED)) if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful) - to_chat(user, "You don't want to harm other living beings!") + to_chat(L, "You don't want to harm other living beings!") return - if(selected.action(target,params)) - selected.start_cooldown() - else if(selected && selected.is_melee()) - if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM)) - to_chat(user, "You don't want to harm other living beings!") + selected.action(user, target, params) return - if(selected.action(target,params)) - selected.start_cooldown() - else - if(internal_damage & MECHA_INT_CONTROL_LOST) - target = safepick(oview(1,src)) - if(!melee_can_hit || !istype(target, /atom)) + if((selected.range & MECHA_MELEE) && Adjacent(target)) + if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM)) + to_chat(L, "You don't want to harm other living beings!") + return + selected.action(user, target, params) return - target.mech_melee_attack(src) - melee_can_hit = FALSE - addtimer(VARSET_CALLBACK(src, melee_can_hit, TRUE), melee_cooldown) - - -/obj/mecha/proc/range_action(atom/target) - return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK) || !istype(target, /atom) || !Adjacent(target)) + return + if(internal_damage & MECHA_INT_CONTROL_LOST) + var/list/possible_targets = oview(1,src) + if(!length(possible_targets)) + return + target = pick(possible_targets) + target.mech_melee_attack(src, user) + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown) ////////////////////////////////// //////// Movement procs //////// ////////////////////////////////// -/obj/mecha/proc/update_step_speed() +/obj/vehicle/sealed/mecha/proc/update_step_speed() // Calculate the speed delta // Calculate the move multiplier speed, to be proportional to mob speed - // 1.5 was the previous value, so calculate hte multiplier in proportion to that + // 1.5 was the previous value, so calculate the multiplier in proportion to that step_multiplier = CONFIG_GET(number/movedelay/run_delay) / 1.5 -/obj/mecha/Move(atom/newloc, direct) - . = ..() - if(.) - events.fireEvent("onMove",get_turf(src)) - if (internal_tank?.disconnect()) // Something moved us and broke connection - occupant_message("Air port connection teared off!") +/obj/vehicle/sealed/mecha/proc/play_stepsound() + SIGNAL_HANDLER + if(stepsound) + playsound(src,stepsound,40,1) + +/obj/vehicle/sealed/mecha/proc/disconnect_air() + SIGNAL_HANDLER + if(internal_tank.disconnect()) // Something moved us and broke connection + to_chat(occupants, "[icon2html(src, occupants)]Air port connection has been severed!") log_message("Lost connection to gas port.", LOG_MECHA) -/obj/mecha/Process_Spacemove(var/movement_dir = 0) +/obj/vehicle/sealed/mecha/Process_Spacemove(movement_dir = 0) . = ..() if(.) return @@ -552,40 +608,35 @@ var/atom/movable/movable_backup = backup if((!movable_backup.anchored) && (movable_backup.newtonian_move(turn(movement_dir, 180)))) step_silent = TRUE - if(occupant) - to_chat(occupant, "You push off of [movable_backup] to propel yourself.") + if(return_drivers()) + to_chat(occupants, "[icon2html(src, occupants)]The [src] push off [movable_backup] to propel yourself.") return TRUE - if(can_move <= world.time && active_thrusters && movement_dir && active_thrusters.thrust(movement_dir)) + if(movedelay <= world.time && active_thrusters && movement_dir && active_thrusters.thrust(movement_dir)) step_silent = TRUE return TRUE return FALSE -/obj/mecha/relaymove(mob/user,direction) +/obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) + if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move)) + return FALSE + COOLDOWN_START(src, cooldown_vehicle_move, movedelay) if(completely_disabled) - return + return FALSE if(!direction) - return - if(user != occupant) //While not "realistic", this piece is player friendly. - user.forceMove(get_turf(src)) - to_chat(user, "You climb out from [src].") - return 0 + return FALSE if(internal_tank?.connected_port) - if(world.time - last_message > 20) - occupant_message("Unable to move while connected to the air system port!") - last_message = world.time - return 0 + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Unable to move while connected to the air system port!") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) + return FALSE if(construction_state) - if(world.time - last_message > 20) - occupant_message("Maintenance protocols are in effect.") - last_message = world.time - return - return domove(direction) - -/obj/mecha/proc/domove(direction) - if(can_move >= world.time) + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect.") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE + if(direction == UP || direction == DOWN) return FALSE if(!Process_Spacemove(direction)) @@ -593,96 +644,77 @@ if(!has_charge(step_energy_drain)) return FALSE if(zoom_mode) - if(world.time - last_message > 20) - occupant_message("Unable to move while in zoom mode.") - last_message = world.time + to_chat(occupants, "[icon2html(src, occupants)]Unable to move while in zoom mode!") return FALSE if(!cell) - if(world.time - last_message > 20) - occupant_message("Missing power cell.") - last_message = world.time + to_chat(occupants, "[icon2html(src, occupants)]Missing power cell.") return FALSE if(!scanmod || !capacitor) - if(world.time - last_message > 20) - occupant_message("Missing [scanmod? "capacitor" : "scanning module"].") - last_message = world.time + to_chat(occupants, "[icon2html(src, occupants)]Missing [scanmod? "capacitor" : "scanning module"].") return FALSE + if(lavaland_only && is_mining_level(z)) + to_chat(occupants, "[icon2html(src, occupants)]Invalid Environment.") + return FALSE + + var/olddir = dir - var/move_result = 0 - var/oldloc = loc if(internal_damage & MECHA_INT_CONTROL_LOST) - move_result = mechsteprand() - else if(dir != direction && (!strafe || occupant.client.keys_held["Alt"])) - move_result = mechturn(direction) - else - move_result = mechstep(direction) - if(move_result || loc != oldloc)// halfway done diagonal move still returns false - use_power(step_energy_drain) - can_move = world.time + (step_in * step_multiplier) + step_restricted - step_restricted = 0 + direction = pick(GLOB.alldirs) + + //only mechs with diagonal movement may move diagonally + if(!allow_diagonal_movement && ISDIAGONALDIR(direction)) return TRUE - return FALSE -/obj/mecha/proc/mechturn(direction) - setDir(direction) - if(turnsound) - playsound(src,turnsound,40,TRUE) - return 1 - -/obj/mecha/proc/mechstep(direction) - var/current_dir = dir - if(!isturf(get_step_multiz(src, direction))) // verify the turf we intend to step into is actually valid - direction = direction & ~(UP|DOWN) - var/result = step(src,direction) + //if we're not facing the way we're going rotate us + if(dir != direction && !strafe || forcerotate) + setDir(direction) + if(turnsound) + playsound(src,turnsound,40,TRUE) + return TRUE + + set_glide_size(DELAY_TO_GLIDE_SIZE(movedelay)) + //Otherwise just walk normally + . = step(src,direction, dir) + if(strafe) - setDir(current_dir) - if(result && !step_silent) - playsound(src,stepsound,40,1) - step_silent = FALSE - return result + for(var/D in return_drivers()) + var/mob/driver = D + if(driver.client?.keys_held["Alt"]) + return + setDir(olddir) -/obj/mecha/proc/mechsteprand() - var/result = step_rand(src) - if(result && !step_silent) - playsound(src,stepsound,40,1) - step_silent = FALSE - return result -/obj/mecha/Bump(var/atom/obstacle) +/obj/vehicle/sealed/mecha/Bump(atom/obstacle) if(phasing && get_charge() >= phasing_energy_drain && !throwing) - spawn() - if(can_move) - can_move = 0 - if(phase_state) - flick(phase_state, src) - var/turf/target = get_step(src, dir) - if(target.flags_1 & NOJAUNT_1) - occupant_message("Phasing anomaly detected, emergency deactivation initiated.") - sleep(step_in*3*step_multiplier) - can_move = 1 - phasing = FALSE - return - if(do_teleport(src, get_step(src, dir), no_effects = TRUE)) - use_power(phasing_energy_drain) - sleep(step_in*3*step_multiplier) - can_move = 1 - else - if(..()) //mech was thrown + if(phase_state) + flick(phase_state, src) + var/turf/target = get_step(src, dir) + if(target.flags_1 & NOJAUNT_1) + occupant_message("Phasing anomaly detected, emergency deactivation initiated.") + sleep(step_in*3*step_multiplier) + phasing = FALSE return - if(bumpsmash && occupant) //Need a pilot to push the PUNCH button. - if(nextsmash < world.time) - obstacle.mech_melee_attack(src) - nextsmash = world.time + smashcooldown - if(!obstacle || obstacle.CanPass(src, get_dir(obstacle, src) || dir)) // The else is in case the obstacle is in the same turf. - step(src,dir) - if(isobj(obstacle)) - var/obj/O = obstacle - if(!O.anchored && O.move_resist <= move_force) - step(obstacle, dir & ~(UP|DOWN)) - else if(ismob(obstacle)) - var/mob/M = obstacle - if(M.move_resist <= move_force) - step(obstacle, dir & ~(UP|DOWN)) + if(do_teleport(src, get_step(src, dir), no_effects = TRUE)) + use_power(phasing_energy_drain) + addtimer(VARSET_CALLBACK(src, movedelay, TRUE), movedelay*3*step_multiplier)\ + return + . = ..() + if(.) //mech was thrown/door/whatever + return + if(bumpsmash) //Need a pilot to push the PUNCH button. + if(COOLDOWN_FINISHED(src, mecha_bump_smash)) + obstacle.mech_melee_attack(src) + COOLDOWN_START(src, mecha_bump_smash, smashcooldown) + if(!obstacle || obstacle.CanPass(src, get_dir(obstacle, src) || dir)) // The else is in case the obstacle is in the same turf. + step(src,dir) + if(isobj(obstacle)) + var/obj/obj_obstacle = obstacle + if(!obj_obstacle.anchored && obj_obstacle.move_resist <= move_force) + step(obstacle, dir & ~(UP|DOWN)) + else if(ismob(obstacle)) + var/mob/mob_obstacle = obstacle + if(mob_obstacle.move_resist <= move_force) + step(obstacle, dir & ~(UP|DOWN)) @@ -692,7 +724,7 @@ //////// Internal damage //////// /////////////////////////////////// -/obj/mecha/proc/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null) +/obj/vehicle/sealed/mecha/proc/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null) if(!islist(possible_int_damage) || !length(possible_int_damage)) return if(prob(20)) @@ -705,27 +737,25 @@ setInternalDamage(int_dam_flag) if(prob(5)) if(ignore_threshold || obj_integrity*100/max_integrity < internal_damage_threshold) - var/obj/item/mecha_parts/mecha_equipment/ME = safepick(equipment) - if(ME) + if(LAZYLEN(equipment)) + var/obj/item/mecha_parts/mecha_equipment/ME = safepick(equipment) qdel(ME) - return -/obj/mecha/proc/setInternalDamage(int_dam_flag) +/obj/vehicle/sealed/mecha/proc/setInternalDamage(int_dam_flag) internal_damage |= int_dam_flag log_message("Internal damage of type [int_dam_flag].", LOG_MECHA) - SEND_SOUND(occupant, sound('sound/machines/warning-buzzer.ogg',wait=0)) + SEND_SOUND(occupants, sound('sound/machines/warning-buzzer.ogg',wait=0)) diag_hud_set_mechstat() - return -/obj/mecha/proc/clearInternalDamage(int_dam_flag) +/obj/vehicle/sealed/mecha/proc/clearInternalDamage(int_dam_flag) if(internal_damage & int_dam_flag) switch(int_dam_flag) if(MECHA_INT_TEMP_CONTROL) - occupant_message("Life support system reactivated.") + to_chat(occupants, "[icon2html(src, occupants)]Life support system reactivated.") if(MECHA_INT_FIRE) - occupant_message("Internal fire extinguished.") + to_chat(occupants, "[icon2html(src, occupants)]Internal fire extinguished.") if(MECHA_INT_TANK_BREACH) - occupant_message("Damaged internal tank has been sealed.") + to_chat(occupants, "[icon2html(src, occupants)]Damaged internal tank has been sealed.") internal_damage &= ~int_dam_flag diag_hud_set_mechstat() @@ -733,7 +763,7 @@ //////////// AI piloting //////////// ///////////////////////////////////// -/obj/mecha/attack_ai(mob/living/silicon/ai/user) +/obj/vehicle/sealed/mecha/attack_ai(mob/living/silicon/ai/user) if(!isAI(user)) return //Allows the Malf to scan a mech's status and loadout, helping it to decide if it is a worthy chariot. @@ -747,7 +777,7 @@ to_chat(user, "ASSUME DIRECT CONTROL?
") else examine(user) - if(occupant) + if(length(return_drivers()) > 0) to_chat(user, "This exosuit has a pilot and cannot be controlled.") return var/can_control_mech = 0 @@ -760,42 +790,40 @@ return to_chat(user, "Take control of exosuit?
") -/obj/mecha/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) +/obj/vehicle/sealed/mecha/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) if(!..()) return - //Transfer from core or card to mech. Proc is called by mech. + //Transfer from core or card to mech. Proc is called by mech. switch(interaction) if(AI_TRANS_TO_CARD) //Upload AI from mech to AI card. if(!construction_state) //Mech must be in maint mode to allow carding. to_chat(user, "[name] must have maintenance protocols active in order to allow a transfer.") return - AI = occupant - if(!AI || !isAI(occupant)) //Mech does not have an AI for a pilot + if(!locate(AI) in occupants) //Mech does not have an AI for a pilot to_chat(user, "No AI detected in the [name] onboard computer.") return + for(var/mob/living/silicon/ai in occupants) AI.ai_restore_power()//So the AI initially has power. AI.control_disabled = TRUE AI.radio_enabled = FALSE AI.disconnect_shell() - RemoveActions(AI, TRUE) - occupant = null - silicon_pilot = FALSE + remove_occupant(AI) + mecha_flags &= ~SILICON_PILOT AI.forceMove(card) card.AI = AI AI.controlled_mech = null AI.remote_control = null - icon_state = "[base_icon_state]-open" to_chat(AI, "You have been downloaded to a mobile storage device. Wireless connection offline.") to_chat(user, "Transfer successful: [AI.name] ([rand(1000,9999)].exe) removed from [name] and stored within local memory.") if(AI_MECH_HACK) //Called by AIs on the mech AI.linked_core = new /obj/structure/AIcore/deactivated(AI.loc) if(AI.can_dominate_mechs) - if(occupant) //Oh, I am sorry, were you using that? - to_chat(AI, "Pilot detected! Forced ejection initiated!") - to_chat(occupant, "You have been forcibly ejected!") - go_out(1) //IT IS MINE, NOW. SUCK IT, RD! + if(LAZYLEN(occupants)) //Oh, I am sorry, were you using that? + to_chat(AI, "Occupants detected! Forced ejection initiated!") + to_chat(occupants, "You have been forcibly ejected!") + ejectall() //IT IS MINE, NOW. SUCK IT, RD! ai_enter_mech(AI, interaction) if(AI_TRANS_FROM_CARD) //Using an AI card to upload to a mech. @@ -818,170 +846,154 @@ ai_enter_mech(AI, interaction) //Hack and From Card interactions share some code, so leave that here for both to use. -/obj/mecha/proc/ai_enter_mech(mob/living/silicon/ai/AI, interaction) +/obj/vehicle/sealed/mecha/proc/ai_enter_mech(mob/living/silicon/ai/AI, interaction) AI.ai_restore_power() - AI.forceMove(src) - occupant = AI - silicon_pilot = TRUE - icon_state = base_icon_state - update_icon() - playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - if(!internal_damage) - SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) + mecha_flags |= SILICON_PILOT + moved_inside(AI) AI.cancel_camera() AI.controlled_mech = src AI.remote_control = src AI.mobility_flags = ALL //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow. - AI.can_shunt = 0 //ONE AI ENTERS. NO AI LEAVES. + if(interaction == AI_MECH_HACK) + AI.can_shunt = FALSE //ONE AI ENTERS. NO AI LEAVES. to_chat(AI, AI.can_dominate_mechs ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!" :\ "You have been uploaded to a mech's onboard computer.") to_chat(AI, "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions.") - if(interaction == AI_TRANS_FROM_CARD) - GrantActions(AI, FALSE) //No eject/return to core action for AI uploaded by card - else - GrantActions(AI, !AI.can_dominate_mechs) - -//An actual AI (simple_animal mecha pilot) entering the mech -/obj/mecha/proc/aimob_enter_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) +///Handles an actual AI (simple_animal mecha pilot) entering the mech +/obj/vehicle/sealed/mecha/proc/aimob_enter_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) if(pilot_mob && pilot_mob.Adjacent(src)) - if(occupant) + if(occupants) return - icon_state = base_icon_state - occupant = pilot_mob + LAZYADD(occupants, src) pilot_mob.mecha = src pilot_mob.forceMove(src) - GrantActions(pilot_mob)//needed for checks, and incase a badmin puts somebody in the mob + update_icon() -/obj/mecha/proc/aimob_exit_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) - if(occupant == pilot_mob) - occupant = null +///Handles an actual AI (simple_animal mecha pilot) exiting the mech +/obj/vehicle/sealed/mecha/proc/aimob_exit_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) + LAZYREMOVE(occupants, pilot_mob) if(pilot_mob.mecha == src) pilot_mob.mecha = null - icon_state = "[base_icon_state]-open" pilot_mob.forceMove(get_turf(src)) - RemoveActions(pilot_mob) + update_icon() ///////////////////////////////////// //////// Atmospheric stuff //////// ///////////////////////////////////// -/obj/mecha/remove_air(amount) +/obj/vehicle/sealed/mecha/remove_air(amount) if(use_internal_tank) return cabin_air.remove(amount) return ..() -/obj/mecha/remove_air_ratio(ratio) +/obj/vehicle/sealed/mecha/remove_air_ratio(ratio) if(use_internal_tank) return cabin_air.remove_ratio(ratio) return ..() -/obj/mecha/return_air() +/obj/vehicle/sealed/mecha/return_air() if(use_internal_tank) return cabin_air return ..() -/obj/mecha/return_analyzable_air() +/obj/vehicle/sealed/mecha/return_analyzable_air() return cabin_air -/obj/mecha/proc/return_pressure() +/obj/vehicle/sealed/mecha/proc/return_pressure() var/datum/gas_mixture/t_air = return_air() if(t_air) - . = t_air.return_pressure() + return t_air.return_pressure() return -/obj/mecha/return_temperature() +/obj/vehicle/sealed/mecha/return_temperature() var/datum/gas_mixture/t_air = return_air() if(t_air) - . = t_air.return_temperature() + return t_air.return_temperature() return -/obj/mecha/portableConnectorReturnAir() +/obj/vehicle/sealed/mecha/portableConnectorReturnAir() return internal_tank.return_air() - -/obj/mecha/MouseDrop_T(mob/M, mob/user) - if((user != M) || user.incapacitated() || !Adjacent(user)) - return - if(!ishuman(user)) // no silicons or drones in mechas. +/obj/vehicle/sealed/mecha/mob_try_enter(mob/M) + if(!ishuman(M)) // no silicons or drones in mechas. return - log_message("[user] tries to move in.", LOG_MECHA) - if (occupant) - to_chat(usr, "The [name] is already occupied!") - log_message("Permission denied (Occupied).", LOG_MECHA) - return - if(!operation_allowed(user)) - to_chat(user, "Access denied. Insufficient operation keycodes.") + log_message("[M] tries to move into [src].", LOG_MECHA) + if(!operation_allowed(M)) + to_chat(M, "Access denied. Insufficient operation keycodes.") log_message("Permission denied (No keycode).", LOG_MECHA) return - if(user.buckled) - to_chat(user, "You are currently buckled and cannot move.") + if(M.buckled) + to_chat(M, "You are currently buckled and cannot move.") log_message("Permission denied (Buckled).", LOG_MECHA) return - if(user.has_buckled_mobs()) //mob attached to us - to_chat(user, "You can't enter the exosuit with other creatures attached to you!") + if(M.has_buckled_mobs()) //mob attached to us + to_chat(M, "You can't enter the exosuit with other creatures attached to you!") log_message("Permission denied (Attached mobs).", LOG_MECHA) return - visible_message("[user] starts to climb into [name].") + visible_message("[M] starts to climb into [name].") - if(do_after(user, enter_delay, target = src)) + if(do_after(M, enter_delay, target = src)) if(obj_integrity <= 0) - to_chat(user, "You cannot get in the [name], it has been destroyed!") - else if(occupant) - to_chat(user, "[occupant] was faster! Try better next time, loser.") - else if(user.buckled) - to_chat(user, "You can't enter the exosuit while buckled.") - else if(user.has_buckled_mobs()) - to_chat(user, "You can't enter the exosuit with other creatures attached to you!") + to_chat(M, "You cannot get in the [name], it has been destroyed!") + else if(LAZYLEN(occupants) >= max_occupants) + to_chat(M, "[occupants[occupants.len]] was faster! Try better next time, loser.")//get the last one that hopped in + else if(M.buckled) + to_chat(M, "You can't enter the exosuit while buckled.") + else if(M.has_buckled_mobs()) + to_chat(M, "You can't enter the exosuit with other creatures attached to you!") else - moved_inside(user) + moved_inside(M) + return ..() else - to_chat(user, "You stop entering the exosuit!") - return - -/obj/mecha/proc/moved_inside(mob/living/carbon/human/H) - if(H?.client && get_dist(H, src) <= 1) - occupant = H - H.forceMove(src) - H.update_mouse_pointer() - add_fingerprint(H) - GrantActions(H, human_occupant=1) - forceMove(loc) - log_message("[H] moved in as pilot.", LOG_MECHA) - icon_state = base_icon_state - setDir(dir_in) - playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - if(!internal_damage) - SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) - return 1 - else - return 0 + to_chat(M, "You stop entering the exosuit!") + +/obj/vehicle/sealed/mecha/generate_actions() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe) + +/obj/vehicle/sealed/mecha/proc/moved_inside(mob/living/H) + . = FALSE + if(!(H?.client)) + return + if(ishuman(H) && !Adjacent(H)) + return + add_occupant(H) + H.forceMove(src) + H.update_mouse_pointer() + add_fingerprint(H) + log_message("[H] moved in as pilot.", LOG_MECHA) + setDir(dir_in) + playsound(src, 'sound/machines/windowdoor.ogg', 50, TRUE) + if(!internal_damage) + SEND_SOUND(H, sound('sound/mecha/nominal.ogg',volume=50)) + return TRUE -/obj/mecha/proc/mmi_move_inside(obj/item/mmi/mmi_as_oc, mob/user) - if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) - to_chat(user, "Consciousness matrix not detected!") +/obj/vehicle/sealed/mecha/proc/mmi_move_inside(obj/item/mmi/M, mob/user) + if(!M.brain_check(user)) return FALSE - else if(mmi_as_oc.brainmob.stat) - to_chat(user, "Beta-rhythm below acceptable level!") - return FALSE - else if(occupant) - to_chat(user, "Occupant detected!") + if(LAZYLEN(occupants) >= max_occupants) + to_chat(user, "It's full!") return FALSE visible_message("[user] starts to insert an MMI into [name].") if(do_after(user, 40, target = src)) - if(!occupant) - return mmi_moved_inside(mmi_as_oc, user) + if(LAZYLEN(occupants) < max_occupants) + return mmi_moved_inside(M, user) else - to_chat(user, "Occupant detected!") + to_chat(user, "Maximum occupants detected!") else to_chat(user, "You stop inserting the MMI.") return FALSE -/obj/mecha/proc/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user) - if(!(Adjacent(mmi_as_oc) && Adjacent(user))) +/obj/vehicle/sealed/mecha/proc/mmi_moved_inside(obj/item/mmi/M, mob/user) + if(!(Adjacent(M) && Adjacent(user))) return FALSE if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) to_chat(user, "Consciousness matrix not detected!") @@ -993,71 +1005,54 @@ to_chat(user, "\the [mmi_as_oc] is stuck to your hand, you cannot put it in \the [src]!") return FALSE var/mob/living/brainmob = mmi_as_oc.brainmob - mmi_as_oc.mecha = src - occupant = brainmob - silicon_pilot = TRUE - brainmob.forceMove(src) //should allow relaymove - brainmob.reset_perspective(src) - brainmob.remote_control = src + M.mecha = src + add_occupant(B)//Note this forcemoves the brain into the mech to allow relaymove + mecha_flags |= SILICON_PILOT + B.reset_perspective(src) + B.remote_control = src brainmob.update_mobility() brainmob.update_mouse_pointer() - icon_state = base_icon_state update_icon() setDir(dir_in) - log_message("[mmi_as_oc] moved in as pilot.", LOG_MECHA) + log_message("[M] moved in as pilot.", LOG_MECHA) if(!internal_damage) - SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) - GrantActions(brainmob) + SEND_SOUND(M, sound('sound/mecha/nominal.ogg',volume=50)) + log_game("[key_name(user)] has put the MMI/posibrain of [key_name(B)] into [src] at [AREACOORD(src)]") return TRUE -/obj/mecha/container_resist(mob/living/user) +/obj/vehicle/sealed/mecha/container_resist_act(mob/living/user) + if(isAI(user)) + var/mob/living/silicon/ai/AI = user + if(!AI.can_shunt) + to_chat(AI, "You can't leave a mech after dominating it!.") + return FALSE + to_chat(user, "You begin the ejection procedure. Equipment is disabled during this process. Hold still to finish ejecting.") is_currently_ejecting = TRUE - to_chat(occupant, "You begin the ejection procedure. Equipment is disabled during this process. Hold still to finish ejecting.") - if(do_after(occupant,exit_delay, target = src)) - to_chat(occupant, "You exit the mech.") - go_out() + if(do_after(user, has_gravity() ? exit_delay : 0 , target = src)) + to_chat(user, "You exit the mech.") + mob_exit(user, TRUE) else - to_chat(occupant, "You stop exiting the mech. Weapons are enabled again.") + to_chat(user, "You stop exiting the mech. Weapons are enabled again.") is_currently_ejecting = FALSE -/obj/mecha/Exited(atom/movable/M, atom/newloc) - . = ..() - if(occupant && occupant == M) // The occupant exited the mech without calling go_out() - go_out(TRUE, newloc) - - if(cell && cell == M) - cell = null - return - if(scanmod && scanmod == M) - scanmod = null - update_part_values() - return - if(capacitor && capacitor == M) - armor = armor.modifyRating(energy = (capacitor.rating * -5)) //lose the energy armor if we lose this cap - capacitor = null - update_part_values() - return +/obj/vehicle/sealed/mecha/proc/ejectall() + for(var/ejectee in occupants) + mob_exit(ejectee, TRUE, TRUE) -/obj/mecha/proc/go_out(forced, atom/newloc = loc) - if(!occupant) - return +/obj/vehicle/sealed/mecha/mob_exit(mob/M, silent, forced) + var/newloc = get_turf(src) var/atom/movable/mob_container - occupant.clear_alert("charge") - occupant.clear_alert("mech damage") - if(ishuman(occupant)) - mob_container = occupant - RemoveActions(occupant, human_occupant=1) - else if(isbrain(occupant)) - var/mob/living/brain/brain = occupant - RemoveActions(brain) + if(ishuman(M)) + mob_container = M + else if(isbrain(M)) + var/mob/living/brain/brain = M mob_container = brain.container - else if(isAI(occupant)) - var/mob/living/silicon/ai/AI = occupant + else if(isAI(M)) + var/mob/living/silicon/ai/AI = M if(forced)//This should only happen if there are multiple AIs in a round, and at least one is Malf. - RemoveActions(occupant) - occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. - occupant = null - silicon_pilot = FALSE + AI.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. + AI = null + mecha_flags &= ~SILICON_PILOT return else if(!AI.linked_core) @@ -1067,15 +1062,13 @@ to_chat(AI, "Returning to core...") AI.controlled_mech = null AI.remote_control = null - RemoveActions(occupant, 1) mob_container = AI newloc = get_turf(AI.linked_core) qdel(AI.linked_core) else - return - var/mob/living/L = occupant - occupant = null //we need it null when forceMove calls Exited(). - silicon_pilot = FALSE + return ..() + var/mob/living/L = M + mecha_flags &= ~SILICON_PILOT if(mob_container.forceMove(newloc))//ejecting mob container log_message("[mob_container] moved out.", LOG_MECHA) L << browse(null, "window=exosuit") @@ -1085,54 +1078,65 @@ if(mmi.brainmob) L.forceMove(mmi) L.reset_perspective() + remove_occupant(L) mmi.mecha = null mmi.update_icon() L.mobility_flags = NONE - icon_state = "[base_icon_state]-open" + update_icon() setDir(dir_in) + return ..() + - if(L?.client) - L.update_mouse_pointer() - L.client.view_size.resetToDefault() +/obj/vehicle/sealed/mecha/add_occupant(mob/M, control_flags) + RegisterSignal(M, COMSIG_MOB_DEATH, .proc/mob_exit) + RegisterSignal(M, COMSIG_MOB_CLICKON, .proc/on_mouseclick) + RegisterSignal(M, COMSIG_MOB_SAY, .proc/display_speech_bubble) + update_icon() + return ..() + +/obj/vehicle/sealed/mecha/remove_occupant(mob/M) + UnregisterSignal(M, COMSIG_MOB_DEATH) + UnregisterSignal(M, COMSIG_MOB_CLICKON) + UnregisterSignal(M, COMSIG_MOB_SAY) + update_icon() + M.clear_alert("charge") + M.clear_alert("mech damage") + if(M.client) + M.update_mouse_pointer() + M.client.view_size.resetToDefault() zoom_mode = 0 + return ..() ///////////////////////// ////// Access stuff ///// ///////////////////////// -/obj/mecha/proc/operation_allowed(mob/M) +/obj/vehicle/sealed/mecha/proc/operation_allowed(mob/M) req_access = operation_req_access req_one_access = list() return allowed(M) -/obj/mecha/proc/internals_access_allowed(mob/M) +/obj/vehicle/sealed/mecha/proc/internals_access_allowed(mob/M) req_one_access = internals_req_access req_access = list() return allowed(M) - - //////////////////////////////// /////// Messages and Log /////// //////////////////////////////// -/obj/mecha/proc/occupant_message(message as text) - if(message) - if(occupant && occupant.client) - to_chat(occupant, "[icon2html(src, occupant)] [message]") - return - GLOBAL_VAR_INIT(year, time2text(world.realtime,"YYYY")) -GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? +GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? // = 2017??? +//why is this here /////////////////////// ///// Power stuff ///// /////////////////////// -/obj/mecha/proc/has_charge(amount) +/obj/vehicle/sealed/mecha/proc/has_charge(amount) return (get_charge()>=amount) -/obj/mecha/proc/get_charge() +/obj/vehicle/sealed/mecha/proc/get_charge() for(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/R in equipment) var/relay_charge = R.get_charge() if(relay_charge) @@ -1140,24 +1144,18 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? if(cell) return max(0, cell.charge) -/obj/mecha/proc/use_power(amount) +/obj/vehicle/sealed/mecha/proc/use_power(amount) if(get_charge() && cell.use(amount)) - return 1 - return 0 + return TRUE + return FALSE /obj/mecha/proc/give_power(amount) if(!isnull(get_charge())) cell.give(amount) - return 1 - return 0 - -/obj/mecha/update_remote_sight(mob/living/user) - if(occupant_sight_flags) - if(user == occupant) - user.sight |= occupant_sight_flags - + return TRUE + return FALSE -/obj/mecha/lighteater_act(obj/item/light_eater/light_eater, atom/parent) +/obj/vehicle/sealed/mecha/lighteater_act(obj/item/light_eater/light_eater, atom/parent) ..() if(!lights_power) return From 928af32280fa5ae6b7a0f3002b9ff80d1545ecf7 Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 23:07:23 -0400 Subject: [PATCH 04/41] /combat/ pass 1 --- code/modules/vehicles/mecha/combat/combat.dm | 4 +- code/modules/vehicles/mecha/combat/durand.dm | 115 ++++++++++-------- code/modules/vehicles/mecha/combat/gygax.dm | 28 ++--- code/modules/vehicles/mecha/combat/honker.dm | 49 +++----- .../modules/vehicles/mecha/combat/marauder.dm | 36 +++--- code/modules/vehicles/mecha/combat/phazon.dm | 21 +--- .../vehicles/mecha/combat/reticence.dm | 8 +- 7 files changed, 120 insertions(+), 141 deletions(-) diff --git a/code/modules/vehicles/mecha/combat/combat.dm b/code/modules/vehicles/mecha/combat/combat.dm index 9c2002269610a..11dfb5a7672a1 100644 --- a/code/modules/vehicles/mecha/combat/combat.dm +++ b/code/modules/vehicles/mecha/combat/combat.dm @@ -1,4 +1,4 @@ -/obj/mecha/combat +/obj/vehicle/sealed/mecha/combat force = 30 internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY) internal_damage_threshold = 50 @@ -7,6 +7,6 @@ destruction_sleep_duration = 40 exit_delay = 40 -/obj/mecha/combat/restore_equipment() +/obj/vehicle/sealed/mecha/combat/restore_equipment() mouse_pointer = 'icons/mecha/mecha_mouse.dmi' . = ..() diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm index aabac69c0b42d..76a28d726aa91 100644 --- a/code/modules/vehicles/mecha/combat/durand.dm +++ b/code/modules/vehicles/mecha/combat/durand.dm @@ -1,82 +1,81 @@ -/obj/mecha/combat/durand +/obj/vehicle/sealed/mecha/combat/durand desc = "An aging combat exosuit utilized by the Nanotrasen corporation. Originally developed to combat hostile alien lifeforms." name = "\improper Durand" icon_state = "durand" base_icon_state = "durand" - step_in = 4 + movedelay = 4 dir_in = 1 //Facing North. max_integrity = 400 deflect_chance = 20 armor = list(MELEE = 40, BULLET = 35, LASER = 15, ENERGY = 10, BOMB = 20, BIO = 0, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 0) max_temperature = 30000 - infra_luminosity = 8 force = 40 wreckage = /obj/structure/mecha_wreckage/durand var/obj/durand_shield/shield -/obj/mecha/combat/durand/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/durand/Initialize(mapload) . = ..() shield = new /obj/durand_shield(loc, src, layer, dir) - RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, PROC_REF(relay)) + RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(relay)) RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, PROC_REF(prehit)) -/obj/mecha/combat/durand/Destroy() +/obj/vehicle/sealed/mecha/combat/durand/Destroy() if(shield) QDEL_NULL(shield) return ..() -/obj/mecha/combat/durand/GrantActions(mob/living/user, human_occupant = 0) - ..() - defense_action.Grant(user, src) - -/obj/mecha/combat/durand/RemoveActions(mob/living/user, human_occupant = 0) - ..() - defense_action.Remove(user) - -/obj/mecha/combat/durand/process() +/obj/vehicle/sealed/mecha/combat/durand/generate_actions() . = ..() - if(defense_mode && !use_power(100)) - defense_action.Activate(forced_state = TRUE) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_defense_mode) -/obj/mecha/combat/durand/domove(direction) +/obj/vehicle/sealed/mecha/combat/durand/process() + . = ..() + if(defense_mode && !use_power(100)) //Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle + for(var/O in occupants) + var/mob/living/occupant = O + var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode) + if(action) + action.Trigger() + break + +/obj/vehicle/sealed/mecha/combat/durand/Move(direction) . = ..() if(shield) shield.forceMove(loc) shield.setDir(dir) -/obj/mecha/combat/durand/forceMove(var/turf/T) +/obj/vehicle/sealed/mecha/combat/durand/forceMove(turf/T) . = ..() shield.forceMove(T) -/obj/mecha/combat/durand/go_out(forced, atom/newloc = loc) +/obj/vehicle/sealed/mecha/combat/durand/mob_exit(mob/M, silent, randomstep, forced) if(defense_mode) - defense_action.Activate(forced_state = TRUE) - . = ..() + var/datum/action/action = LAZYACCESSASSOC(occupant_actions, M, /datum/action/vehicle/sealed/mecha/mech_defense_mode) + if(action) + action.Trigger(FALSE) + return ..() ///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA. -/obj/mecha/combat/durand/proc/relay(datum/source, list/signal_args) +/obj/vehicle/sealed/mecha/combat/durand/proc/relay(datum/source, mob/owner, list/signal_args) SIGNAL_HANDLER - if(!shield) //if the shield somehow got deleted stack_trace("Durand triggered relay without a shield") shield = new /obj/durand_shield(loc, src, layer) shield.setDir(dir) - SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_ACTIVATE, source, signal_args) + SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_TRIGGER, owner, signal_args) //Redirects projectiles to the shield if defense_check decides they should be blocked and returns true. -/obj/mecha/combat/durand/proc/prehit(obj/projectile/source, list/signal_args) - SIGNAL_HANDLER - +/obj/vehicle/sealed/mecha/combat/durand/proc/prehit(obj/projectile/source, list/signal_args) if(defense_check(source.loc) && shield) signal_args[2] = shield /**Checks if defense mode is enabled, and if the attacker is standing in an area covered by the shield. Expects a turf. Returns true if the attack should be blocked, false if not.*/ -/obj/mecha/combat/durand/proc/defense_check(var/turf/aloc) +/obj/vehicle/sealed/mecha/combat/durand/proc/defense_check(turf/aloc) if (!defense_mode || !shield || shield.switching) return FALSE . = FALSE @@ -95,14 +94,14 @@ Expects a turf. Returns true if the attack should be blocked, false if not.*/ . = TRUE return -/obj/mecha/combat/durand/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0) +/obj/vehicle/sealed/mecha/combat/durand/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0) if(defense_check(user.loc)) log_message("Attack absorbed by defense field. Attacker - [user].", LOG_MECHA, color="orange") shield.attack_generic(user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration) else . = ..() -/obj/mecha/combat/durand/blob_act(obj/structure/blob/B) +/obj/vehicle/sealed/mecha/combat/durand/blob_act(obj/structure/blob/B) if(defense_check(B.loc)) log_message("Attack by blob. Attacker - [B].", LOG_MECHA, color="red") log_message("Attack absorbed by defense field.", LOG_MECHA, color="orange") @@ -110,14 +109,14 @@ Expects a turf. Returns true if the attack should be blocked, false if not.*/ else . = ..() -/obj/mecha/combat/durand/attackby(obj/item/W as obj, mob/user as mob, params) +/obj/vehicle/sealed/mecha/combat/durand/attackby(obj/item/W as obj, mob/user as mob, params) if(defense_check(user.loc)) log_message("Attack absorbed by defense field. Attacker - [user], with [W]", LOG_MECHA, color="orange") shield.attackby(W, user, params) else . = ..() -/obj/mecha/combat/durand/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) +/obj/vehicle/sealed/mecha/combat/durand/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) if(defense_check(AM.loc)) log_message("Impact with [AM] absorbed by defense field.", LOG_MECHA, color="orange") shield.hitby(AM, skipcatch, hitpush, blocked, throwingdatum) @@ -148,8 +147,11 @@ own integrity back to max. Shield is automatically dropped if we run out of powe light_power = 5 light_color = LIGHT_COLOR_CYAN light_on = FALSE - var/obj/mecha/combat/durand/chassis ///Our link back to the durand - var/switching = FALSE ///To keep track of things during the animation + ///Our link back to the durand + var/obj/vehicle/sealed/mecha/combat/durand/chassis + ///To keep track of things during the animation + var/switching = FALSE + var/currentuser /obj/durand_shield/Initialize(mapload, _chassis, _layer, _dir) @@ -157,7 +159,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe chassis = _chassis layer = _layer setDir(_dir) - RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, PROC_REF(activate)) + RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(activate)) /obj/durand_shield/Destroy() @@ -166,29 +168,36 @@ own integrity back to max. Shield is automatically dropped if we run out of powe chassis = null return ..() -/**Handles activating and deactivating the shield. This proc is called by a signal sent from the mech's action button -and relayed by the mech itself. The "forced" variabe, signal_args[1], will skip the to-pilot text and is meant for when -the shield is disabled by means other than the action button (like running out of power)*/ - -/obj/durand_shield/proc/activate(datum/source, var/datum/action/innate/mecha/mech_defense_mode/button, list/signal_args) +/** + *Handles activating and deactivating the shield. This proc is called by a signal sent from the mech's action button + *and relayed by the mech itself. The "forced" variabe, signal_args[1], will skip the to-pilot text and is meant for when + *the shield is disabled by means other than the action button (like running out of power) + * Arguments: + * * source: the shield + * * owner: mob that activated the shield + * * signal_args: whether it's forced + */ +/obj/durand_shield/proc/activate(datum/source, mob/owner, list/signal_args) SIGNAL_HANDLER - - if(!chassis || !chassis.occupant) + currentuser = owner + if(!chassis?.occupants) return if(switching && !signal_args[1]) return if(!chassis.defense_mode && (!chassis.cell || chassis.cell.charge < 100)) //If it's off, and we have less than 100 units of power - chassis.balloon_alert(chassis.occupant, "Insufficient power.") + chassis.balloon_alert(chassis.occupants, "Insufficient power.") return switching = TRUE chassis.defense_mode = !chassis.defense_mode - chassis.defense_action.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]" //This is backwards because we haven't changed the var yet if(!signal_args[1]) - chassis.balloon_alert(chassis.occupant, "Shield [chassis.defense_mode ? "enabled" : "disabled"].") + chassis.balloon_alert(chassis.occupants, "Shield [chassis.defense_mode ? "enabled" : "disabled"].") chassis.log_message("User has toggled defense mode -- now [chassis.defense_mode ? "enabled" : "disabled"].", LOG_MECHA) else chassis.log_message("defense mode state changed -- now [chassis.defense_mode ? "enabled" : "disabled"].", LOG_MECHA) - chassis.defense_action.UpdateButtonIcon() + for(var/occupant in chassis.occupants) + var/datum/action/button = chassis.occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode] + button.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]" + button.UpdateButtonIcon() set_light_on(chassis.defense_mode) @@ -196,14 +205,21 @@ the shield is disabled by means other than the action button (like running out o invisibility = 0 flick("shield_raise", src) playsound(src, 'sound/mecha/mech_shield_raise.ogg', 50, FALSE) + set_light(l_range = MINIMUM_USEFUL_LIGHT_RANGE , l_power = 5, l_color = "#00FFFF") icon_state = "shield" + RegisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE, .proc/resetdir) else flick("shield_drop", src) playsound(src, 'sound/mecha/mech_shield_drop.ogg', 50, FALSE) + set_light(0) icon_state = "shield_null" invisibility = INVISIBILITY_MAXIMUM //no showing on right-click + UnregisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE) switching = FALSE +/obj/durand_shield/proc/resetdir(datum/source, olddir, newdir) + setDir(newdir) + /obj/durand_shield/take_damage() if(!chassis) qdel(src) @@ -214,7 +230,10 @@ the shield is disabled by means other than the action button (like running out o flick("shield_impact", src) if(!chassis.use_power((max_integrity - obj_integrity) * 100)) chassis.cell?.charge = 0 - chassis.defense_action.Activate(forced_state = TRUE) + for(var/O in chassis.occupants) + var/mob/living/occupant = O + var/datum/action/action = LAZYACCESSASSOC(chassis.occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode) + action.Trigger(FALSE) obj_integrity = 10000 /obj/durand_shield/play_attack_sound() diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm index 0e571452320c4..873788e979ee2 100644 --- a/code/modules/vehicles/mecha/combat/gygax.dm +++ b/code/modules/vehicles/mecha/combat/gygax.dm @@ -1,23 +1,23 @@ -/obj/mecha/combat/gygax +/obj/vehicle/sealed/mecha/combat/gygax desc = "A lightweight, security exosuit. Popular among private and corporate security." name = "\improper Gygax" icon_state = "gygax" base_icon_state = "gygax" - step_in = 3 + allow_diagonal_movement = TRUE + movedelay = 3 dir_in = 1 //Facing North. max_integrity = 250 deflect_chance = 5 armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) max_temperature = 25000 leg_overload_coeff = 80 - infra_luminosity = 6 force = 25 wreckage = /obj/structure/mecha_wreckage/gygax internal_damage_threshold = 35 max_equip = 3 step_energy_drain = 3 -/obj/mecha/combat/gygax/dark +/obj/vehicle/sealed/mecha/combat/gygax/dark desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." name = "\improper Dark Gygax" icon_state = "darkgygax" @@ -33,7 +33,7 @@ max_equip = 5 destruction_sleep_duration = 20 -/obj/mecha/combat/gygax/dark/loaded/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/gygax/dark/loaded/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) @@ -46,23 +46,15 @@ ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay ME.attach(src) -/obj/mecha/combat/gygax/dark/add_cell(obj/item/stock_parts/cell/C=null) +/obj/vehicle/sealed/mecha/combat/gygax/dark/add_cell(obj/item/stock_parts/cell/C=null) if(C) C.forceMove(src) cell = C return - cell = new /obj/item/stock_parts/cell/hyper(src) + cell = new /obj/item/stock_parts/cell/bluespace(src) -/obj/mecha/combat/gygax/GrantActions(mob/living/user, human_occupant = 0) - ..() - overload_action.Grant(user, src) - - -/obj/mecha/combat/gygax/RemoveActions(mob/living/user, human_occupant = 0) - ..() - overload_action.Remove(user) - -/obj/mecha/combat/gygax/dark/RemoveActions(mob/living/user, human_occupant = 0) - ..() +/obj/vehicle/sealed/mecha/combat/gygax/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_overload_mode) diff --git a/code/modules/vehicles/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm index 04ddc20f3bde5..7666b68d688b9 100644 --- a/code/modules/vehicles/mecha/combat/honker.dm +++ b/code/modules/vehicles/mecha/combat/honker.dm @@ -1,23 +1,22 @@ -/obj/mecha/combat/honker +/obj/vehicle/sealed/mecha/combat/honker desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. Used to spread the fun and joy of life. HONK!" name = "\improper H.O.N.K" icon_state = "honker" base_icon_state = "honker" - step_in = 3 + movedelay = 3 max_integrity = 140 deflect_chance = 60 internal_damage_threshold = 60 armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) max_temperature = 25000 - infra_luminosity = 5 operation_req_access = list(ACCESS_THEATRE) internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_THEATRE) wreckage = /obj/structure/mecha_wreckage/honker - add_req_access = 0 + mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS max_equip = 3 var/squeak = 0 -/obj/mecha/combat/honker/get_stats_part() +/obj/vehicle/sealed/mecha/combat/honker/get_stats_part(mob/user) var/integrity = obj_integrity/max_integrity*100 var/cell_charge = get_charge() var/datum/gas_mixture/int_tank_air = internal_tank.return_air() @@ -36,11 +35,11 @@ AirHONK temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
HONK pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
HONK temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
- Lights: [lights?"on":"off"]
+ Lights: [(mecha_flags & LIGHTS_ON)?"on":"off"]
"} return output -/obj/mecha/combat/honker/get_stats_html() +/obj/vehicle/sealed/mecha/combat/honker/get_stats_html(mob/user) var/output = {" @@ -83,7 +82,7 @@
- [src.get_stats_part()] + [src.get_stats_part(user)]
[src.get_equipment_list()] @@ -100,7 +99,7 @@ "} return output -/obj/mecha/combat/honker/get_commands() +/obj/vehicle/sealed/mecha/combat/honker/get_commands() var/output = {"
Sounds of HONK:
"} -/obj/mecha/combat/honker/get_equipment_list() - if(!equipment.len) +/obj/vehicle/sealed/mecha/combat/honker/get_equipment_list() + if(!LAZYLEN(equipment)) return var/output = "Honk-ON-Systems:
" for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) @@ -145,19 +144,12 @@ output += "
" return output +/obj/vehicle/sealed/mecha/combat/honker/play_stepsound() + if(squeak) + playsound(src, "clownstep", 70, 1) + squeak = !squeak - -/obj/mecha/combat/honker/mechstep(direction) - var/result = step(src,direction) - if(result) - if(!squeak) - playsound(src, "clownstep", 70, 1) - squeak = 1 - else - squeak = 0 - return result - -/obj/mecha/combat/honker/Topic(href, href_list) +/obj/vehicle/sealed/mecha/combat/honker/Topic(href, href_list) ..() if (href_list["play_sound"]) switch(href_list["play_sound"]) @@ -188,12 +180,3 @@ if("explosionfar") playsound(src, 'sound/effects/explosionfar.ogg', 50) return - -/proc/rand_hex_color() - var/list/colors = list("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f") - var/color="" - for (var/i=0;i<6;i++) - color = color+pick(colors) - return color - - diff --git a/code/modules/vehicles/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm index 607835354aa79..42d5cf7bb92ee 100644 --- a/code/modules/vehicles/mecha/combat/marauder.dm +++ b/code/modules/vehicles/mecha/combat/marauder.dm @@ -1,35 +1,29 @@ -/obj/mecha/combat/marauder +/obj/vehicle/sealed/mecha/combat/marauder desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations." name = "\improper Marauder" icon_state = "marauder" base_icon_state = "marauder" - step_in = 5 + movedelay = 5 max_integrity = 500 deflect_chance = 25 armor = list(MELEE = 50, BULLET = 55, LASER = 40, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 60, FIRE = 100, ACID = 100, STAMINA = 0) max_temperature = 60000 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - infra_luminosity = 3 operation_req_access = list(ACCESS_CENT_SPECOPS) internals_req_access = list(ACCESS_CENT_SPECOPS) wreckage = /obj/structure/mecha_wreckage/marauder - add_req_access = 0 + mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS internal_damage_threshold = 25 force = 45 max_equip = 5 - bumpsmash = 1 + bumpsmash = TRUE -/obj/mecha/combat/marauder/GrantActions(mob/living/user, human_occupant = 0) - ..() - smoke_action.Grant(user, src) - zoom_action.Grant(user, src) - -/obj/mecha/combat/marauder/RemoveActions(mob/living/user, human_occupant = 0) - ..() - smoke_action.Remove(user) - zoom_action.Remove(user) +/obj/vehicle/sealed/mecha/combat/marauder/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_smoke) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_zoom) -/obj/mecha/combat/marauder/loaded/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/marauder/loaded/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) @@ -42,21 +36,21 @@ ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) ME.attach(src) -/obj/mecha/combat/marauder/seraph +/obj/vehicle/sealed/mecha/combat/marauder/seraph desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." name = "\improper Seraph" icon_state = "seraph" base_icon_state = "seraph" operation_req_access = list(ACCESS_CENT_SPECOPS) internals_req_access = list(ACCESS_CENT_SPECOPS) - step_in = 3 + movedelay = 3 max_integrity = 550 wreckage = /obj/structure/mecha_wreckage/seraph internal_damage_threshold = 20 force = 55 max_equip = 6 -/obj/mecha/combat/marauder/seraph/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/marauder/seraph/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) @@ -71,7 +65,7 @@ ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) ME.attach(src) -/obj/mecha/combat/marauder/mauler +/obj/vehicle/sealed/mecha/combat/marauder/mauler desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." name = "\improper Mauler" icon_state = "mauler" @@ -82,12 +76,12 @@ max_equip = 6 destruction_sleep_duration = 20 -/obj/mecha/combat/marauder/mauler/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/marauder/mauler/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) ME.attach(src) -/obj/mecha/combat/marauder/mauler/loaded/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg(src) ME.attach(src) diff --git a/code/modules/vehicles/mecha/combat/phazon.dm b/code/modules/vehicles/mecha/combat/phazon.dm index 5026958886059..d7d3f805ef7f0 100644 --- a/code/modules/vehicles/mecha/combat/phazon.dm +++ b/code/modules/vehicles/mecha/combat/phazon.dm @@ -1,31 +1,22 @@ -/obj/mecha/combat/phazon +/obj/vehicle/sealed/mecha/combat/phazon desc = "This is a Phazon exosuit. The pinnacle of scientific research and pride of Nanotrasen, it uses cutting edge bluespace technology and expensive materials." name = "\improper Phazon" icon_state = "phazon" base_icon_state = "phazon" - step_in = 2 + movedelay = 2 dir_in = 2 //Facing South. step_energy_drain = 3 max_integrity = 200 deflect_chance = 30 armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 0) max_temperature = 25000 - infra_luminosity = 3 wreckage = /obj/structure/mecha_wreckage/phazon - add_req_access = 1 internal_damage_threshold = 25 force = 15 max_equip = 3 phase_state = "phazon-phase" -/obj/mecha/combat/phazon/GrantActions(mob/living/user, human_occupant = 0) - ..() - switch_damtype_action.Grant(user, src) - phasing_action.Grant(user, src) - - -/obj/mecha/combat/phazon/RemoveActions(mob/living/user, human_occupant = 0) - ..() - switch_damtype_action.Remove(user) - phasing_action.Remove(user) - +/obj/vehicle/sealed/mecha/combat/phazon/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_phasing) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_switch_damtype) diff --git a/code/modules/vehicles/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm index 6a1b3ff5da32c..13d595b2cb348 100644 --- a/code/modules/vehicles/mecha/combat/reticence.dm +++ b/code/modules/vehicles/mecha/combat/reticence.dm @@ -1,9 +1,9 @@ -/obj/mecha/combat/reticence +/obj/vehicle/sealed/mecha/combat/reticence desc = "A silent, fast, and nigh-invisible miming exosuit. Popular among mimes and mime assassins." name = "\improper reticence" icon_state = "reticence" base_icon_state = "reticence" - step_in = 2 + movedelay = 2 dir_in = 1 //Facing North. max_integrity = 100 deflect_chance = 3 @@ -12,7 +12,7 @@ wreckage = /obj/structure/mecha_wreckage/reticence operation_req_access = list(ACCESS_THEATRE) internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_THEATRE) - add_req_access = 0 + mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS internal_damage_threshold = 25 max_equip = 2 step_energy_drain = 3 @@ -20,7 +20,7 @@ stepsound = null turnsound = null -/obj/mecha/combat/reticence/loaded/Initialize(mapload) +/obj/vehicle/sealed/mecha/combat/reticence/loaded/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced ME.attach(src) From aea771d12576dcc49763c2d74d866ed051695e8a Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 23:13:26 -0400 Subject: [PATCH 05/41] /mecha_equipment/ first pass --- .../mecha/equipment/mecha_equipment.dm | 106 +++++++----------- 1 file changed, 42 insertions(+), 64 deletions(-) diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm index 0a656d66d2fb4..09303c544e1a9 100644 --- a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm +++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm @@ -8,10 +8,10 @@ force = 5 max_integrity = 300 item_flags = ISWEAPON - var/equip_cooldown = 0 // cooldown after use - var/equip_ready = 1 //whether the equipment is ready for use. (or deactivated/activated for static stuff) + var/equip_cooldown = 0 + var/equip_ready = TRUE //whether the equipment is ready for use. (or deactivated/activated for static stuff) var/energy_drain = 0 - var/obj/mecha/chassis = null + var/obj/vehicle/sealed/mecha/chassis = null ///Bitflag. Determines the range of the equipment. var/range = MECHA_MELEE /// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this. @@ -24,31 +24,31 @@ /obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page() if(chassis) - send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) - send_byjax(chassis.occupant,"exosuit.browser","equipment_menu",chassis.get_equipment_menu(),"dropdowns") - return 1 + send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list()) + send_byjax(chassis.occupants,"exosuit.browser","equipment_menu",chassis.get_equipment_menu(),"dropdowns") + return TRUE return /obj/item/mecha_parts/mecha_equipment/proc/update_equip_info() if(chassis) - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",get_equip_info()) - return 1 + send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",get_equip_info()) + return TRUE return /obj/item/mecha_parts/mecha_equipment/Destroy() if(chassis) - chassis.equipment -= src + LAZYREMOVE(chassis.equipment, src) if(chassis.selected == src) chassis.selected = null - src.update_chassis_page() + update_chassis_page() log_message("[src] is destroyed.", LOG_MECHA) - if(chassis.occupant) - chassis.occupant_message("[src] is destroyed!") - chassis.occupant.playsound_local(chassis, destroy_sound, 50) + if(chassis.occupants) + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] is destroyed!") + playsound(chassis, destroy_sound, 50) chassis = null return ..() -/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) if(!do_after(user, 15, M)) return FALSE if(!can_attach(M)) @@ -73,62 +73,53 @@ return txt -/obj/item/mecha_parts/mecha_equipment/proc/is_ranged()//add a distance restricted equipment. Why not? - return range&MECHA_RANGED - -/obj/item/mecha_parts/mecha_equipment/proc/is_melee() - return range&MECHA_MELEE - - /obj/item/mecha_parts/mecha_equipment/proc/action_checks(atom/target) if(!target) - return 0 + return FALSE if(!chassis) - return 0 + return FALSE if(!equip_ready) - return 0 + return FALSE if(energy_drain && !chassis.has_charge(energy_drain)) - return 0 + return FALSE if(chassis.is_currently_ejecting) - return 0 + return FALSE if(chassis.equipment_disabled) - to_chat(chassis.occupant, "Error -- Equipment control unit is unresponsive.") - return 0 - return 1 - -/obj/item/mecha_parts/mecha_equipment/proc/action(atom/target) - return 0 + to_chat(chassis.occupants, "Error -- Equipment control unit is unresponsive.") + return FALSE + if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT)) + return FALSE + return TRUE -/obj/item/mecha_parts/mecha_equipment/proc/start_cooldown() - set_ready_state(0) +/obj/item/mecha_parts/mecha_equipment/proc/action(mob/source, atom/target, params) + TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_EQUIPMENT, equip_cooldown)//Cooldown is on the MECH so people dont bypass it by switching equipment + send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info()) chassis.use_power(energy_drain) - addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), equip_cooldown) + return TRUE -/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target) +/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target, mob/user) if(!chassis) return var/C = chassis.loc - set_ready_state(0) chassis.use_power(energy_drain) - . = do_after(chassis.occupant, equip_cooldown, target=target) - set_ready_state(1) + . = do_after(user, equip_cooldown, target=target) if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) - return 0 + return FALSE -/obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, delay) +/obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, mob/user, delay) if(!chassis) return var/C = chassis.loc - . = do_after(chassis.occupant, delay, target=target) + . = do_after(user, delay, target=target) if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) - return 0 + return FALSE -/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M) - if(M.equipment.len Date: Wed, 11 Oct 2023 23:28:15 -0400 Subject: [PATCH 06/41] medical_tools --- .../mecha/equipment/tools/medical_tools.dm | 135 +++++++++--------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm index f18e953bef9dd..43ef82d56a402 100644 --- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm @@ -7,12 +7,12 @@ . = ..() START_PROCESSING(SSobj, src) -/obj/item/mecha_parts/mecha_equipment/medical/can_attach(obj/mecha/medical/M) +/obj/item/mecha_parts/mecha_equipment/medical/can_attach(obj/vehicle/sealed/mecha/medical/M) if(..() && istype(M)) return 1 -/obj/item/mecha_parts/mecha_equipment/medical/attach(obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/medical/attach(obj/vehicle/sealed/mecha/M) ..() START_PROCESSING(SSobj, src) @@ -22,8 +22,7 @@ /obj/item/mecha_parts/mecha_equipment/medical/process() if(!chassis) - STOP_PROCESSING(SSobj, src) - return 1 + return PROCESS_KILL /obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/detach() STOP_PROCESSING(SSobj, src) @@ -49,43 +48,46 @@ /obj/item/mecha_parts/mecha_equipment/medical/sleeper/Exit(atom/movable/O) return 0 -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/action(mob/living/carbon/target) +/obj/item/mecha_parts/mecha_equipment/medical/sleeper/action(mob/source, mob/living/carbon/target, params) if(!action_checks(target)) return if(!istype(target)) return if(!patient_insertion_check(target)) return - occupant_message("You start putting [target] into [src]...") + to_chat(source, "[icon2html(src, source)]You start putting [target] into [src]...") chassis.visible_message("[chassis] starts putting [target] into \the [src].") - if(do_after_cooldown(target)) - if(!patient_insertion_check(target)) + if(do_after(source, equip_cooldown, target=target)) + if(!chassis || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) + return + if(!patient_insertion_check(target, source)) return target.forceMove(src) patient = target START_PROCESSING(SSobj, src) update_equip_info() - occupant_message("[target] successfully loaded into [src]. Life support functions engaged.") + to_chat(source, "[icon2html(src, source)][target] successfully loaded into [src]. Life support functions engaged.") chassis.visible_message("[chassis] loads [target] into [src].") log_message("[target] loaded. Life support functions engaged.", LOG_MECHA) + return ..() -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/patient_insertion_check(mob/living/carbon/target) +/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/patient_insertion_check(mob/living/carbon/target, mob/user) if(target.buckled) - occupant_message("[target] will not fit into the sleeper because [target.p_theyre()] buckled to [target.buckled]!") + to_chat(user, "[icon2html(src, user)][target] will not fit into the sleeper because [target.p_theyre()] buckled to [target.buckled]!") return if(target.has_buckled_mobs()) - occupant_message("[target] will not fit into the sleeper because of the creatures attached to it!") + to_chat(user, "[icon2html(src, user)][target] will not fit into the sleeper because of the creatures attached to it!") return if(patient) - occupant_message("The sleeper is already occupied!") + to_chat(user, "[icon2html(src, user)]The sleeper is already occupied!") return - return 1 + return TRUE /obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/go_out() if(!patient) return patient.forceMove(get_turf(src)) - occupant_message("[patient] ejected. Life support functions disabled.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][patient] ejected. Life support functions disabled.") log_message("[patient] ejected. Life support functions disabled.", LOG_MECHA) STOP_PROCESSING(SSobj, src) patient = null @@ -93,7 +95,7 @@ /obj/item/mecha_parts/mecha_equipment/medical/sleeper/detach() if(patient) - occupant_message("Unable to detach [src] - equipment occupied!") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Unable to detach [src] - equipment occupied!") return STOP_PROCESSING(SSobj, src) return ..() @@ -108,17 +110,21 @@ return /obj/item/mecha_parts/mecha_equipment/medical/sleeper/Topic(href,href_list) - ..() + .. = ..() + if(.) + return + if(!(usr in chassis.occupants)) + return if(href_list["eject"]) go_out() if(href_list["view_stats"]) - chassis.occupant << browse(get_patient_stats(),"window=msleeper") - onclose(chassis.occupant, "msleeper") + usr << browse(get_patient_stats(),"window=msleeper") + onclose(usr, "msleeper") return if(href_list["inject"]) var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG = locate() in chassis var/datum/reagent/R = locate(href_list["inject"]) in SG.reagents.reagent_list - if (istype(R)) + if(istype(R)) inject_reagent(R, SG) return @@ -196,19 +202,18 @@ return 0 var/to_inject = min(R.volume, inject_amount) if(to_inject && patient.reagents.get_reagent_amount(R.type) + to_inject <= inject_amount*2) - occupant_message("Injecting [patient] with [to_inject] units of [R.name].") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Injecting [patient] with [to_inject] units of [R.name].") log_message("Injecting [patient] with [to_inject] units of [R.name].", LOG_MECHA) - log_combat(chassis.occupant, patient, "injected", "[name] ([R] - [to_inject] units)") + log_combat(chassis.occupants, patient, "injected", "[name] ([R] - [to_inject] units)") SG.reagents.trans_id_to(patient,R.type,to_inject) update_equip_info() - return /obj/item/mecha_parts/mecha_equipment/medical/sleeper/update_equip_info() if(..()) if(patient) - send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_patient_dam()) - send_byjax(chassis.occupant,"msleeper.browser","reagents",get_patient_reagents()) - send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents()) + send_byjax(chassis.occupants,"msleeper.browser","lossinfo",get_patient_dam()) + send_byjax(chassis.occupants,"msleeper.browser","reagents",get_patient_reagents()) + send_byjax(chassis.occupants,"msleeper.browser","injectwith",get_available_reagents()) return 1 return @@ -219,9 +224,8 @@ if(..()) return if(!chassis.has_charge(energy_drain)) - set_ready_state(1) log_message("Deactivated.", LOG_MECHA) - occupant_message("[src] deactivated - no power.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] deactivated - no power.") STOP_PROCESSING(SSobj, src) return var/mob/living/carbon/M = patient @@ -276,7 +280,7 @@ STOP_PROCESSING(SSobj, src) return ..() -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/mecha/medical/M) +obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M) if(..()) if(istype(M)) return 1 @@ -288,35 +292,36 @@ return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list" return -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/action(atom/movable/target) +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/action(mob/source, atom/movable/target, params) if(!action_checks(target)) return if(istype(target, /obj/item/reagent_containers/syringe)) return load_syringe(target) if(istype(target, /obj/item/storage))//Loads syringes from boxes for(var/obj/item/reagent_containers/syringe/S in target.contents) - load_syringe(S) + load_syringe(S, source) return if(mode) - return analyze_reagents(target) + return analyze_reagents(target, source) if(!syringes.len) - occupant_message("No syringes loaded.") + to_chat(source, "[icon2html(src, source)]No syringes loaded.") return if(reagents.total_volume<=0) - occupant_message("No available reagents to load syringe with.") + to_chat(source, "[icon2html(src, source)]No available reagents to load syringe with.") + return + if(HAS_TRAIT(source, TRAIT_PACIFISM)) + to_chat(source, "The [src] is lethally chambered! You don't want to risk harming anyone...") return var/turf/trg = get_turf(target) var/obj/item/reagent_containers/syringe/mechsyringe = syringes[1] mechsyringe.forceMove(get_turf(chassis)) - reagents.trans_to(mechsyringe, min(mechsyringe.volume, reagents.total_volume), transfered_by = chassis.occupant) + reagents.trans_to(mechsyringe, min(mechsyringe.volume, reagents.total_volume), transfered_by = source) syringes -= mechsyringe mechsyringe.icon = 'icons/obj/chemical.dmi' mechsyringe.icon_state = "syringeproj" playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1) - log_message("Launched [mechsyringe] from [src], targeting [target].", LOG_MECHA) - var/mob/originaloccupant = chassis.occupant - spawn(0) - src = null //if src is deleted, still process the syringe + log_message("Launched [mechsyringe] from [src] by [source], targeting [target].", LOG_MECHA) + spawn(0) //This code is trash and whoever wrote it should feel bad for(var/i=0, i<6, i++) if(!mechsyringe) break @@ -335,9 +340,9 @@ mechsyringe.icon_state = initial(mechsyringe.icon_state) mechsyringe.icon = initial(mechsyringe.icon) mechsyringe.reagents.reaction(M, INJECT) - mechsyringe.reagents.trans_to(M, mechsyringe.reagents.total_volume, transfered_by = originaloccupant) + mechsyringe.reagents.trans_to(M, mechsyringe.reagents.total_volume, transfered_by = source) M.take_bodypart_damage(2) - log_combat(originaloccupant, M, "shot", "syringegun") + log_combat(source, M, "shot", "syringegun") break else if(mechsyringe.loc == trg) mechsyringe.icon_state = initial(mechsyringe.icon_state) @@ -350,7 +355,7 @@ mechsyringe.update_icon() break sleep(1) - return 1 + return ..() /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Topic(href,href_list) @@ -374,12 +379,14 @@ if(processed_reagents.len) message += " added to production" START_PROCESSING(SSobj, src) - occupant_message(message) - occupant_message("Reagent processing started.") + to_chat(usr, message) + to_chat(usr, "[icon2html(src, usr)]Reagent processing started.") log_message("Reagent processing started.", LOG_MECHA) return if (href_list["show_reagents"]) - chassis.occupant << browse(get_reagents_page(),"window=msyringegun") + if(!(usr in chassis.occupants)) + return + usr << browse(get_reagents_page(),"window=msyringegun") if (href_list["purge_reagent"]) var/reagent = href_list["purge_reagent"] if(reagent) @@ -453,43 +460,43 @@ /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/load_syringe(obj/item/reagent_containers/syringe/S) if(syringes.lenUnable to load syringe!") return FALSE - S.reagents.trans_to(src, S.reagents.total_volume, transfered_by = chassis.occupant) + S.reagents.trans_to(src, S.reagents.total_volume, transfered_by = user) S.forceMove(src) syringes += S occupant_message("Syringe loaded.") update_equip_info() return 1 - occupant_message("[src]'s syringe chamber is full.") + to_chat(user, "[icon2html(src, user)][src]'s syringe chamber is full!") return 0 -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/analyze_reagents(atom/A) +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/analyze_reagents(atom/A, mob/user) if(get_dist(src,A) >= 4) - occupant_message("The object is too far away.") - return 0 + to_chat(user, "[icon2html(src, user)]The object is too far away!") + return FALSE if(!A.reagents || ismob(A)) - occupant_message("No reagent info gained from [A].") - return 0 - occupant_message("Analyzing reagents...") + to_chat(user, "[icon2html(src, user)]No reagent info gained from [A].") + return FALSE + to_chat(user, "[icon2html(src, user)]Analyzing reagents...") for(var/datum/reagent/R in A.reagents.reagent_list) if(!(R.chem_flags & CHEMICAL_NOT_SYNTH) && add_known_reagent(R.type,R.name)) - occupant_message("Reagent analyzed, identified as [R.name] and added to database.") - send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) - occupant_message("Analyzis complete.") - return 1 + to_chat(user, "[icon2html(src, user)]Reagent analyzed, identified as [R.name] and added to database.") + send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form()) + to_chat(user, "[icon2html(src, user)]Analysis complete.") + return TRUE /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/add_known_reagent(r_id,r_name) if(!(r_id in known_reagents)) known_reagents += r_id known_reagents[r_id] = r_name - return 1 - return 0 + return TRUE + return FALSE /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/update_equip_info() if(..()) - send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents()) - send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) + send_byjax(chassis.occupants,"msyringegun.browser","reagents",get_current_reagents()) + send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form()) return 1 return @@ -503,7 +510,7 @@ if(..()) return if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(energy_drain)) - occupant_message("Reagent processing stopped.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Reagent processing stopped.") log_message("Reagent processing stopped.", LOG_MECHA) STOP_PROCESSING(SSobj, src) return @@ -538,7 +545,7 @@ return medigun.process() -/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/action(mob/source, atom/movable/target, params) medigun.process_fire(target, loc) From ad9342b6163ff4fef15ea90dd1431ad2e30e20fc Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 23:32:28 -0400 Subject: [PATCH 07/41] mining_tools first pass --- .../mecha/equipment/tools/mining_tools.dm | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index ccbc3991466fb..026c0ee0dc6dc 100644 --- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm @@ -13,6 +13,7 @@ energy_drain = 10 force = 15 harmful = TRUE + range = MECHA_MELEE tool_behaviour = TOOL_DRILL toolspeed = 0.9 var/drill_delay = 7 @@ -23,7 +24,7 @@ . = ..() AddComponent(/datum/component/butchering, 50, 100) -/obj/item/mecha_parts/mecha_equipment/drill/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/drill/action(mob/source, atom/target, params) if(!action_checks(target)) return if(isspaceturf(target)) @@ -36,49 +37,46 @@ "[chassis] starts to drill [target]...", \ "You hear drilling.") - if(do_after_cooldown(target)) - set_ready_state(FALSE) + if(do_after_cooldown(target, source)) log_message("Started drilling [target]", LOG_MECHA) if(isturf(target)) var/turf/T = target - T.drill_act(src) - set_ready_state(TRUE) + T.drill_act(src, source) return - while(do_after_mecha(target, drill_delay)) + while(do_after_mecha(target, source, drill_delay)) if(isliving(target)) - drill_mob(target, chassis.occupant) + drill_mob(target, source) playsound(src,'sound/weapons/drill.ogg',40,1) else if(isobj(target)) var/obj/O = target O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target)) playsound(src,'sound/weapons/drill.ogg',40,1) else - set_ready_state(TRUE) return - set_ready_state(TRUE) + return ..() -/turf/proc/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) +/turf/proc/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user) return -/turf/closed/wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) - if(drill.do_after_mecha(src, 60 / drill.drill_level)) +/turf/closed/wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user) + if(drill.do_after_mecha(src, user, 60 / drill.drill_level)) drill.log_message("Drilled through [src]", LOG_MECHA) dismantle_wall(TRUE, FALSE) -/turf/closed/wall/r_wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) +/turf/closed/wall/r_wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user) if(drill.drill_level >= DRILL_HARDENED) - if(drill.do_after_mecha(src, 120 / drill.drill_level)) + if(drill.do_after_mecha(src, user, 120 / drill.drill_level)) drill.log_message("Drilled through [src]", LOG_MECHA) dismantle_wall(TRUE, FALSE) else - drill.occupant_message("[src] is too durable to drill through.") + to_chat(user, "[icon2html(src, user)][src] is too durable to drill through.") -/turf/closed/mineral/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) +/turf/closed/mineral/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user) var/turf/T = get_turf(drill.chassis) for(var/turf/closed/mineral/M in RANGE_TURFS(1, T)) if(get_dir(drill.chassis,M)&drill.chassis.dir) M.gets_drilled() - drill.log_message("Drilled through [src]", LOG_MECHA) + drill.log_message("[user] drilled through [src]", LOG_MECHA) drill.move_ores() /turf/open/floor/plating/asteroid/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) @@ -91,15 +89,15 @@ /obj/item/mecha_parts/mecha_equipment/drill/proc/move_ores() - if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.equipment && istype(chassis, /obj/mecha/working/ripley)) - var/obj/mecha/working/ripley/R = chassis //we could assume that it's a ripley because it has a clamp, but that's ~unsafe~ and ~bad practice~ + if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.equipment && istype(chassis, /obj/vehicle/sealed/mecha/working/ripley)) + var/obj/vehicle/sealed/mecha/working/ripley/R = chassis //we could assume that it's a ripley because it has a clamp, but that's ~unsafe~ and ~bad practice~ R.collect_ore() -/obj/item/mecha_parts/mecha_equipment/drill/can_attach(obj/mecha/M as obj) +/obj/item/mecha_parts/mecha_equipment/drill/can_attach(obj/vehicle/sealed/mecha/M as obj) if(..()) - if(istype(M, /obj/mecha/working) || istype(M, /obj/mecha/combat)) - return 1 - return 0 + if(istype(M, /obj/vehicle/sealed/mecha/working) || istype(M, /obj/vehicle/sealed/mecha/combat)) + return TRUE + return FALSE /obj/item/mecha_parts/mecha_equipment/drill/attach(obj/mecha/M) ..() @@ -167,16 +165,16 @@ . = ..() START_PROCESSING(SSfastprocess, src) -/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/mecha/M as obj) - return (..() && istype(M, /obj/mecha/working)) +/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/vehicle/sealed/mecha/M as obj) + return (..() && istype(M, /obj/vehicle/sealed/mecha/working)) /obj/item/mecha_parts/mecha_equipment/mining_scanner/process() if(!loc) STOP_PROCESSING(SSfastprocess, src) qdel(src) - if(istype(loc, /obj/mecha/working) && scanning_time <= world.time) - var/obj/mecha/working/mecha = loc - if(!mecha.occupant) + if(istype(loc, /obj/vehicle/sealed/mecha/working) && scanning_time <= world.time) + var/obj/vehicle/sealed/mecha/working/mecha = loc + if(!mecha.occupants) return scanning_time = world.time + equip_cooldown mineral_scan_pulse(get_turf(src)) From 42e6848b6d7ab821578e6999a1dd1c82ce45b88e Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 11 Oct 2023 23:41:43 -0400 Subject: [PATCH 08/41] Mining_tools --- beestation.dme | 2 - .../mecha/equipment/tools/other_tools.dm | 102 ++++++++---------- .../mecha/equipment/tools/weapon_bay.dm | 4 +- 3 files changed, 47 insertions(+), 61 deletions(-) diff --git a/beestation.dme b/beestation.dme index 8f5d4e19d2d10..74ea95cf20d92 100644 --- a/beestation.dme +++ b/beestation.dme @@ -3959,7 +3959,6 @@ #include "code\modules\vehicles\cars\clowncar.dm" #include "code\modules\vehicles\mecha\_mecha.dm" #include "code\modules\vehicles\mecha\mech_bay.dm" -#include "code\modules\vehicles\mecha\mech_fabricator.dm" #include "code\modules\vehicles\mecha\mech_melee_attack.dm" #include "code\modules\vehicles\mecha\mecha_actions.dm" #include "code\modules\vehicles\mecha\mecha_construction_paths.dm" @@ -3981,7 +3980,6 @@ #include "code\modules\vehicles\mecha\equipment\tools\other_tools.dm" #include "code\modules\vehicles\mecha\equipment\tools\weapon_bay.dm" #include "code\modules\vehicles\mecha\equipment\tools\work_tools.dm" -#include "code\modules\vehicles\mecha\equipment\weapons\mecha_ammo.dm" #include "code\modules\vehicles\mecha\equipment\weapons\weapons.dm" #include "code\modules\vehicles\mecha\medical\odysseus.dm" #include "code\modules\vehicles\mecha\working\ripley.dm" diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm index 5343bdd20c9cf..686ccfa4e1b79 100644 --- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm @@ -12,13 +12,13 @@ energy_drain = 1000 range = MECHA_RANGED -/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/teleporter/action(mob/source, atom/target, params) if(!action_checks(target) || is_centcom_level(loc.z)) return var/turf/T = get_turf(target) if(T) do_teleport(chassis, T, 4, channel = TELEPORT_CHANNEL_BLUESPACE) - return 1 + return ..() @@ -33,7 +33,7 @@ range = MECHA_RANGED -/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(mob/source, atom/target, params) if(!action_checks(target) || is_centcom_level(loc.z)) return var/list/theareas = get_areas_in_range(100, chassis) @@ -58,11 +58,11 @@ return var/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, src, 300, 1, /obj/effect/portal/anom) var/turf/T = get_turf(target) - message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Wormhole Generator in [ADMIN_VERBOSEJMP(T)]") - log_game("[key_name(chassis.occupant)] used a Wormhole Generator in [AREACOORD(T)]") + message_admins("[ADMIN_LOOKUPFLW(source)] used a Wormhole Generator in [ADMIN_VERBOSEJMP(T)]") + log_game("[key_name(source)] used a Wormhole Generator in [AREACOORD(T)]") src = null QDEL_LIST_IN(created, rand(150,300)) - return 1 + return ..() /////////////////////////////////////// GRAVITATIONAL CATAPULT /////////////////////////////////////////// @@ -78,36 +78,36 @@ var/mode = 1 //1 - gravsling 2 - gravpush -/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target) +/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(mob/source, atom/movable/target, params) if(!action_checks(target)) return switch(mode) if(1) if(!locked) if(!istype(target) || target.anchored || target.move_resist >= MOVE_FORCE_EXTREMELY_STRONG) - occupant_message("Unable to lock on [target]") + to_chat(source, "[icon2html(src, source)]Unable to lock on [target]!") return if(ismob(target)) var/mob/M = target if(M.mob_negates_gravity()) - occupant_message("Unable to lock on [target]") + to_chat(source, "[icon2html(src, source)]Unable to lock on [target]!") return locked = target - occupant_message("Locked on [target]") - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) + to_chat(source, "[icon2html(src, source)]Locked on [target].") + send_byjax(source,"exosuit.browser","[REF(src)]",src.get_equip_info()) else if(target!=locked) if(locked in view(chassis)) var/turf/targ = get_turf(target) var/turf/orig = get_turf(locked) locked.throw_at(target, 14, 1.5) locked = null - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) - log_game("[key_name(chassis.occupant)] used a Gravitational Catapult to throw [locked] (From [AREACOORD(orig)]) at [target] ([AREACOORD(targ)]).") - return TRUE + send_byjax(source,"exosuit.browser","[REF(src)]",src.get_equip_info()) + log_game("[key_name(source)] used a Gravitational Catapult to throw [locked] (From [AREACOORD(orig)]) at [target] ([AREACOORD(targ)]).") + return ..() else locked = null - occupant_message("Lock on [locked] disengaged.") - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) + to_chat(source, "[icon2html(src, source)]Lock on [locked] disengaged.") + send_byjax(source,"exosuit.browser","[REF(src)]",src.get_equip_info()) if(2) var/list/atoms = list() if(isturf(target)) @@ -125,8 +125,8 @@ var/delay = 2 SSmove_manager.move_away(A, target, delay = delay, timeout = delay * dist, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) var/turf/T = get_turf(target) - log_game("[key_name(chassis.occupant)] used a Gravitational Catapult repulse wave on [AREACOORD(T)]") - return TRUE + log_game("[key_name(source)] used a Gravitational Catapult repulse wave on [AREACOORD(T)]") + return ..() /obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info() @@ -136,7 +136,7 @@ ..() if(href_list["mode"]) mode = text2num(href_list["mode"]) - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) + send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info()) return @@ -157,9 +157,10 @@ selectable = 0 /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/attack_react() - if(action_checks(src)) - start_cooldown() - return 1 + if(energy_drain && !chassis.has_charge(energy_drain)) + return FALSE + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_ARMOR, equip_cooldown) + return TRUE @@ -175,9 +176,10 @@ selectable = 0 /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/projectile_react() - if(action_checks(src)) - start_cooldown() - return 1 + if(energy_drain && !chassis.has_charge(energy_drain)) + return FALSE + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_ARMOR, equip_cooldown) + return TRUE ////////////////////////////////// REPAIR DROID ////////////////////////////////////////////////// @@ -200,7 +202,7 @@ chassis.cut_overlay(droid_overlay) return ..() -/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj) +/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/vehicle/sealed/mecha/M) ..() droid_overlay = new(src.icon, icon_state = "repair_droid") M.add_overlay(droid_overlay) @@ -224,20 +226,17 @@ START_PROCESSING(SSobj, src) droid_overlay = new(src.icon, icon_state = "repair_droid_a") log_message("Activated.", LOG_MECHA) - set_ready_state(0) else STOP_PROCESSING(SSobj, src) droid_overlay = new(src.icon, icon_state = "repair_droid") log_message("Deactivated.", LOG_MECHA) - set_ready_state(1) chassis.add_overlay(droid_overlay) - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) + send_byjax(chassis.occupants,"exosuit.browser", "[REF(src)]", get_equip_info()) /obj/item/mecha_parts/mecha_equipment/repair_droid/process() if(!chassis) STOP_PROCESSING(SSobj, src) - set_ready_state(1) return var/h_boost = health_boost var/repaired = 0 @@ -255,10 +254,8 @@ if(repaired) if(!chassis.use_power(energy_drain)) STOP_PROCESSING(SSobj, src) - set_ready_state(1) else //no repair needed, we turn off STOP_PROCESSING(SSobj, src) - set_ready_state(1) chassis.cut_overlay(droid_overlay) droid_overlay = new(src.icon, icon_state = "repair_droid") chassis.add_overlay(droid_overlay) @@ -310,11 +307,9 @@ if(href_list["toggle_relay"]) if(equip_ready) //inactive START_PROCESSING(SSobj, src) - set_ready_state(0) log_message("Activated.", LOG_MECHA) else STOP_PROCESSING(SSobj, src) - set_ready_state(1) log_message("Deactivated.", LOG_MECHA) /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info() @@ -326,13 +321,11 @@ /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/process() if(!chassis || chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT) STOP_PROCESSING(SSobj, src) - set_ready_state(1) return var/cur_charge = chassis.get_charge() if(isnull(cur_charge) || !chassis.cell) STOP_PROCESSING(SSobj, src) - set_ready_state(1) - occupant_message("No power cell detected.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]No power cell detected.") return if(cur_charge < chassis.cell.maxcharge) var/area/A = get_area(chassis) @@ -384,11 +377,9 @@ ..() if(href_list["toggle"]) if(equip_ready) //inactive - set_ready_state(0) START_PROCESSING(SSobj, src) log_message("Activated.", LOG_MECHA) else - set_ready_state(1) STOP_PROCESSING(SSobj, src) log_message("Deactivated.", LOG_MECHA) @@ -397,26 +388,26 @@ if(output) return "[output] \[[fuel]: [round(fuel.amount*fuel.perunit,0.1)] cm3\] - [equip_ready?"A":"Dea"]ctivate" -/obj/item/mecha_parts/mecha_equipment/generator/action(target) +/obj/item/mecha_parts/mecha_equipment/generator/action(mob/source, atom/movable/target, params) if(chassis) - var/result = load_fuel(target) - if(result) - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) + if(load_fuel(target, source)) + send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info()) + return ..() -/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/sheet/P) +/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(obj/item/stack/sheet/P, mob/user) if(P.type == fuel.type && P.amount > 0) var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0) if(to_load) var/units = min(max(round(to_load / P.perunit),1),P.amount) fuel.amount += units P.use(units) - occupant_message("[units] unit\s of [fuel] successfully loaded.") + to_chat(user, "[icon2html(src, user)][units] unit\s of [fuel] successfully loaded.") return units else - occupant_message("Unit is full.") + to_chat(user, "[icon2html(src, user)]Unit is full.") return 0 else - occupant_message("[fuel] traces in target minimal! [P] cannot be used as fuel.") + to_chat(user, "[icon2html(src, user)][fuel] traces in target minimal! [P] cannot be used as fuel.") return /obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user, params) @@ -425,17 +416,14 @@ /obj/item/mecha_parts/mecha_equipment/generator/process() if(!chassis) STOP_PROCESSING(SSobj, src) - set_ready_state(1) return if(fuel.amount<=0) STOP_PROCESSING(SSobj, src) log_message("Deactivated - no fuel.", LOG_MECHA) - set_ready_state(1) return var/cur_charge = chassis.get_charge() if(isnull(cur_charge)) - set_ready_state(1) - occupant_message("No power cell detected.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]No power cell detected.") log_message("Deactivated.", LOG_MECHA) STOP_PROCESSING(SSobj, src) return @@ -445,7 +433,7 @@ chassis.give_power(power_per_cycle) fuel.amount -= min(use_fuel/fuel.perunit,fuel.amount) update_equip_info() - return 1 + return TRUE /obj/item/mecha_parts/mecha_equipment/generator/nuclear @@ -475,14 +463,14 @@ selectable = FALSE var/effect_type = /obj/effect/particle_effect/sparks -/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) for(var/obj/item/I in M.equipment) if(istype(I, src)) to_chat(user, "[M] already has this thruster package!") return FALSE . = ..() -/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/vehicle/sealed/mecha/M) M.active_thrusters = src //Enable by default . = ..() @@ -513,13 +501,13 @@ if (chassis.active_thrusters == src) return chassis.active_thrusters = src - occupant_message("[src] enabled.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] enabled.") /obj/item/mecha_parts/mecha_equipment/thrusters/proc/disable() if(chassis.active_thrusters != src) return chassis.active_thrusters = null - occupant_message("[src] disabled.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] disabled.") /obj/item/mecha_parts/mecha_equipment/thrusters/get_equip_info() return "[..()] \[Enable|Disable\]" @@ -543,7 +531,7 @@ effect_type = /obj/effect/particle_effect/smoke var/move_cost = 20 //moles per step -/obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) if(!M.internal_tank) to_chat(user, "[M] does not have an internal tank and cannot support this upgrade!") return FALSE diff --git a/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm b/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm index 5fe3e14880f46..469d430328a5d 100644 --- a/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm +++ b/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm @@ -4,8 +4,8 @@ icon = 'icons/mecha/mecha_equipment.dmi' icon_state = "mecha_weapon_bay" -/obj/item/mecha_parts/concealed_weapon_bay/try_attach_part(mob/user, obj/mecha/M) - if(istype(M, /obj/mecha/combat)) +/obj/item/mecha_parts/concealed_weapon_bay/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) + if(istype(M, /obj/vehicle/sealed/mecha/combat)) to_chat(user, "[M] can already hold weapons!") return if(locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents) From 919ae62f1572371e31558f8be767765e3e072d1d Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 00:19:41 -0400 Subject: [PATCH 09/41] work_tools first pass --- .../mecha/equipment/tools/work_tools.dm | 118 +++++++++--------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index 7bd2db855ae9f..147cb4d937e69 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -9,19 +9,20 @@ equip_cooldown = 15 energy_drain = 10 tool_behaviour = TOOL_RETRACTOR + range = MECHA_MELEE toolspeed = 0.8 var/dam_force = 20 - var/obj/mecha/working/ripley/cargo_holder + var/obj/vehicle/sealed/mecha/working/ripley/cargo_holder harmful = TRUE mech_flags = EXOSUIT_MODULE_RIPLEY -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj) +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/vehicle/sealed/mecha/working/ripley/M) if(..()) if(istype(M)) return 1 return 0 -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/attach(obj/mecha/M as obj) +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/attach(obj/vehicle/sealed/mecha/M) ..() cargo_holder = M return @@ -30,43 +31,43 @@ ..() cargo_holder = null -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(mob/source, atom/target, params) if(!action_checks(target)) return if(!cargo_holder) return - if(isobj(target)) - var/obj/O = target + if(ismecha(target)) + var/obj/vehicle/sealed/mecha/M = target if(istype(O, /obj/machinery/door/firedoor)) var/obj/machinery/door/firedoor/D = O - D.try_to_crowbar(src,chassis.occupant) + D.try_to_crowbar(src, source) return if(istype(O, /obj/machinery/door/airlock/)) var/obj/machinery/door/airlock/D = O - D.try_to_crowbar(src,chassis.occupant) + D.try_to_crowbar(src, source) return if(!O.anchored) if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) chassis.visible_message("[chassis] lifts [target] and starts to load it into it's cargo compartment.") O.anchored = TRUE - if(do_after_cooldown(target)) + if(do_after_cooldown(target, source)) cargo_holder.cargo += O O.forceMove(chassis) O.anchored = FALSE - balloon_alert(chassis.occupant, "[target] has been loaded.") + balloon_alert(source, "[target] has been loaded.") log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]", LOG_MECHA) else O.anchored = initial(O.anchored) else - balloon_alert(chassis.occupant, "Not enough room in cargo compartment.") + balloon_alert(source, "Not enough room in cargo compartment.") else - balloon_alert(chassis.occupant, "[target] is firmly secured!") + balloon_alert(source, "[target] is firmly secured!") else if(isliving(target)) var/mob/living/M = target if(M.stat == DEAD) return - if(chassis.occupant.a_intent == INTENT_HARM) + if(source.a_intent == INTENT_HARM) M.take_overall_damage(dam_force) if(!M) return @@ -75,12 +76,12 @@ target.visible_message("[chassis] squeezes [target]!", \ "[chassis] squeezes you!",\ "You hear something crack.") - log_combat(chassis.occupant, M, "attacked", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + log_combat(source, M, "attacked", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])") else step_away(M,chassis) - occupant_message("You push [target] out of the way.") - chassis.visible_message("[chassis] pushes [target] out of the way.") - return 1 + to_chat(source, "[icon2html(src, source)]You push [target] out of the way.") + chassis.visible_message("[chassis] pushes [target] out of the way.") + return ..() @@ -98,7 +99,7 @@ dam_force = 20 real_clamp = TRUE -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/action(mob/source, atom/target, params) if(!action_checks(target)) return if(!cargo_holder) @@ -109,24 +110,24 @@ if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) chassis.visible_message("[chassis] lifts [target] and starts to load it into it's cargo compartment.") O.anchored = TRUE - if(do_after_cooldown(target)) + if(do_after_cooldown(target, source)) cargo_holder.cargo += O O.forceMove(chassis) O.anchored = FALSE - balloon_alert(chassis.occupant, "[target] has been loaded.") + balloon_alert(source, "[target] has been loaded.") log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]", LOG_MECHA) else O.anchored = initial(O.anchored) else - balloon_alert(chassis.occupant, "Not enough room in cargo compartment.") + balloon_alert(source, "Not enough room in cargo compartment.") else - balloon_alert(chassis.occupant, "[target] is firmly secured!") + balloon_alert(source, "[target] is firmly secured!") else if(isliving(target)) var/mob/living/M = target if(M.stat == DEAD) return - if(chassis.occupant.a_intent == INTENT_HARM) + if(source.a_intent == INTENT_HARM) if(real_clamp) M.take_overall_damage(dam_force) if(!M) @@ -135,11 +136,11 @@ M.updatehealth() target.visible_message("[chassis] destroys [target] in an unholy fury!", \ "[chassis] destroys you in an unholy fury!") - log_combat(chassis.occupant, M, "attacked", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + log_combat(source, M, "attacked", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])") else target.visible_message("[chassis] destroys [target] in an unholy fury!", \ "[chassis] destroys you in an unholy fury!") - else if(chassis.occupant.a_intent == INTENT_DISARM) + else if(source.a_intent == INTENT_DISARM) if(real_clamp) var/mob/living/carbon/C = target var/play_sound = FALSE @@ -158,7 +159,7 @@ playsound(src, get_dismember_sound(), 80, TRUE) target.visible_message("[chassis] rips [target]'s arms off!", \ "[chassis] rips your arms off!") - log_combat(chassis.occupant, M, "dismembered of[limbs_gone],", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + log_combat(source, M, "dismembered of[limbs_gone],", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])") else target.visible_message("[chassis] rips [target]'s arms off!", \ "[chassis] rips your arms off!") @@ -166,7 +167,7 @@ step_away(M,chassis) target.visible_message("[chassis] tosses [target] like a piece of paper!", \ "[chassis] tosses you like a piece of paper!") - return 1 + return ..() @@ -185,14 +186,14 @@ create_reagents(1000) reagents.add_reagent(/datum/reagent/water, 1000) -/obj/item/mecha_parts/mecha_equipment/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. +/obj/item/mecha_parts/mecha_equipment/extinguisher/action(mob/source, atom/target, params) //copypasted from extinguisher. TODO: Rewrite from scratch.//Still todo if(!action_checks(target) || get_dist(chassis, target)>3) return if(istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1) var/obj/structure/reagent_dispensers/watertank/WT = target WT.reagents.trans_to(src, 1000) - occupant_message("Extinguisher refilled.") + to_chat(source, "[icon2html(src, source)]Extinguisher refilled.") playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) else if(reagents.total_volume <= 0) @@ -228,7 +229,7 @@ /obj/item/mecha_parts/mecha_equipment/extinguisher/get_equip_info() return "[..()] \[[src.reagents.total_volume]\]" -/obj/item/mecha_parts/mecha_equipment/extinguisher/can_attach(obj/mecha/working/M as obj) +/obj/item/mecha_parts/mecha_equipment/extinguisher/can_attach(obj/vehicle/sealed/mecha/working/M as obj) if(..()) if(istype(M)) return 1 @@ -254,7 +255,7 @@ GLOB.rcd_list -= src return ..() -/obj/item/mecha_parts/mecha_equipment/rcd/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/rcd/action(mob/source, atom/target, params) if(istype(target, /turf/open/space/transit))//>implying these are ever made -Sieve return @@ -268,53 +269,49 @@ if(0) if(iswallturf(target)) var/turf/closed/wall/W = target - occupant_message("Deconstructing [W]...") - if(do_after_cooldown(W)) + to_chat(source, "[icon2html(src, source)]Deconstructing [W]...") + if(do_after_cooldown(W, source)) chassis.spark_system.start() W.ScrapeAway(flags = CHANGETURF_INHERIT_AIR) playsound(W, 'sound/items/deconstruct.ogg', 50, 1) else if(isfloorturf(target)) var/turf/open/floor/F = target - occupant_message("Deconstructing [F]...") - if(do_after_cooldown(target)) + to_chat(source, "[icon2html(src, source)]Deconstructing [F]...") + if(do_after_cooldown(target, source)) chassis.spark_system.start() F.ScrapeAway(flags = CHANGETURF_INHERIT_AIR) playsound(F, 'sound/items/deconstruct.ogg', 50, 1) else if (istype(target, /obj/machinery/door/airlock)) - occupant_message("Deconstructing [target]...") - if(do_after_cooldown(target)) + to_chat(source, "[icon2html(src, source)]Deconstructing [target]...") + if(do_after_cooldown(target, source)) chassis.spark_system.start() qdel(target) playsound(target, 'sound/items/deconstruct.ogg', 50, 1) if(1) if(isspaceturf(target)) var/turf/open/space/S = target - occupant_message("Building Floor...") - if(do_after_cooldown(S)) + to_chat(source, "[icon2html(src, source)]Building Floor...") + if(do_after_cooldown(S, source)) S.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) playsound(S, 'sound/items/deconstruct.ogg', 50, 1) chassis.spark_system.start() else if(isfloorturf(target)) var/turf/open/floor/F = target - occupant_message("Building Wall...") - if(do_after_cooldown(F)) + to_chat(source, "[icon2html(src, source)]Building Wall...") + if(do_after_cooldown(F, source)) F.PlaceOnTop(/turf/closed/wall) playsound(F, 'sound/items/deconstruct.ogg', 50, 1) chassis.spark_system.start() if(2) if(isfloorturf(target)) - occupant_message("Building Airlock...") - if(do_after_cooldown(target)) + to_chat(source, "[icon2html(src, source)]Building Airlock...") + if(do_after_cooldown(target, source)) chassis.spark_system.start() var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) T.autoclose = TRUE playsound(target, 'sound/items/deconstruct.ogg', 50, 1) - playsound(target, 'sound/effects/sparks2.ogg', 50, 1) - - - -/obj/item/mecha_parts/mecha_equipment/rcd/do_after_cooldown(var/atom/target) - . = ..() + playsound(target, 'sound/effects/sparks2.ogg', 50, TRUE) + return ..() /obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list) ..() @@ -322,13 +319,13 @@ mode = text2num(href_list["mode"]) switch(mode) if(0) - occupant_message("Switched RCD to Deconstruct.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Switched RCD to Deconstruct.") energy_drain = initial(energy_drain) if(1) - occupant_message("Switched RCD to Construct.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Switched RCD to Construct.") energy_drain = 2*initial(energy_drain) if(2) - occupant_message("Switched RCD to Construct Airlock.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Switched RCD to Construct Airlock.") energy_drain = 2*initial(energy_drain) return @@ -480,17 +477,17 @@ icon_state = "ripleyupgrade" mech_flags = EXOSUIT_MODULE_RIPLEY -/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/mecha/working/ripley/M) - if(M.type != /obj/mecha/working/ripley) +/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/vehicle/sealed/mecha/working/ripley/M) + if(M.type != /obj/vehicle/sealed/mecha/working/ripley) to_chat(loc, "This conversion kit can only be applied to APLU MK-I models.") return FALSE if(M.cargo.len) to_chat(loc, "[M]'s cargo hold must be empty before this conversion kit can be applied.") return FALSE - if(!M.maint_access) //non-removable upgrade, so lets make sure the pilot or owner has their say. + if(!(M.mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)) //non-removable upgrade, so lets make sure the pilot or owner has their say. to_chat(loc, "[M] must have maintenance protocols active in order to allow this conversion kit.") return FALSE - if(M.occupant) //We're actualy making a new mech and swapping things over, it might get weird if players are involved + if(LAZYLEN(M.occupants)) //We're actualy making a new mech and swapping things over, it might get weird if players are involved to_chat(loc, "[M] must be unoccupied before this conversion kit can be applied.") return FALSE if(!M.cell) //Turns out things break if the cell is missing @@ -498,8 +495,8 @@ return FALSE return TRUE -/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/mecha/M) - var/obj/mecha/working/ripley/mkii/N = new /obj/mecha/working/ripley/mkii(get_turf(M),1) +/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/vehicle/sealed/mecha/M) + var/obj/vehicle/sealed/mecha/working/ripley/mkii/N = new /obj/vehicle/sealed/mecha/working/ripley/mkii(get_turf(M),1) if(!N) return QDEL_NULL(N.cell) @@ -522,10 +519,9 @@ if(istype(E, /obj/item/mecha_parts/concealed_weapon_bay)) //why is the bay not just a variable change who did this E.forceMove(N) for(var/obj/item/mecha_parts/mecha_equipment/E in M.equipment) //Move the equipment over... - E.detach() + E.detach(M) E.attach(N) - M.equipment -= E - N.maint_access = M.maint_access + N.mecha_flags = M.mecha_flags N.strafe = M.strafe N.obj_integrity = M.obj_integrity //This is not a repair tool if (M.name != "\improper APLU MK-I \"Ripley\"") From 530019d5da758dc63ab85ae906a623fdd01259e1 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 00:29:11 -0400 Subject: [PATCH 10/41] weapons first pass --- .../mecha/equipment/weapons/weapons.dm | 126 ++++++++---------- code/modules/vehicles/mecha/mech_bay.dm | 4 +- 2 files changed, 55 insertions(+), 75 deletions(-) diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 4d12261bbb711..969340a5bbf3e 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -6,75 +6,56 @@ var/fire_sound var/projectiles_per_shot = 1 var/variance = 0 - var/randomspread = 0 //use random spread for machineguns, instead of shotgun scatter + var/randomspread = FALSE //use random spread for machineguns, instead of shotgun scatter var/projectile_delay = 0 var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the weapon is fired. var/kickback = TRUE //Will using this weapon in no grav push mecha back. mech_flags = EXOSUIT_MODULE_COMBAT -/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/vehicle/sealed/mecha/M) if(!..()) return FALSE - if(istype(M, /obj/mecha/combat)) + if(istype(M, /obj/vehicle/sealed/mecha/combat)) return TRUE if((locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents) && !(locate(/obj/item/mecha_parts/mecha_equipment/weapon) in M.equipment)) return TRUE return FALSE -/obj/item/mecha_parts/mecha_equipment/weapon/proc/get_shot_amount() - return projectiles_per_shot - -/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target, params) +/obj/item/mecha_parts/mecha_equipment/weapon/action(mob/source, atom/target, params) if(!action_checks(target)) - return 0 - - var/turf/curloc = get_turf(chassis) - var/turf/targloc = get_turf(target) - if (!targloc || !istype(targloc) || !curloc) - return 0 - if (targloc == curloc) - return 0 - - set_ready_state(0) - for(var/i=1 to get_shot_amount()) - var/obj/projectile/A = new projectile(curloc) - A.firer = chassis.occupant - A.original = target - if(!A.suppressed && firing_effect_type) - new firing_effect_type(get_turf(src), chassis.dir) - + return FALSE + var/newtonian_target = turn(chassis.dir,180) + . = ..()//start the cooldown early because of sleeps + for(var/i in 1 to projectiles_per_shot) + if(energy_drain && !chassis.has_charge(energy_drain))//in case we run out of energy mid-burst, such as emp + break var/spread = 0 if(variance) if(randomspread) spread = round((rand() - 0.5) * variance) else spread = round((i / projectiles_per_shot - 0.5) * variance) - A.preparePixelProjectile(target, chassis.occupant, params, spread) + + var/obj/projectile/A = new projectile(get_turf(src)) + A.preparePixelProjectile(target, source, params, spread) A.fire() - playsound(chassis, fire_sound, 50, 1) + if(!A.suppressed && firing_effect_type) + new firing_effect_type(get_turf(src), chassis.dir) + playsound(chassis, fire_sound, 50, TRUE) sleep(max(0, projectile_delay)) - if(kickback) - chassis.newtonian_move(turn(chassis.dir,180)) + if(kickback) + chassis.newtonian_move(newtonian_target) chassis.log_message("Fired from [src.name], targeting [target].", LOG_MECHA) - return 1 - + return ..() //Base energy weapon type /obj/item/mecha_parts/mecha_equipment/weapon/energy name = "general energy weapon" firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/energy -/obj/item/mecha_parts/mecha_equipment/weapon/energy/get_shot_amount() - return min(round(chassis.cell.charge / energy_drain), projectiles_per_shot) - -/obj/item/mecha_parts/mecha_equipment/weapon/energy/start_cooldown() - set_ready_state(0) - chassis.use_power(energy_drain*get_shot_amount()) - addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), equip_cooldown) - /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser equip_cooldown = 8 name = "\improper CH-PS \"Immolator\" laser" @@ -151,12 +132,12 @@ fire_sound = 'sound/weapons/plasma_cutter.ogg' harmful = TRUE -/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/vehicle/sealed/mecha/M) if(..()) //combat mech - return 1 - else if(M.equipment.len < M.max_equip && istype(M)) - return 1 - return 0 + return TRUE + else if(LAZYLEN(M.equipment) < M.max_equip) + return TRUE + return FALSE /obj/item/mecha_parts/mecha_equipment/weapon/energy/taser name = "\improper PBT \"Pacifier\" mounted taser" @@ -178,17 +159,19 @@ kickback = FALSE mech_flags = EXOSUIT_MODULE_HONK -/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/mecha/combat/honker/M) - if(..()) - if(istype(M)) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/vehicle/sealed/mecha/mecha) + . = ..() + if(!.) + return + if(!istype(mecha, /obj/vehicle/sealed/mecha/combat/honker)) + return FALSE + -/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target, params) +/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(mob/source, atom/target, params) if(!action_checks(target)) return playsound(chassis, 'sound/items/airhorn.ogg', 100, 1) - chassis.occupant_message("HONK") + to_chat(source, "[icon2html(src, source)]HONK") for(var/mob/living/carbon/M in ohearers(6, chassis)) if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -222,15 +205,12 @@ var/projectiles var/projectile_energy_cost -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_shot_amount() - return min(projectiles, projectiles_per_shot) - /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action_checks(target) if(!..()) - return 0 + return FALSE if(projectiles <= 0) - return 0 - return 1 + return FALSE + return TRUE /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info() return "[..()] \[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]" @@ -243,7 +223,7 @@ projectiles++ projectiles_to_add-- chassis.use_power(projectile_energy_cost) - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) + send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info()) log_message("Rearmed [src.name].", LOG_MECHA) return 1 @@ -259,11 +239,11 @@ src.rearm() return -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(atom/target) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(mob/source, atom/target, params) if(..()) - projectiles -= get_shot_amount() - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) - return 1 + projectiles -= projectiles_per_shot + send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info()) + return ..() /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine @@ -330,19 +310,19 @@ var/missile_range = 30 var/diags_first = FALSE -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/action(target) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/action(mob/source, atom/target, params) if(!action_checks(target)) return var/obj/O = new projectile(chassis.loc) playsound(chassis, fire_sound, 50, 1) log_message("Launched a [O.name] from [name], targeting [target].", LOG_MECHA) projectiles-- - proj_init(O) - O.throw_at(target, missile_range, missile_speed, chassis.occupant, FALSE, diagonals_first = diags_first) - return 1 + proj_init(O, source) + O.throw_at(target, missile_range, missile_speed, source, FALSE, diagonals_first = diags_first) + return TRUE //used for projectile initilisation (priming flashbang) and additional logging -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/proc/proj_init(var/obj/O) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/proc/proj_init(var/obj/O, mob/user) return @@ -358,10 +338,10 @@ equip_cooldown = 60 var/det_time = 20 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(var/obj/item/grenade/flashbang/F) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(obj/item/grenade/flashbang/F, mob/user) var/turf/T = get_turf(src) - message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] fired a [src] in [ADMIN_VERBOSEJMP(T)]") - log_game("[key_name(chassis.occupant)] fired a [src] in [AREACOORD(T)]") + message_admins("[ADMIN_LOOKUPFLW(user)] fired a [F] in [ADMIN_VERBOSEJMP(T)]") + log_game("[key_name(user)] fired a [F] in [AREACOORD(T)]") addtimer(CALLBACK(F, TYPE_PROC_REF(/obj/item/grenade/flashbang, prime)), det_time) /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze @@ -384,7 +364,7 @@ equip_cooldown = 20 mech_flags = EXOSUIT_MODULE_HONK -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M) if(..()) if(istype(M)) return 1 @@ -402,7 +382,7 @@ equip_cooldown = 10 mech_flags = EXOSUIT_MODULE_HONK -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M) if(..()) if(istype(M)) return 1 @@ -428,7 +408,7 @@ diags_first = TRUE mech_flags = EXOSUIT_MODULE_HONK -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/vehicle/sealed/mecha/combat/honker/M) if(..()) if(istype(M)) return 1 @@ -437,7 +417,7 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(target) . = ..() if(.) - chassis.occupant_message("HONK") + to_chat(usr, "[icon2html(src, usr)]HONK") /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/proj_init(obj/item/punching_glove/PG) if(!istype(PG)) diff --git a/code/modules/vehicles/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm index 2c644a494fe29..570e33894d0d7 100644 --- a/code/modules/vehicles/mecha/mech_bay.dm +++ b/code/modules/vehicles/mecha/mech_bay.dm @@ -20,7 +20,7 @@ icon = 'icons/mecha/mech_bay.dmi' icon_state = "recharge_port" circuit = /obj/item/circuitboard/machine/mech_recharger - var/obj/mecha/recharging_mech + var/obj/vehicle/sealed/mecha/recharging_mech var/obj/machinery/computer/mech_bay_power_console/recharge_console ///Power unit per second to charge by, modified by /RefreshParts() var/recharge_power = 25 @@ -57,7 +57,7 @@ if(machine_stat & NOPOWER || !recharge_console) return if(!recharging_mech) - recharging_mech = locate(/obj/mecha) in recharging_turf + recharging_mech = locate(/obj/vehicle/sealed/mecha) in recharging_turf if(recharging_mech) recharge_console.update_icon() recharge_console.ui_update() From 27d1b25c580292acaf026092cf710230aa90c4bf Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 00:44:18 -0400 Subject: [PATCH 11/41] mecha_actions first pass --- .../vehicles/mecha/mech_melee_attack.dm | 117 +++++++++ code/modules/vehicles/mecha/mecha_actions.dm | 226 ++++++++---------- 2 files changed, 222 insertions(+), 121 deletions(-) diff --git a/code/modules/vehicles/mecha/mech_melee_attack.dm b/code/modules/vehicles/mecha/mech_melee_attack.dm index e69de29bb2d1d..fbbe472a9c259 100644 --- a/code/modules/vehicles/mecha/mech_melee_attack.dm +++ b/code/modules/vehicles/mecha/mech_melee_attack.dm @@ -0,0 +1,117 @@ +///Called when a mech melee attacks an atom +/atom/proc/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker) + return + +/turf/closed/wall/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker) + mecha_attacker.do_attack_animation(src) + switch(mecha_attacker.damtype) + if(BRUTE) + playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) + mecha_attacker.visible_message("[mecha_attacker.name] hits [src]!", \ + "You hit [src]!", null, COMBAT_MESSAGE_RANGE) + if(prob(hardness + mecha_attacker.force) && mecha_attacker.force > 20) + dismantle_wall(1) + playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) + else + add_dent(WALL_DENT_HIT) + if(BURN) + playsound(src, 'sound/items/welder.ogg', 100, TRUE) + if(TOX) + playsound(src, 'sound/effects/spray2.ogg', 100, TRUE) + return FALSE + +/obj/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker) + mecha_attacker.do_attack_animation(src) + var/play_soundeffect = 0 + var/mech_damtype = mecha_attacker.damtype + if(mecha_attacker.selected) + mech_damtype = mecha_attacker.selected.damtype + play_soundeffect = 1 + else + switch(mecha_attacker.damtype) + if(BRUTE) + playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) + if(BURN) + playsound(src, 'sound/items/welder.ogg', 50, TRUE) + if(TOX) + playsound(src, 'sound/effects/spray2.ogg', 50, TRUE) + return 0 + else + return 0 + mecha_attacker.visible_message("[mecha_attacker.name] hits [src]!", "You hit [src]!", null, COMBAT_MESSAGE_RANGE) + return take_damage(mecha_attacker.force * 3, mech_damtype, "melee", play_soundeffect, get_dir(src, mecha_attacker)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs. + +/obj/structure/window/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker) + if(!can_be_reached()) + return + return ..() + +/mob/living/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/user) + if(user.a_intent == INTENT_HARM) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, "You don't want to harm other living beings!") + return + mecha_attacker.do_attack_animation(src) + if(mecha_attacker.damtype == "brute") + step_away(src, mecha_attacker, 15) + switch(mecha_attacker.damtype) + if(BRUTE) + Unconscious(20) + take_overall_damage(rand(mecha_attacker.force/2, mecha_attacker.force)) + playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) + if(BURN) + take_overall_damage(0, rand(mecha_attacker.force * 0.5, mecha_attacker.force)) + playsound(src, 'sound/items/welder.ogg', 50, TRUE) + if(TOX) + mecha_attacker.mech_toxin_damage(src) + else + return + updatehealth() + visible_message("[mecha_attacker.name] hits [src]!", \ + "[mecha_attacker.name] hits you!", "You hear a sickening sound of flesh hitting flesh!", COMBAT_MESSAGE_RANGE, mecha_attacker) + to_chat(mecha_attacker, "You hit [src]!") + log_combat(user, src, "attacked", mecha_attacker, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(mecha_attacker.damtype)])") + else + step_away(src, mecha_attacker) + log_combat(user, src, "pushed", mecha_attacker) + visible_message("[mecha_attacker] pushes [src] out of the way.", \ + "[mecha_attacker] pushes you out of the way.", "You hear aggressive shuffling!", 5, list(mecha_attacker)) + to_chat(mecha_attacker, "You push [src] out of the way.") + +/mob/living/carbon/human/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/user) + if(user.a_intent == INTENT_HARM) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, "You don't want to harm other living beings!") + return + mecha_attacker.do_attack_animation(src) + if(mecha_attacker.damtype == BRUTE) + step_away(src, mecha_attacker, 15) + var/obj/item/bodypart/temp = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD)) + if(temp) + var/update = 0 + var/dmg = rand(mecha_attacker.force * 0.5, mecha_attacker.force) + switch(mecha_attacker.damtype) + if(BRUTE) + if(mecha_attacker.force > 35) // durand and other heavy mechas + Unconscious(20) + else if(mecha_attacker.force > 20 && !IsKnockdown()) // lightweight mechas like gygax + Knockdown(40) + update |= temp.receive_damage(dmg, 0) + playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE) + if(FIRE) + update |= temp.receive_damage(0, dmg) + playsound(src, 'sound/items/welder.ogg', 50, TRUE) + if(TOX) + mecha_attacker.mech_toxin_damage(src) + else + return + if(update) + update_damage_overlays() + updatehealth() + + visible_message("[mecha_attacker.name] hits [src]!", \ + "[mecha_attacker.name] hits you!", "You hear a sickening sound of flesh hitting flesh!", COMBAT_MESSAGE_RANGE, list(mecha_attacker)) + to_chat(mecha_attacker, "You hit [src]!") + log_combat(user, src, "attacked", mecha_attacker, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(mecha_attacker.damtype)])") + else + return ..() diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index 399ff5597f1e2..ff9992c6d36d5 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -1,76 +1,57 @@ -//////////////////////////////////////// Action Buttons /////////////////////////////////////////////// - -/obj/mecha/proc/GrantActions(mob/living/user, human_occupant = 0) - if(human_occupant) - eject_action.Grant(user, src) - if(enclosed) - internals_action.Grant(user, src) - cycle_action.Grant(user, src) - lights_action.Grant(user, src) - stats_action.Grant(user, src) - strafing_action.Grant(user, src) - - -/obj/mecha/proc/RemoveActions(mob/living/user, human_occupant = 0) - if(human_occupant) - eject_action.Remove(user) - internals_action.Remove(user) - cycle_action.Remove(user) - lights_action.Remove(user) - stats_action.Remove(user) - strafing_action.Remove(user) - - -/datum/action/innate/mecha - check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUN | AB_CHECK_CONSCIOUS - icon_icon = 'icons/mob/actions/actions_mecha.dmi' - var/obj/mecha/chassis +//////////////////////MECHA ACTIONS\\\\\\\\\\\\\\\\\\\\\ + +/obj/vehicle/sealed/mecha/generate_action_type() + . = ..() + if(istype(., /datum/action/vehicle/sealed/mecha)) + var/datum/action/vehicle/sealed/mecha/mecha = . + mecha.chassis = src -/datum/action/innate/mecha/Grant(mob/living/L, obj/mecha/M) - if(M) - chassis = M - ..() -/datum/action/innate/mecha/Destroy() +/datum/action/vehicle/sealed/mecha + icon_icon = 'icons/mob/actions/actions_mecha.dmi' + var/obj/vehicle/sealed/mecha/chassis + +/datum/action/vehicle/sealed/mecha/Destroy() chassis = null return ..() -/datum/action/innate/mecha/mech_eject +/datum/action/vehicle/sealed/mecha/mech_eject name = "Eject From Mech" button_icon_state = "mech_eject" -/datum/action/innate/mecha/mech_eject/Activate() +/datum/action/vehicle/sealed/mecha/mech_eject/Trigger() if(!owner) return - if(!chassis || chassis.occupant != owner) + if(!chassis || !(owner in chassis.occupants)) return - chassis.container_resist(chassis.occupant) + chassis.container_resist_act(owner) -/datum/action/innate/mecha/mech_toggle_internals +/datum/action/vehicle/sealed/mecha/mech_toggle_internals name = "Toggle Internal Airtank Usage" button_icon_state = "mech_internals_off" -/datum/action/innate/mecha/mech_toggle_internals/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_toggle_internals/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return chassis.use_internal_tank = !chassis.use_internal_tank button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]" chassis.balloon_alert(owner, "Now taking air from the [chassis.use_internal_tank ? "internal airtank" : "environment"].") - chassis.log_message("Now taking air from the [chassis.use_internal_tank ? "internal airtank" : "environment"].", LOG_MECHA) + chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA) UpdateButtonIcon() -/datum/action/innate/mecha/mech_cycle_equip +/datum/action/vehicle/sealed/mecha/mech_cycle_equip name = "Cycle Equipment" button_icon_state = "mech_cycle_equip_off" -/datum/action/innate/mecha/mech_cycle_equip/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_cycle_equip/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return var/list/available_equipment = list() - for(var/obj/item/mecha_parts/mecha_equipment/M in chassis.equipment) - if(M.selectable) - available_equipment += M + for(var/e in chassis.equipment) + var/obj/item/mecha_parts/mecha_equipment/equipment = e + if(equipment.selectable) + available_equipment += equipment if(available_equipment.len == 0) chassis.balloon_alert(owner, "No equipment available.") @@ -78,94 +59,100 @@ if(!chassis.selected) chassis.selected = available_equipment[1] chassis.balloon_alert(owner, "[chassis.selected] selected.") - send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) + send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list()) button_icon_state = "mech_cycle_equip_on" UpdateButtonIcon() return var/number = 0 - for(var/A in available_equipment) + for(var/equipment in available_equipment) number++ - if(A == chassis.selected) - if(available_equipment.len == number) - chassis.selected = null - chassis.balloon_alert(owner, "Switched to no equipment.") - button_icon_state = "mech_cycle_equip_off" - else - chassis.selected = available_equipment[number+1] - chassis.balloon_alert(owner, "Switched to [chassis.selected].") - button_icon_state = "mech_cycle_equip_on" - send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) - UpdateButtonIcon() - return - - -/datum/action/innate/mecha/mech_toggle_lights + if(equipment != chassis.selected) + continue + if(available_equipment.len == number) + chassis.selected = null + chassis.balloon_alert(owner, "Switched to no equipment.") + button_icon_state = "mech_cycle_equip_off" + else + chassis.selected = available_equipment[number+1] + chassis.balloon_alert(owner, "Switched to [chassis.selected].") + button_icon_state = "mech_cycle_equip_on" + send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list()) + UpdateButtonIcon() + return + + +/datum/action/vehicle/sealed/mecha/mech_toggle_lights name = "Toggle Lights" button_icon_state = "mech_lights_off" -/datum/action/innate/mecha/mech_toggle_lights/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_toggle_lights/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return - if(!chassis.lights_power) + if(!(chassis.mecha_flags & HAS_LIGHTS)) + to_chat(owner, "This mechs lights are destroyed!") return - chassis.lights = !chassis.lights - if(chassis.lights) + chassis.mecha_flags ^= LIGHTS_ON + if(chassis.mecha_flags & LIGHTS_ON) button_icon_state = "mech_lights_on" else button_icon_state = "mech_lights_off" - chassis.set_light_on(chassis.lights) - chassis.balloon_alert(owner, "Toggled lights [chassis.lights ? "on" : "off"].") - chassis.log_message("Toggled lights [chassis.lights ? "on" : "off"].", LOG_MECHA) + chassis.set_light_on(chassis.mecha_flags & LIGHTS_ON) + chassis.balloon_alert(owner, "Toggled lights [(chassis.mecha_flags & LIGHTS_ON) ? "on" : "off"].") + chassis.log_message("Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].", LOG_MECHA) UpdateButtonIcon() -/datum/action/innate/mecha/mech_view_stats +/datum/action/vehicle/sealed/mecha/mech_view_stats name = "View Stats" button_icon_state = "mech_view_stats" -/datum/action/innate/mecha/mech_view_stats/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_view_stats/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return - chassis.occupant << browse(chassis.get_stats_html(), "window=exosuit") + var/datum/browser/popup = new(owner , "exosuit") + popup.set_content(chassis.get_stats_html(owner)) + popup.open() -/datum/action/innate/mecha/strafe +/datum/action/vehicle/sealed/mecha/strafe name = "Toggle Strafing. Disabled when Alt is held." button_icon_state = "strafe" -/datum/action/innate/mecha/strafe/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/strafe/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return chassis.toggle_strafe() -/obj/mecha/AltClick(mob/living/user) - if((user == occupant) && user.canUseTopic(src)) +/obj/vehicle/sealed/mecha/AltClick(mob/living/user) + if((user in occupants) && user.canUseTopic(src)) toggle_strafe() -/obj/mecha/proc/toggle_strafe() +/obj/vehicle/sealed/mecha/proc/toggle_strafe() strafe = !strafe - occupant_message("Toggled strafing mode [strafe?"on":"off"].") + to_chat(occupants, "[icon2html(src, occupants)]Toggled strafing mode [strafe?"on":"off"].") log_message("Toggled strafing mode [strafe?"on":"off"].", LOG_MECHA) - strafing_action.UpdateButtonIcon() + + for(var/occupant in occupants) + var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/strafe) + action?.UpdateButtonIcon() //////////////////////////////////////// Specific Ability Actions /////////////////////////////////////////////// //Need to be granted by the mech type, Not default abilities. -/datum/action/innate/mecha/mech_defense_mode +/datum/action/vehicle/sealed/mecha/mech_defense_mode name = "Toggle an energy shield that blocks all attacks from the faced direction at a heavy power cost." button_icon_state = "mech_defense_mode_off" - var/image/def_overlay -/datum/action/innate/mecha/mech_defense_mode/Activate(forced_state = FALSE) - SEND_SIGNAL(chassis, COMSIG_MECHA_ACTION_ACTIVATE, args) ///Signal sent to the mech, to be handed to the shield. See durand.dm for more details +/datum/action/vehicle/sealed/mecha/mech_defense_mode/Trigger(forced_state = FALSE) + SEND_SIGNAL(chassis, COMSIG_MECHA_ACTION_TRIGGER, owner, args) //Signal sent to the mech, to be handed to the shield. See durand.dm for more details -/datum/action/innate/mecha/mech_overload_mode +/datum/action/vehicle/sealed/mecha/mech_overload_mode name = "Toggle leg actuators overload" button_icon_state = "mech_overload_off" -/datum/action/innate/mecha/mech_overload_mode/Activate(forced_state = null) - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_overload_mode/Trigger(forced_state = null) + if(!owner || !chassis || !(owner in chassis.occupants)) return if(!isnull(forced_state)) chassis.leg_overload_mode = forced_state @@ -173,38 +160,35 @@ chassis.leg_overload_mode = !chassis.leg_overload_mode button_icon_state = "mech_overload_[chassis.leg_overload_mode ? "on" : "off"]" chassis.log_message("Toggled leg actuators overload.", LOG_MECHA) - if(chassis.leg_overload_mode) - chassis.leg_overload_mode = 1 - chassis.step_in = min(1, round(chassis.step_in/2)) + if(!chassis.leg_overload_mode) + chassis.movedelay = min(1, round(chassis.movedelay * 0.5)) chassis.step_energy_drain = max(chassis.overload_step_energy_drain_min,chassis.step_energy_drain*chassis.leg_overload_coeff) chassis.balloon_alert(owner,"Toggled leg actuators overload.") else - chassis.leg_overload_mode = 0 - chassis.step_in = initial(chassis.step_in) + chassis.movedelay = initial(chassis.movedelay) chassis.step_energy_drain = chassis.normal_step_energy_drain chassis.balloon_alert(owner, "Disabled leg actuators overload.") UpdateButtonIcon() -/datum/action/innate/mecha/mech_smoke +/datum/action/vehicle/sealed/mecha/mech_smoke name = "Smoke" button_icon_state = "mech_smoke" -/datum/action/innate/mecha/mech_smoke/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_smoke/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return - if(chassis.smoke_ready && chassis.smoke>0) + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_SMOKE) && chassis.smoke_charges>0) chassis.smoke_system.start() - chassis.smoke-- - chassis.smoke_ready = FALSE - addtimer(VARSET_CALLBACK(chassis, smoke_ready, TRUE), chassis.smoke_cooldown) + chassis.smoke_charges-- + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_SMOKE, chassis.smoke_cooldown) -/datum/action/innate/mecha/mech_zoom +/datum/action/vehicle/sealed/mecha/mech_zoom name = "Zoom" button_icon_state = "mech_zoom_off" -/datum/action/innate/mecha/mech_zoom/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_zoom/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return if(owner.client) chassis.zoom_mode = !chassis.zoom_mode @@ -218,35 +202,35 @@ owner.client.view_size.resetToDefault() //Let's not let this stack shall we? UpdateButtonIcon() -/datum/action/innate/mecha/mech_switch_damtype +/datum/action/vehicle/sealed/mecha/mech_switch_damtype name = "Reconfigure arm microtool arrays" button_icon_state = "mech_damtype_brute" -/datum/action/innate/mecha/mech_switch_damtype/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_switch_damtype/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return var/new_damtype switch(chassis.damtype) - if(TOX) - new_damtype = BRUTE - chassis.balloon_alert(owner, "Your exosuit's hands form into fists.") - if(BRUTE) - new_damtype = BURN - chassis.balloon_alert(owner, "A torch tip extends from your exosuit's hand, glowing red.") - if(BURN) - new_damtype = TOX - chassis.balloon_alert(owner, "A bone-chillingly thick plasteel needle protracts from the exosuit's palm.") + if("tox") + new_damtype = "brute" + to_chat(owner, "[icon2html(chassis, owner)]Your exosuit's hands form into fists.") + if("brute") + new_damtype = "fire" + to_chat(owner, "[icon2html(chassis, owner)]A torch tip extends from your exosuit's hand, glowing red.") + if("fire") + new_damtype = "tox" + to_chat(owner, "[icon2html(chassis, owner)]A bone-chillingly thick plasteel needle protracts from the exosuit's palm.") chassis.damtype = new_damtype button_icon_state = "mech_damtype_[new_damtype]" - playsound(src, 'sound/mecha/mechmove01.ogg', 50, TRUE) + playsound(chassis, 'sound/mecha/mechmove01.ogg', 50, TRUE) UpdateButtonIcon() -/datum/action/innate/mecha/mech_toggle_phasing +/datum/action/vehicle/sealed/mecha/mech_toggle_phasing name = "Toggle Phasing" button_icon_state = "mech_phasing_off" -/datum/action/innate/mecha/mech_toggle_phasing/Activate() - if(!owner || !chassis || chassis.occupant != owner) +/datum/action/vehicle/sealed/mecha/mech_toggle_phasing/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) return chassis.phasing = !chassis.phasing button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]" From c78b38bcf8f56878a36408768f0c44575f448453 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 00:51:10 -0400 Subject: [PATCH 12/41] mecha_control & mecha_construct --- .../mecha/mecha_construction_paths.dm | 16 +++++----- .../vehicles/mecha/mecha_control_console.dm | 30 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm index bf67acd2a3917..e9e0dfdb0721d 100644 --- a/code/modules/vehicles/mecha/mecha_construction_paths.dm +++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm @@ -28,7 +28,7 @@ if(!result) return // Remove default mech power cell, as we replace it with a new one. - var/obj/mecha/M = new result(drop_location()) + var/obj/vehicle/sealed/mecha/M = new result(drop_location()) QDEL_NULL(M.cell) QDEL_NULL(M.scanmod) QDEL_NULL(M.capacitor) @@ -264,7 +264,7 @@ ) /datum/component/construction/mecha/ripley - result = /obj/mecha/working/ripley + result = /obj/vehicle/sealed/mecha/working/ripley base_icon = "ripley" circuit_control = /obj/item/circuitboard/mecha/ripley/main @@ -407,7 +407,7 @@ ) /datum/component/construction/mecha/gygax - result = /obj/mecha/combat/gygax + result = /obj/vehicle/sealed/mecha/combat/gygax base_icon = "gygax" circuit_control = /obj/item/circuitboard/mecha/gygax/main @@ -549,7 +549,7 @@ ) /datum/component/construction/mecha/firefighter - result = /obj/mecha/working/ripley/firefighter + result = /obj/vehicle/sealed/mecha/working/ripley/firefighter base_icon = "fireripley" circuit_control = /obj/item/circuitboard/mecha/ripley/main @@ -706,7 +706,7 @@ ) /datum/component/construction/mecha/honker - result = /obj/mecha/combat/honker + result = /obj/vehicle/sealed/mecha/combat/honker steps = list( list( "key" = TOOL_BIKEHORN @@ -820,7 +820,7 @@ ) /datum/component/construction/mecha/durand - result = /obj/mecha/combat/durand + result = /obj/vehicle/sealed/mecha/combat/durand base_icon = "durand" circuit_control = /obj/item/circuitboard/mecha/durand/main @@ -962,7 +962,7 @@ ) /datum/component/construction/mecha/phazon - result = /obj/mecha/combat/phazon + result = /obj/vehicle/sealed/mecha/combat/phazon base_icon = "phazon" circuit_control = /obj/item/circuitboard/mecha/phazon/main @@ -1207,7 +1207,7 @@ ) /datum/component/construction/mecha/odysseus - result = /obj/mecha/medical/odysseus + result = /obj/vehicle/sealed/mecha/medical/odysseus base_icon = "odysseus" circuit_control = /obj/item/circuitboard/mecha/odysseus/main diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm index 3c6883377c157..eab0695dbdea4 100644 --- a/code/modules/vehicles/mecha/mecha_control_console.dm +++ b/code/modules/vehicles/mecha/mecha_control_console.dm @@ -23,27 +23,27 @@ var/list/data = list() var/list/trackerlist = list() - for(var/obj/mecha/MC in GLOB.mechas_list) + for(var/obj/vehicle/sealed/mecha/MC in GLOB.mechas_list) trackerlist += MC.trackers data["mechs"] = list() for(var/obj/item/mecha_parts/mecha_tracking/MT in trackerlist) if(!MT.chassis) continue - var/obj/mecha/M = MT.chassis + var/obj/vehicle/sealed/mecha/M = MT.chassis var/list/mech_data = list( name = M.name, integrity = round((M.obj_integrity / M.max_integrity) * 100), charge = M.cell ? round(M.cell.percent()) : null, airtank = M.internal_tank ? M.return_pressure() : null, - pilot = M.occupant, + pilot = M.return_drivers(), location = get_area_name(M, TRUE), active_equipment = M.selected, emp_recharging = MT.recharging, tracker_ref = REF(MT) ) - if(istype(M, /obj/mecha/working/ripley)) - var/obj/mecha/working/ripley/RM = M + if(istype(M, /obj/vehicle/sealed/mecha/working/ripley)) + var/obj/vehicle/sealed/mecha/working/ripley/RM = M mech_data += list( cargo_space = round((RM.cargo.len / RM.cargo_capacity) * 100) ) @@ -62,20 +62,20 @@ if(!istype(MT)) return var/message = stripped_input(usr, "Input message", "Transmit message") - var/obj/mecha/M = MT.chassis + var/obj/vehicle/sealed/mecha/M = MT.chassis if(trim(message) && M) - M.occupant_message(message) + to_chat(M.occupants, message) to_chat(usr, "Message sent.") . = TRUE if("shock") var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"]) if(!istype(MT)) return - var/obj/mecha/M = MT.chassis + var/obj/vehicle/sealed/mecha/M = MT.chassis if(M) MT.shock() - log_game("[key_name(usr)] has activated remote EMP on exosuit [M], located at [loc_name(M)], which is currently [M.occupant? "being piloted by [key_name(M.occupant)]." : "without a pilot."] ") - message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [M.occupant ? "being piloted by [key_name_admin(M.occupant)][ADMIN_FLW(M.occupant)]." : "without a pilot."] ") + log_game("[key_name(usr)] has activated remote EMP on exosuit [M], located at [loc_name(M)], which [M.occupants ? "has the occupants [M.occupants]." : "without a pilot."] ") + message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [M.occupants ? "occupied by [M.occupants][ADMIN_FLW(M)]." : "without a pilot."] ") . = TRUE /obj/item/mecha_parts/mecha_tracking @@ -89,7 +89,7 @@ /// Cooldown variable for EMP pulsing var/recharging = FALSE /// The Mecha that this tracking beacon is attached to - var/obj/mecha/chassis + var/obj/vehicle/sealed/mecha/chassis /** * Returns a html formatted string describing attached mech status @@ -103,11 +103,11 @@ Integrity: [round((chassis.obj_integrity/chassis.max_integrity * 100), 0.01)]%
Cell Charge: [isnull(cell_charge) ? "Not Found":"[chassis.cell.percent()]%"]
Airtank: [chassis.internal_tank ? "[round(chassis.return_pressure(), 0.01)]" : "Not Equipped"] kPa
- Pilot: [chassis.occupant || "None"]
+ Pilot: [chassis.return_drivers() || "None"]
Location: [get_area_name(chassis, TRUE) || "Unknown"]
Active Equipment: [chassis.selected || "None"]"} - if(istype(chassis, /obj/mecha/working/ripley)) - var/obj/mecha/working/ripley/RM = chassis + if(istype(chassis, /obj/vehicle/sealed/mecha/working/ripley)) + var/obj/vehicle/sealed/mecha/working/ripley/RM = chassis answer += "
Used Cargo Space: [round((RM.cargo.len / RM.cargo_capacity * 100), 0.01)]%" return answer @@ -124,7 +124,7 @@ chassis = null return ..() -/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/mecha/M) +/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) if(!do_after(user, 15, M)) return if(!..()) From 15ef630037972e9f87874568579d53c47b8ab0e3 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 00:57:30 -0400 Subject: [PATCH 13/41] mecha_defense pass 1 --- code/modules/vehicles/mecha/mecha_defense.dm | 97 +++++++++++--------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index 944970bcf6e9a..fa271e7360f37 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -1,4 +1,4 @@ -/obj/mecha/proc/get_armour_facing(relative_dir) +/obj/vehicle/sealed/mecha/proc/get_armour_facing(relative_dir) switch(abs(relative_dir)) if(180) // BACKSTAB! return facing_modifiers[MECHA_BACK_ARMOUR] @@ -6,7 +6,7 @@ return facing_modifiers[MECHA_FRONT_ARMOUR] return facing_modifiers[MECHA_SIDE_ARMOUR] //always return non-0 -/obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) +/obj/vehicle/sealed/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) . = ..() if(. && obj_integrity > 0) spark_system.start() @@ -18,10 +18,10 @@ else check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT)) if(. >= 5 || prob(33)) - occupant_message("Taking damage!") + to_chat(occupants, "[icon2html(src, occupants)]Taking damage!") log_message("Took [damage_amount] points of damage. Damage type: [damage_type].", LOG_MECHA) -/obj/mecha/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) +/obj/vehicle/sealed/mecha/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) . = ..() if(!damage_amount) return 0 @@ -52,7 +52,7 @@ . *= booster_damage_modifier -/obj/mecha/attack_hand(mob/living/user) +/obj/vehicle/sealed/mecha/attack_hand(mob/living/user) . = ..() if(.) return @@ -62,11 +62,11 @@ user.visible_message("[user] hits [name]. Nothing happens.", null, null, COMBAT_MESSAGE_RANGE) log_message("Attack by hand/paw. Attacker - [user].", LOG_MECHA, color="red") -/obj/mecha/attack_paw(mob/user as mob) +/obj/vehicle/sealed/mecha/attack_paw(mob/user as mob) return attack_hand(user) -/obj/mecha/attack_alien(mob/living/user) +/obj/vehicle/sealed/mecha/attack_alien(mob/living/user) log_message("Attack by alien. Attacker - [user].", LOG_MECHA, color="red") playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) attack_generic(user, 15, BRUTE, MELEE, 0) @@ -90,42 +90,44 @@ return 1 -/obj/mecha/hulk_damage() +/obj/vehicle/sealed/mecha/hulk_damage() return 15 -/obj/mecha/attack_hulk(mob/living/carbon/human/user) +/obj/vehicle/sealed/mecha/attack_hulk(mob/living/carbon/human/user) . = ..() if(.) log_message("Attack by hulk. Attacker - [user].", LOG_MECHA, color="red") log_combat(user, src, "punched", "hulk powers") -/obj/mecha/blob_act(obj/structure/blob/B) +/obj/vehicle/sealed/mecha/blob_act(obj/structure/blob/B) log_message("Attack by blob. Attacker - [B].", LOG_MECHA, color="red") take_damage(30, BRUTE, MELEE, 0, get_dir(src, B)) -/obj/mecha/attack_tk() +/obj/vehicle/sealed/mecha/attack_tk() return -/obj/mecha/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) //wrapper +/obj/vehicle/sealed/mecha/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) //wrapper log_message("Hit by [AM].", LOG_MECHA, color="red") . = ..() -/obj/mecha/bullet_act(obj/projectile/Proj) //wrapper - if (!enclosed && occupant && !silicon_pilot && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs - occupant.bullet_act(Proj) //If the sides are open, the occupant can be hit +/obj/vehicle/sealed/mecha/bullet_act(obj/projectile/Proj) //wrapper + if(!enclosed && LAZYLEN(occupants) && !(mecha_flags & SILICON_PILOT) && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs + for(var/m in occupants) + var/mob/living/hitmob = m + hitmob.bullet_act(Proj) //If the sides are open, the occupant can be hit return BULLET_ACT_HIT log_message("Hit by projectile. Type: [Proj.name]([Proj.armor_flag]).", LOG_MECHA, color="red") . = ..() -/obj/mecha/ex_act(severity, target) +/obj/vehicle/sealed/mecha/ex_act(severity, target) log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red") if(prob(deflect_chance)) severity++ log_message("Armor saved, changing severity to [severity]", LOG_MECHA) . = ..() -/obj/mecha/contents_explosion(severity, target) +/obj/vehicle/sealed/mecha/contents_explosion(severity, target) severity++ for(var/X in equipment) var/obj/item/mecha_parts/mecha_equipment/ME = X @@ -145,16 +147,17 @@ SSexplosions.med_mov_atom += MT if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += MT - if(occupant) + for(var/Z in occupants) + var/mob/living/occupant = Z occupant.ex_act(severity,target) -/obj/mecha/handle_atom_del(atom/A) - if(A == occupant) - occupant = null +/obj/vehicle/sealed/mecha/handle_atom_del(atom/A) + if(A in occupants) + LAZYREMOVE(occupants, A) icon_state = initial(icon_state)+"-open" setDir(dir_in) -/obj/mecha/emp_act(severity) +/obj/vehicle/sealed/mecha/emp_act(severity) . = ..() if (. & EMP_PROTECT_SELF) return @@ -163,20 +166,22 @@ take_damage(30 / severity, BURN, ENERGY, 1) log_message("EMP detected", LOG_MECHA, color="red") - if(istype(src, /obj/mecha/combat)) + if(istype(src, /obj/vehicle/sealed/mecha/combat)) mouse_pointer = 'icons/mecha/mecha_mouse-disable.dmi' - occupant?.update_mouse_pointer() - if(!equipment_disabled && occupant) //prevent spamming this message with back-to-back EMPs - to_chat(occupant, "Error -- Connection to equipment control unit has been lost.
") + for(var/occus in occupants) + var/mob/living/occupant = occus + occupant.update_mouse_pointer() + if(!equipment_disabled && occupants) //prevent spamming this message with back-to-back EMPs + to_chat(occupants, "Error -- Connection to equipment control unit has been lost.") addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/mecha, restore_equipment)), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) equipment_disabled = 1 -/obj/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) +/obj/vehicle/sealed/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature>max_temperature) log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red") take_damage(5, BURN, 0, 1) -/obj/mecha/attackby(obj/item/W as obj, mob/user as mob, params) +/obj/vehicle/sealed/mecha/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/mmi)) var/obj/item/mmi/M = W @@ -191,7 +196,7 @@ return if(W.GetID()) - if(add_req_access || maint_access) + if((mecha_flags & ADDING_ACCESS_POSSIBLE) || (mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)) if(internals_access_allowed(user)) output_maintenance_dialog(W.GetID(), user) return @@ -259,7 +264,7 @@ log_message("Attacked by [W]. Attacker - [user]", LOG_MECHA) return ..() -/obj/mecha/wrench_act(mob/living/user, obj/item/I) +/obj/vehicle/sealed/mecha/wrench_act(mob/living/user, obj/item/I) ..() . = TRUE if(construction_state == MECHA_SECURE_BOLTS) @@ -270,7 +275,7 @@ construction_state = MECHA_SECURE_BOLTS to_chat(user, "You tighten the securing bolts.") -/obj/mecha/crowbar_act(mob/living/user, obj/item/I) +/obj/vehicle/sealed/mecha/crowbar_act(mob/living/user, obj/item/I) ..() . = TRUE if(construction_state == MECHA_LOOSE_BOLTS) @@ -281,7 +286,7 @@ construction_state = MECHA_LOOSE_BOLTS to_chat(user, "You close the hatch to the power unit.") -/obj/mecha/screwdriver_act(mob/living/user, obj/item/I) +/obj/vehicle/sealed/mecha/screwdriver_act(mob/living/user, obj/item/I) ..() . = TRUE if(internal_damage & MECHA_INT_TEMP_CONTROL) @@ -289,7 +294,7 @@ to_chat(user, "You repair the damaged temperature controller.") return -/obj/mecha/welder_act(mob/living/user, obj/item/W) +/obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W) . = ..() if(user.a_intent == INTENT_HARM) return @@ -310,7 +315,7 @@ return to_chat(user, "The [name] is at full integrity!") -/obj/mecha/proc/mech_toxin_damage(mob/living/target) +/obj/vehicle/sealed/mecha/proc/mech_toxin_damage(mob/living/target) playsound(src, 'sound/effects/spray2.ogg', 50, 1) if(target.reagents) if(target.reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + force < force*2) @@ -319,15 +324,15 @@ target.reagents.add_reagent(/datum/reagent/toxin, force/2.5) -/obj/mecha/mech_melee_attack(obj/mecha/M) +/obj/vehicle/sealed/mecha/mech_melee_attack(obj/vehicle/sealed/mecha/M, mob/user) if(!has_charge(melee_energy_drain)) - return 0 + return NONE use_power(melee_energy_drain) if(M.damtype == BRUTE || M.damtype == BURN) - log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + log_combat(user, src, "attacked", M, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") . = ..() -/obj/mecha/proc/full_repair(charge_cell) +/obj/vehicle/sealed/mecha/proc/full_repair(charge_cell) obj_integrity = max_integrity if(cell && charge_cell) cell.charge = cell.maxcharge @@ -342,10 +347,10 @@ if(internal_damage & MECHA_INT_CONTROL_LOST) clearInternalDamage(MECHA_INT_CONTROL_LOST) -/obj/mecha/narsie_act() +/obj/vehicle/sealed/mecha/narsie_act() emp_act(EMP_HEAVY) -/obj/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) +/obj/vehicle/sealed/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) if(!no_effect) if(selected) used_item = selected @@ -357,12 +362,16 @@ visual_effect_icon = ATTACK_EFFECT_MECHTOXIN ..() -/obj/mecha/obj_destruction() +/obj/vehicle/sealed/mecha/obj_destruction() if(wreckage) var/mob/living/silicon/ai/AI - if(isAI(occupant)) - AI = occupant - occupant = null + for(var/crew in occupants) + if(isAI(crew)) + if(AI) + var/mob/living/silicon/ai/unlucky_ais = crew + unlucky_ais.gib() + continue + AI = crew var/obj/structure/mecha_wreckage/WR = new wreckage(loc, AI) for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) if(E.salvageable && prob(30)) From 159b30dc353fb50f4ed12c80c901578be8ce9152 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 01:04:29 -0400 Subject: [PATCH 14/41] mecha_topic --- code/modules/vehicles/mecha/mecha_parts.dm | 6 +- code/modules/vehicles/mecha/mecha_topic.dm | 99 +++++++++++----------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/code/modules/vehicles/mecha/mecha_parts.dm b/code/modules/vehicles/mecha/mecha_parts.dm index 215790b4fab50..55194dd2b23e5 100644 --- a/code/modules/vehicles/mecha/mecha_parts.dm +++ b/code/modules/vehicles/mecha/mecha_parts.dm @@ -10,20 +10,20 @@ flags_1 = CONDUCT_1 block_upgrade_walk = 1 -/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/mecha/M) //For attaching parts to a finished mech +/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) //For attaching parts to a finished mech if(!user.transferItemToLoc(src, M)) to_chat(user, "\The [src] is stuck to your hand, you cannot put it in \the [M]!") return FALSE user.visible_message("[user] attaches [src] to [M].", "You attach [src] to [M].") return TRUE -/obj/item/mecha_parts/part/try_attach_part(mob/user, obj/mecha/M) +/obj/item/mecha_parts/part/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) return /obj/item/mecha_parts/chassis name = "Mecha Chassis" icon_state = "backbone" - interaction_flags_item = NONE //Don't pick us up!! + interaction_flags_item = NONE //Don't pick us up!! var/construct_type /obj/item/mecha_parts/chassis/Initialize(mapload) diff --git a/code/modules/vehicles/mecha/mecha_topic.dm b/code/modules/vehicles/mecha/mecha_topic.dm index 48b66371241c7..789cb783953e7 100644 --- a/code/modules/vehicles/mecha/mecha_topic.dm +++ b/code/modules/vehicles/mecha/mecha_topic.dm @@ -3,7 +3,7 @@ ///// Rendering stats window /////// //////////////////////////////////// -/obj/mecha/proc/get_stats_html() +/obj/vehicle/sealed/mecha/proc/get_stats_html(mob/user) . = {" @@ -36,7 +36,7 @@
- [get_stats_part()] + [get_stats_part(user)]
[get_equipment_list()] @@ -52,7 +52,7 @@ "} ///Returns the status of the mech. -/obj/mecha/proc/get_stats_part() +/obj/vehicle/sealed/mecha/proc/get_stats_part(mob/user) var/integrity = obj_integrity/max_integrity*100 var/cell_charge = get_charge() var/datum/gas_mixture/int_tank_air = 0 @@ -73,20 +73,20 @@ Air tank temperature: [internal_tank?"[tank_temperature]°K|[tank_temperature - T0C]°C":"N/A"]
Cabin pressure: [internal_tank?"[cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa":"N/A"]
Cabin temperature: [internal_tank?"[return_temperature()]°K|[return_temperature() - T0C]°C":"N/A"]
"} - . += "[get_actions()]
" + . += "[get_actions(user)]
" ///Returns HTML for mech actions. Ideally, this proc would be empty for the base mecha. Segmented for easy refactoring. -/obj/mecha/proc/get_actions() +/obj/vehicle/sealed/mecha/proc/get_actions(mob/user) . = "" - . += "[defense_action.owner ? "Defense Mode: [defense_mode ? "Enabled" : "Disabled"].
" : ""]" - . += "[overload_action.owner ? "Leg Actuators Overload: [leg_overload_mode ? "Enabled" : "Disabled"].
" : ""]" - . += "[smoke_action.owner ? "Smoke: [smoke].
" : ""]" - . += "[zoom_action.owner ? "Zoom: [zoom_mode ? "Enabled" : "Disabled"].
" : ""]" - . += "[switch_damtype_action.owner ? "Damtype: [damtype].
" : ""]" - . += "[phasing_action.owner ? "Phase Modulator: [phasing ? "Enabled" : "Disabled"].
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_defense_mode) ? "Defense Mode: [defense_mode ? "Enabled" : "Disabled"]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_overload_mode) ? "Leg Actuators Overload: [leg_overload_mode ? "Enabled" : "Disabled"]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_smoke) ? "Smoke Charges remaining: [smoke_charges]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_zoom) ? "Zoom: [zoom_mode ? "Enabled" : "Disabled"]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_switch_damtype) ? "Damtype: [damtype]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_toggle_phasing) ? "Phase Modulator: [phasing ? "Enabled" : "Disabled"]
" : ""]" ///HTML for internal damage. -/obj/mecha/proc/report_internal_damage() +/obj/vehicle/sealed/mecha/proc/report_internal_damage() . = "" var/list/dam_reports = list( "[MECHA_INT_FIRE]" = "INTERNAL FIRE.", @@ -103,8 +103,8 @@ if(return_pressure() > WARNING_HIGH_PRESSURE) . += "DANGEROUSLY HIGH CABIN PRESSURE.
" -/obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html - if(!equipment.len) +/obj/vehicle/sealed/mecha/proc/get_equipment_list() //outputs mecha equipment list in html + if(!LAZYLEN(equipment)) return . = "Equipment:
" for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) @@ -112,7 +112,7 @@ . += "
" ///HTML for commands. -/obj/mecha/proc/get_commands() +/obj/vehicle/sealed/mecha/proc/get_commands() . = {"
Electronics
@@ -135,28 +135,27 @@ "} -/obj/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu +/obj/vehicle/sealed/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu . = {"
Equipment
"} -/obj/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user) +/obj/vehicle/sealed/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user) if(!id_card || !user) return . = {" @@ -188,7 +187,7 @@ onclose(user, "exosuit_add_access") -/obj/mecha/proc/output_maintenance_dialog(obj/item/card/id/id_card,mob/user) +/obj/vehicle/sealed/mecha/proc/output_maintenance_dialog(obj/item/card/id/id_card,mob/user) if(!id_card || !user) return . = {" @@ -200,8 +199,8 @@ - [add_req_access?"Edit operation keycodes":null] - [maint_access?"[(construction_state > MECHA_LOCKED) ? "Terminate" : "Initiate"] maintenance protocol":null] + [(mecha_flags & ADDING_ACCESS_POSSIBLE)?"Edit operation keycodes":null] + [(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"[(construction_state > MECHA_LOCKED) ? "Terminate" : "Initiate"] maintenance protocol":null] [(construction_state == MECHA_OPEN_HATCH) ?"--------------------
":null] [(construction_state == MECHA_OPEN_HATCH) ?"[cell?"Drop power cell":"No cell installed
"]":null] [(construction_state == MECHA_OPEN_HATCH) ?"[scanmod?"Drop scanning module":"No scanning module installed
"]":null] @@ -220,7 +219,7 @@ ///// Topic ///// ///////////////// -/obj/mecha/Topic(href, href_list) +/obj/vehicle/sealed/mecha/Topic(href, href_list) ..() if(!usr) @@ -241,13 +240,13 @@ return if(href_list["req_access"]) - if(!add_req_access) + if(!(mecha_flags & ADDING_ACCESS_POSSIBLE)) return output_access_dialog(id_card,usr) return if(href_list["maint_access"]) - if(!maint_access) + if(!(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)) return if(construction_state == MECHA_LOCKED) construction_state = MECHA_SECURE_BOLTS @@ -277,14 +276,14 @@ return if(href_list["add_req_access"]) - if(!add_req_access) + if(!(mecha_flags & ADDING_ACCESS_POSSIBLE)) return operation_req_access |= text2num(href_list["add_req_access"]) output_access_dialog(id_card,usr) return if(href_list["del_req_access"]) - if(!add_req_access) + if(!(mecha_flags & ADDING_ACCESS_POSSIBLE)) return operation_req_access -= text2num(href_list["del_req_access"]) output_access_dialog(id_card, usr) @@ -293,7 +292,7 @@ //Here ID access stuff goes to die. if(href_list["finish_req_access"]) - add_req_access = 0 + mecha_flags &= ~ADDING_ACCESS_POSSIBLE usr << browse(null,"window=exosuit_add_access") return @@ -307,7 +306,7 @@ return //Start of all internal topic stuff. - if(usr != occupant) + if(!locate(usr) in occupants) return if(href_list["update_content"]) @@ -320,7 +319,7 @@ if(!equip || !equip.selectable) return selected = equip - occupant_message("You switch to [equip].") + to_chat(occupants, "[icon2html(src, occupants)]You switch to [equip].") visible_message("[src] raises [equip].") send_byjax(usr, "exosuit.browser", "eq_list", get_equipment_list()) return @@ -347,58 +346,58 @@ //Changes the exosuit name. if(href_list["change_name"]) var/userinput = stripped_input(usr, "Choose a new exosuit name.", "Rename exosuit", "", MAX_NAME_LEN) - if(!userinput || usr != occupant || usr.incapacitated()) + if(!userinput || !locate(usr) in occupants || usr.incapacitated()) return name = userinput return //Toggles ID upload. if (href_list["toggle_id_upload"]) - add_req_access = !add_req_access - send_byjax(usr,"exosuit.browser","t_id_upload","[add_req_access?"L":"Unl"]ock ID upload panel") + mecha_flags ^= ADDING_ACCESS_POSSIBLE + send_byjax(usr,"exosuit.browser","t_id_upload","[(mecha_flags & ADDING_ACCESS_POSSIBLE)?"L":"Unl"]ock ID upload panel") return //Toggles main access. if(href_list["toggle_maint_access"]) if(construction_state) - occupant_message("Maintenance protocols in effect") + to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect") return - maint_access = !maint_access - send_byjax(usr,"exosuit.browser","t_maint_access","[maint_access?"Forbid":"Permit"] maintenance protocols") + mecha_flags ^= ADDING_MAINT_ACCESS_POSSIBLE + send_byjax(usr,"exosuit.browser","t_maint_access","[(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"Forbid":"Permit"] maintenance protocols") return //Toggles connection port. if (href_list["toggle_port_connection"]) if(internal_tank.connected_port) if(internal_tank.disconnect()) - occupant_message("Disconnected from the air system port.") + to_chat(occupants, "[icon2html(src, occupants)]Disconnected from the air system port.") log_message("Disconnected from gas port.", LOG_MECHA) else - occupant_message("Unable to disconnect from the air system port!") + to_chat(occupants, "[icon2html(src, occupants)]Unable to disconnect from the air system port!") return else var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate() in loc if(internal_tank.connect(possible_port)) - occupant_message("Connected to the air system port.") + to_chat(occupants, "[icon2html(src, occupants)]Connected to the air system port.") log_message("Connected to gas port.", LOG_MECHA) else - occupant_message("Unable to connect with air system port!") + to_chat(occupants, "[icon2html(src, occupants)]Unable to connect with air system port!") return - send_byjax(occupant,"exosuit.browser","t_port_connection","[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port") + send_byjax(occupants,"exosuit.browser","t_port_connection","[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port") return //Repairs internal damage if(href_list["repair_int_control_lost"]) - occupant_message("Recalibrating coordination system.") + to_chat(occupants, "[icon2html(src, occupants)]Recalibrating coordination system...") log_message("Recalibration of coordination system started.", LOG_MECHA) addtimer(CALLBACK(src, PROC_REF(stationary_repair), loc), 100, TIMER_UNIQUE) ///Repairs internal damage if the mech hasn't moved. -/obj/mecha/proc/stationary_repair(location) +/obj/vehicle/sealed/mecha/proc/stationary_repair(location) if(location == loc) clearInternalDamage(MECHA_INT_CONTROL_LOST) - occupant_message("Recalibration successful.") + to_chat(occupants, "[icon2html(src, occupants)]Recalibration successful.") log_message("Recalibration of coordination system finished with 0 errors.", LOG_MECHA) else - occupant_message("Recalibration failed!") + to_chat(occupants, "[icon2html(src, occupants)]Recalibration failed!") log_message("Recalibration of coordination system failed with 1 error.", LOG_MECHA, color="red") From 46eda483c80b49f85573c9c0eb3604ba951d23a7 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 01:13:26 -0400 Subject: [PATCH 15/41] working --- .../vehicles/mecha/medical/odysseus.dm | 20 ++-- code/modules/vehicles/mecha/working/ripley.dm | 104 ++++++++---------- .../modules/vehicles/mecha/working/working.dm | 2 +- 3 files changed, 59 insertions(+), 67 deletions(-) diff --git a/code/modules/vehicles/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm index b39faa4977d72..1cd8ea3b60b6f 100644 --- a/code/modules/vehicles/mecha/medical/odysseus.dm +++ b/code/modules/vehicles/mecha/medical/odysseus.dm @@ -1,32 +1,34 @@ -/obj/mecha/medical/odysseus +/obj/vehicle/sealed/mecha/medical/odysseus desc = "These exosuits are developed and produced by Vey-Med. (© All rights reserved)." name = "\improper Odysseus" icon_state = "odysseus" base_icon_state = "odysseus" - step_in = 2 + allow_diagonal_movement = TRUE + movedelay = 2 max_temperature = 15000 max_integrity = 120 wreckage = /obj/structure/mecha_wreckage/odysseus internal_damage_threshold = 35 deflect_chance = 15 step_energy_drain = 6 + internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_MEDICAL) -/obj/mecha/medical/odysseus/moved_inside(mob/living/carbon/human/H) +/obj/vehicle/sealed/mecha/medical/odysseus/moved_inside(mob/living/carbon/human/H) . = ..() if(.) var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] hud.add_hud_to(H) -/obj/mecha/medical/odysseus/go_out() - if(isliving(occupant)) - var/mob/living/L = occupant +/obj/vehicle/sealed/mecha/medical/odysseus/remove_occupant(mob/M) + if(isliving(M)) + var/mob/living/L = M var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] hud.remove_hud_from(L) - ..() + return ..() -/obj/mecha/medical/odysseus/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user) +/obj/vehicle/sealed/mecha/medical/odysseus/mmi_moved_inside(obj/item/mmi/M, mob/user) . = ..() if(.) var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] - var/mob/living/brain/B = mmi_as_oc.brainmob + var/mob/living/brain/B = M.brainmob hud.add_hud_to(B) diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index 35850c15dd97c..bbd664e7651e4 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -1,10 +1,10 @@ -/obj/mecha/working/ripley +/obj/vehicle/sealed/mecha/working/ripley desc = "Autonomous Power Loader Unit MK-I. Designed primarily around heavy lifting, the Ripley can be outfitted with utility equipment to fill a number of roles." name = "\improper APLU MK-I \"Ripley\"" icon_state = "ripley" base_icon_state = "ripley" silicon_icon_state = "ripley-empty" - step_in = 1.5 //Move speed, lower is faster. + movedelay = 1.5 //Move speed, lower is faster. var/fast_pressure_step_in = 1.5 //step_in while in low pressure conditions var/slow_pressure_step_in = 2.0 //step_in while in normal pressure conditions max_temperature = 20000 @@ -36,58 +36,46 @@ if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) //we can reach it and it's in front of us? grab it! ore.forceMove(ore_box) -/obj/mecha/working/ripley/Destroy() - for(var/atom/movable/A in cargo) - A.forceMove(drop_location()) - step_rand(A) - cargo.Cut() - return ..() - -/obj/mecha/working/ripley/go_out() +/obj/vehicle/sealed/mecha/working/ripley/mob_exit(mob/M, silent, forced) ..() update_icon() -/obj/mecha/working/ripley/moved_inside(mob/living/carbon/human/H) +/obj/vehicle/sealed/mecha/working/ripley/moved_inside(mob/living/carbon/human/H) ..() update_icon() -/obj/mecha/working/ripley/update_icon() - ..() - var/datum/component/armor_plate/C = GetComponent(/datum/component/armor_plate) - if (C.amount) - cut_overlays() - if(C.amount < 3) - add_overlay(occupant ? "ripley-g" : "ripley-g-open") - else - add_overlay(occupant ? "ripley-g-full" : "ripley-g-full-open") - -/obj/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null) +/obj/vehicle/sealed/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage, ignore_threshold = FALSE) if (!enclosed) possible_int_damage -= (MECHA_INT_TEMP_CONTROL + MECHA_INT_TANK_BREACH) //if we don't even have an air tank, these two doesn't make a ton of sense. . = ..() -/obj/mecha/working/ripley/Initialize(mapload) +/obj/vehicle/sealed/mecha/working/ripley/Initialize(mapload) . = ..() AddComponent(/datum/component/armor_plate,3,/obj/item/stack/sheet/animalhide/goliath_hide,list(MELEE = 10, BULLET = 5, LASER = 5)) +/obj/vehicle/sealed/mecha/working/ripley/Destroy() + for(var/atom/movable/A in cargo) + A.forceMove(drop_location()) + step_rand(A) + cargo.Cut() + return ..() -/obj/mecha/working/ripley/mkii +/obj/vehicle/sealed/mecha/working/ripley/mkii desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection" name = "\improper APLU MK-II \"Ripley\"" icon_state = "ripleymkii" base_icon_state = "ripleymkii" fast_pressure_step_in = 1.75 //step_in while in low pressure conditions slow_pressure_step_in = 3 //step_in while in normal pressure conditions - step_in = 3 + movedelay = 4 armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) wreckage = /obj/structure/mecha_wreckage/ripley/mkii enclosed = TRUE enter_delay = 40 silicon_icon_state = null - opacity = TRUE -/obj/mecha/working/ripley/firefighter +/obj/vehicle/sealed/mecha/working/ripley/firefighter desc = "Autonomous Power Loader Unit MK-III. This model is refitted with a pressurized cabin and additional hazard protection." name = "\improper APLU MK-III \"Firefighter\"" icon_state = "firefighter" @@ -96,7 +84,7 @@ max_integrity = 250 fast_pressure_step_in = 2 //step_in while in low pressure conditions slow_pressure_step_in = 4 //step_in while in normal pressure conditions - step_in = 4 + movedelay = 4 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF rad_flags = RAD_PROTECT_CONTENTS lights_power = 7 @@ -106,50 +94,47 @@ enclosed = TRUE enter_delay = 40 silicon_icon_state = null - opacity = TRUE -/obj/mecha/working/ripley/deathripley +/obj/vehicle/sealed/mecha/working/ripley/deathripley desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE" name = "\improper DEATH-RIPLEY" icon_state = "deathripley" base_icon_state = "deathripley" fast_pressure_step_in = 2 //step_in while in low pressure conditions slow_pressure_step_in = 4 //step_in while in normal pressure conditions - step_in = 4 + movedelay = 4 slow_pressure_step_in = 3 - opacity=0 lights_power = 7 wreckage = /obj/structure/mecha_wreckage/ripley/deathripley step_energy_drain = 0 enclosed = TRUE enter_delay = 40 silicon_icon_state = null - opacity = TRUE -/obj/mecha/working/ripley/deathripley/Initialize(mapload) +/obj/vehicle/sealed/mecha/working/ripley/deathripley/Initialize(mapload) . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill ME.attach(src) -/obj/mecha/working/ripley/deathripley/real +/obj/vehicle/sealed/mecha/working/ripley/deathripley/real desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE. FOR REAL" -/obj/mecha/working/ripley/deathripley/real/Initialize(mapload) +/obj/vehicle/sealed/mecha/working/ripley/deathripley/real/Initialize(mapload) . = ..() for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) E.detach() qdel(E) - equipment.Cut() + LAZYCLEARLIST(equipment) var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/real ME.attach(src) -/obj/mecha/working/ripley/mining +/obj/vehicle/sealed/mecha/working/ripley/mining desc = "An old, dusty mining Ripley." name = "\improper APLU \"Miner\"" obj_integrity = 75 //Low starting health -/obj/mecha/working/ripley/mining/Initialize(mapload) +/obj/vehicle/sealed/mecha/working/ripley/mining/Initialize(mapload) . = ..() if(cell) cell.charge = FLOOR(cell.charge * 0.25, 1) //Starts at very low charge @@ -177,24 +162,24 @@ var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new scanner.attach(src) -/obj/mecha/working/ripley/Exit(atom/movable/O) +/obj/vehicle/sealed/mecha/working/ripley/Exit(atom/movable/O) if(O in cargo) return 0 return ..() -/obj/mecha/working/ripley/Topic(href, href_list) +/obj/vehicle/sealed/mecha/working/ripley/Topic(href, href_list) ..() if(href_list["drop_from_cargo"]) var/obj/O = locate(href_list["drop_from_cargo"]) in cargo if(O) - occupant_message("You unload [O].") + to_chat(occupants, "[icon2html(src, occupants)]You unload [O].") O.forceMove(drop_location()) cargo -= O log_message("Unloaded [O]. Cargo compartment capacity: [cargo_capacity - src.cargo.len]", LOG_MECHA) return -/obj/mecha/working/ripley/contents_explosion(severity, target) +/obj/vehicle/sealed/mecha/working/ripley/contents_explosion(severity, target) for(var/X in cargo) var/obj/O = X if(prob(30/severity)) @@ -202,7 +187,7 @@ O.forceMove(drop_location()) . = ..() -/obj/mecha/working/ripley/get_stats_part() +/obj/vehicle/sealed/mecha/working/ripley/get_stats_part() var/output = ..() output += "Cargo Compartment Contents:
" if(cargo.len) @@ -213,19 +198,7 @@ output += "
" return output -/obj/mecha/working/ripley/proc/update_pressure() - var/turf/T = get_turf(loc) - - if(lavaland_equipment_pressure_check(T)) - step_in = fast_pressure_step_in - for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) - drill.equip_cooldown = initial(drill.equip_cooldown)/2 - else - step_in = slow_pressure_step_in - for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) - drill.equip_cooldown = initial(drill.equip_cooldown) - -/obj/mecha/working/ripley/relay_container_resist(mob/living/user, obj/O) +/obj/vehicle/sealed/mecha/working/ripley/relay_container_resist_act(mob/living/user, obj/O) to_chat(user, "You lean on the back of [O] and start pushing so it falls out of [src].") if(do_after(user, 300, target = O)) if(!user || user.stat != CONSCIOUS || user.loc != src || O.loc != src ) @@ -236,3 +209,20 @@ else if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded. to_chat(user, "You fail to push [O] out of [src]!") + +/** + * Makes the mecha go faster and halves the mecha drill cooldown if in Lavaland pressure. + * + * Checks for Lavaland pressure, if that works out the mech's speed is equal to fast_pressure_step_in and the cooldown for the mecha drill is halved. If not it uses slow_pressure_step_in and drill cooldown is normal. + */ +/obj/vehicle/sealed/mecha/working/ripley/proc/update_pressure() + var/turf/T = get_turf(loc) + + if(lavaland_equipment_pressure_check(T)) + movedelay = fast_pressure_step_in + for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) + drill.equip_cooldown = initial(drill.equip_cooldown)/2 + else + movedelay = slow_pressure_step_in + for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) + drill.equip_cooldown = initial(drill.equip_cooldown) diff --git a/code/modules/vehicles/mecha/working/working.dm b/code/modules/vehicles/mecha/working/working.dm index 3e45148ef51ec..f979a57ada429 100644 --- a/code/modules/vehicles/mecha/working/working.dm +++ b/code/modules/vehicles/mecha/working/working.dm @@ -1,2 +1,2 @@ -/obj/mecha/working +/obj/vehicle/sealed/mecha/working internal_damage_threshold = 60 From 4834ce0c6adeeacbf3bcb60523188cce9f1f3087 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 01:19:53 -0400 Subject: [PATCH 16/41] odysseus --- .../targetting_datums/basic_targetting_datum.dm | 4 ++-- code/modules/vehicles/mecha/_mecha.dm | 16 ++++++++-------- code/modules/vehicles/mecha/mecha_defense.dm | 2 +- code/modules/vehicles/mecha/working/ripley.dm | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm index 5aa2aafdf66e0..c46cf0a5917b2 100644 --- a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm +++ b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm @@ -39,8 +39,8 @@ return TRUE if(ismecha(the_target)) //Targetting vs mechas - var/obj/mecha/M = the_target - if(can_attack(living_mob, M.occupant)) //Can we attack any of the occupants? + var/obj/vehicle/sealed/mecha/M = the_target + if(can_attack(living_mob, M.occupants)) //Can we attack any of the occupants? return TRUE if(istype(the_target, /obj/machinery/porta_turret)) //Cringe turret! kill it! diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 74c80f26f4ac4..55f784a0f1055 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -1149,7 +1149,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? // = 2017??? return TRUE return FALSE -/obj/mecha/proc/give_power(amount) +/obj/vehicle/sealed/mecha/proc/give_power(amount) if(!isnull(get_charge())) cell.give(amount) return TRUE @@ -1157,10 +1157,10 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? // = 2017??? /obj/vehicle/sealed/mecha/lighteater_act(obj/item/light_eater/light_eater, atom/parent) ..() - if(!lights_power) - return - lights = FALSE - lights_power = 0 - set_light_on(FALSE) - visible_message(src, "The lights on [src] short out!") - playsound(src, 'sound/items/welder.ogg', 50, 1) + if(mecha_flags & HAS_LIGHTS) + visible_message("[src]'s lights burn out!") + mecha_flags &= ~HAS_LIGHTS + set_light_on(FALSE) + for(var/occupant in occupants) + remove_action_type_from_mob(/datum/action/vehicle/sealed/mecha/mech_toggle_lights, occupant) + playsound(src, 'sound/items/welder.ogg', 50, 1) diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index fa271e7360f37..cfb39333472c4 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -71,7 +71,7 @@ playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) attack_generic(user, 15, BRUTE, MELEE, 0) -/obj/mecha/attack_animal(mob/living/simple_animal/user) +/obj/vehicle/sealed/mecha/attack_animal(mob/living/simple_animal/user) log_message("Attack by simple animal. Attacker - [user].", LOG_MECHA, color="red") if(!user.melee_damage && !user.obj_damage) user.emote("custom", message = "[user.friendly] [src].") diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index bbd664e7651e4..fd3911764ce94 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -22,13 +22,13 @@ enter_delay = 10 //can enter in a quarter of the time of other mechs exit_delay = 10 -/obj/mecha/working/ripley/Move() +/obj/vehicle/sealed/mecha/working/ripley/Move() . = ..() if(.) collect_ore() update_pressure() -/obj/mecha/working/ripley/proc/collect_ore() +/obj/vehicle/sealed/mecha/working/ripley/proc/collect_ore() if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in equipment) var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in cargo if(ore_box) From 737f77dd72b485fce50bf3bd52d73dc051f7155c Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 01:47:54 -0400 Subject: [PATCH 17/41] conflict fixes --- .../lavaland_surface_random_ripley.dmm | 2 +- .../RandomRuins/SpaceRuins/mechtransport.dmm | 2 +- _maps/RandomZLevels/caves.dmm | 2 +- _maps/RandomZLevels/snowdin.dmm | 2 +- _maps/RandomZLevels/spacebattle.dmm | 12 ++++---- .../basic_ai_behaviors/targetting.dm | 2 +- code/game/machinery/doors/airlock.dm | 12 ++++---- code/game/objects/effects/spiders.dm | 6 ++-- code/game/turfs/closed/wall/misc_walls.dm | 4 +-- code/modules/admin/battle_royale.dm | 2 +- .../antagonists/clock_cult/clockwork_turfs.dm | 2 +- .../clock_cult/items/clockwork_weapon.dm | 4 +-- .../scriptures/interdiction_lens.dm | 2 +- .../scriptures/sigil_transmission.dm | 6 ++-- .../heretic/knowledge/rust_lore.dm | 2 +- code/modules/mob/living/brain/MMI.dm | 28 ++++++++++++++++++ .../living/simple_animal/hostile/hostile.dm | 2 +- .../simple_animal/hostile/mecha_pilot.dm | 12 ++++---- code/modules/multiz/zmimic/mimic_movable.dm | 2 +- code/modules/vehicles/mecha/_mecha.dm | 29 +++++++++---------- .../mecha/equipment/tools/medical_tools.dm | 8 ++--- .../mecha/equipment/tools/mining_tools.dm | 2 +- .../mecha/equipment/tools/work_tools.dm | 7 +++-- .../mecha/equipment/weapons/weapons.dm | 4 +-- code/modules/vehicles/mecha/mecha_defense.dm | 2 +- .../modules/vehicles/mecha/medical/medical.dm | 19 ------------ 26 files changed, 93 insertions(+), 84 deletions(-) delete mode 100644 code/modules/vehicles/mecha/medical/medical.dm diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm index 546ddcff7e4a6..6950eb4ac43ca 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm @@ -9,7 +9,7 @@ /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "d" = ( -/obj/mecha/working/ripley/mining{ +/obj/vehicle/sealed/mecha/working/ripley/mining{ ruin_mecha = 1 }, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, diff --git a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm index 748cf85d8ca47..8c709f4b4f953 100644 --- a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm +++ b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm @@ -101,7 +101,7 @@ /turf/open/floor/mineral/titanium/yellow/airless, /area/ruin/space/has_grav/powered/mechtransport) "A" = ( -/obj/mecha/working/ripley{ +/obj/vehicle/sealed/mecha/working/ripley{ ruin_mecha = 1 }, /turf/open/floor/mineral/titanium/yellow/airless, diff --git a/_maps/RandomZLevels/caves.dmm b/_maps/RandomZLevels/caves.dmm index 335a38c7f411d..8ea1777a37b09 100644 --- a/_maps/RandomZLevels/caves.dmm +++ b/_maps/RandomZLevels/caves.dmm @@ -2116,7 +2116,7 @@ }, /area/awaymission/caves/BMP_asteroid) "gC" = ( -/obj/mecha/working/ripley/mining{ +/obj/vehicle/sealed/mecha/working/ripley/mining{ ruin_mecha = 1 }, /turf/open/floor/plasteel/recharge_floor, diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm index c49ebc3194758..91b1509e0a07a 100644 --- a/_maps/RandomZLevels/snowdin.dmm +++ b/_maps/RandomZLevels/snowdin.dmm @@ -10932,7 +10932,7 @@ /turf/open/floor/plasteel/dark, /area/awaymission/snowdin/post/mining_main/mechbay) "In" = ( -/obj/mecha/working/ripley/mining{ +/obj/vehicle/sealed/mecha/working/ripley/mining{ dir = 1; ruin_mecha = 1 }, diff --git a/_maps/RandomZLevels/spacebattle.dmm b/_maps/RandomZLevels/spacebattle.dmm index ad05ab90e3777..bfebb690d9aef 100644 --- a/_maps/RandomZLevels/spacebattle.dmm +++ b/_maps/RandomZLevels/spacebattle.dmm @@ -774,11 +774,11 @@ /turf/open/floor/plasteel, /area/awaymission/spacebattle/cruiser) "dK" = ( -/obj/mecha/medical/odysseus, +/obj/vehicle/sealed/mecha/medical/odysseus, /turf/open/floor/plating, /area/awaymission/spacebattle/cruiser) "dL" = ( -/obj/mecha/working/ripley/firefighter{ +/obj/vehicle/sealed/mecha/working/ripley/firefighter{ ruin_mecha = 1 }, /turf/open/floor/plating, @@ -2014,7 +2014,7 @@ /turf/open/floor/plasteel/rockvault/alien, /area/awaymission/spacebattle/secret) "jp" = ( -/obj/mecha/combat/gygax, +/obj/vehicle/sealed/mecha/combat/gygax, /turf/open/floor/plating, /area/awaymission/spacebattle/cruiser) "jq" = ( @@ -2050,7 +2050,7 @@ /area/awaymission/spacebattle/cruiser) "jz" = ( /mob/living/simple_animal/hostile/syndicate/mecha_pilot{ - spawn_mecha_type = /obj/mecha/combat/gygax/dark/loaded + spawn_mecha_type = /obj/vehicle/sealed/mecha/combat/gygax/dark/loaded }, /turf/open/floor/plasteel, /area/awaymission/spacebattle/cruiser) @@ -2155,13 +2155,13 @@ /area/awaymission/spacebattle/cruiser) "jV" = ( /mob/living/simple_animal/hostile/syndicate/mecha_pilot{ - spawn_mecha_type = /obj/mecha/combat/gygax/dark/loaded + spawn_mecha_type = /obj/vehicle/sealed/mecha/combat/gygax/dark/loaded }, /turf/open/floor/plating/airless, /area/awaymission/spacebattle/cruiser) "jW" = ( /mob/living/simple_animal/hostile/syndicate/mecha_pilot{ - spawn_mecha_type = /obj/mecha/combat/gygax/dark/loaded + spawn_mecha_type = /obj/vehicle/sealed/mecha/combat/gygax/dark/loaded }, /turf/open/floor/plasteel/airless, /area/awaymission/spacebattle/cruiser) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm index 63a9ee83bb071..775d1741b8fd0 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm @@ -3,7 +3,7 @@ /// How far can we see stuff? var/vision_range = 9 /// Static typecache list of potentially dangerous objs - var/static/list/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha)) + var/static/list/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) /datum/ai_behavior/find_potential_targets/perform(delta_time, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) . = ..() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 78f1e89468a66..adf6ab80fef69 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -386,16 +386,16 @@ if(operating || (obj_flags & EMAGGED)) return if(ismecha(AM)) - var/obj/mecha/mecha = AM + var/obj/vehicle/sealed/mecha/mecha = AM if(density) - if(mecha.occupant) - if(world.time - mecha.occupant.last_bumped <= 10) + if(mecha.occupants) + if(world.time - mecha.occupants.last_bumped <= 10) return - mecha.occupant.last_bumped = world.time - if(locked && (allowed(mecha.occupant) || check_access_list(mecha.operation_req_access)) && aac) + mecha.occupants.last_bumped = world.time + if(locked && (allowed(mecha.occupants) || check_access_list(mecha.operation_req_access)) && aac) aac.request_from_door(src) return - if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access))) + if(mecha.occupants && (src.allowed(mecha.occupants) || src.check_access_list(mecha.operation_req_access))) open() else do_animate("deny") diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index b3dbe045cd0c5..a8238caac56e7 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -51,10 +51,10 @@ to_chat(L, "You get stuck in \the [src] for a moment.") L.Immobilize(1.5 SECONDS) if(ismecha(AM)) - var/obj/mecha/mech = AM + var/obj/vehicle/sealed/mecha/mech = AM mech.step_restricted += 1 SECONDS //unlike the above, this one stacks based on number of webs. Punch the webs to destroy them you dolt. - if(mech.occupant && !mech.step_restricted) - to_chat(mech.occupant, "\the [mech] gets stuck in \the [src]!") + if(mech.occupants && !mech.step_restricted) + to_chat(mech.occupants, "\the [mech] gets stuck in \the [src]!") /obj/structure/spider/stickyweb/CanAllowThrough(atom/movable/mover, border_dir) . = ..() diff --git a/code/game/turfs/closed/wall/misc_walls.dm b/code/game/turfs/closed/wall/misc_walls.dm index 3716a192eb0a6..b4588c86f6380 100644 --- a/code/game/turfs/closed/wall/misc_walls.dm +++ b/code/game/turfs/closed/wall/misc_walls.dm @@ -122,8 +122,8 @@ var/mob/interloper = AM interloper.death() if(ismecha(AM)) - var/obj/mecha/fuckphazons = AM - var/mob/living/carbon/interloper = fuckphazons.occupant + var/obj/vehicle/sealed/mecha/fuckphazons = AM + var/mob/living/carbon/interloper = fuckphazons.occupants interloper?.death() qdel(interloper) diff --git a/code/modules/admin/battle_royale.dm b/code/modules/admin/battle_royale.dm index 1c6e4f8fcf9bc..074e6df67957a 100644 --- a/code/modules/admin/battle_royale.dm +++ b/code/modules/admin/battle_royale.dm @@ -97,7 +97,7 @@ GLOBAL_LIST_INIT(battle_royale_insane_loot, list( /obj/item/energy_katana, /obj/item/clothing/suit/space/hardsuit/shielded/syndi, /obj/item/his_grace, - /obj/mecha/combat/marauder/mauler/loaded, + /obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded, /obj/item/holoparasite_creator/tech, /obj/item/mjolnir, /obj/item/pneumatic_cannon/pie/selfcharge, diff --git a/code/modules/antagonists/clock_cult/clockwork_turfs.dm b/code/modules/antagonists/clock_cult/clockwork_turfs.dm index 2a789423715b5..d702f4d659dbd 100644 --- a/code/modules/antagonists/clock_cult/clockwork_turfs.dm +++ b/code/modules/antagonists/clock_cult/clockwork_turfs.dm @@ -151,7 +151,7 @@ return 1 return -/turf/closed/wall/clockwork/mech_melee_attack(obj/mecha/M) +/turf/closed/wall/clockwork/mech_melee_attack(obj/vehicle/sealed/mecha/M) return /turf/closed/wall/clockwork/update_icon() diff --git a/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm b/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm index 5906f8a4d9551..8455aaad988c4 100644 --- a/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm +++ b/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm @@ -132,13 +132,13 @@ /obj/item/clockwork/weapon/brass_sword/attack_obj(obj/O, mob/living/user) ..() - if(!(istype(O, /obj/mecha) && is_reebe(user.z))) + if(!(istype(O, /obj/vehicle/sealed/mecha) && is_reebe(user.z))) return if(!COOLDOWN_FINISHED(src, emp_cooldown)) return COOLDOWN_START(src, emp_cooldown, 20 SECONDS) - var/obj/mecha/target = O + var/obj/vehicle/sealed/mecha/target = O target.emp_act(EMP_HEAVY) new /obj/effect/temp_visual/emp/pulse(target.loc) addtimer(CALLBACK(src, PROC_REF(send_message), user), 20 SECONDS) diff --git a/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm b/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm index 567c4994af9e9..89bec9d8fad8c 100644 --- a/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm +++ b/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm @@ -67,7 +67,7 @@ for(var/mob/living/L in viewers(INTERDICTION_LENS_RANGE, src)) if(!is_servant_of_ratvar(L) && use_power(5)) L.apply_status_effect(STATUS_EFFECT_INTERDICTION) - for(var/obj/mecha/M in dview(INTERDICTION_LENS_RANGE, src, SEE_INVISIBLE_MINIMUM)) + for(var/obj/vehicle/sealed/mecha/M in dview(INTERDICTION_LENS_RANGE, src, SEE_INVISIBLE_MINIMUM)) if(use_power(5)) M.emp_act(EMP_HEAVY) M.take_damage(400 * delta_time) diff --git a/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm b/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm index 8c55f34b89556..a032b9b170277 100644 --- a/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm +++ b/code/modules/antagonists/clock_cult/scriptures/sigil_transmission.dm @@ -51,12 +51,12 @@ GB.update_power() /obj/structure/destructible/clockwork/sigil/transmission/can_affect(atom/movable/AM) - return (istype(AM, /obj/mecha) || iscyborg(AM) || ishuman(AM)) + return (istype(AM, /obj/vehicle/sealed/mecha) || iscyborg(AM) || ishuman(AM)) /obj/structure/destructible/clockwork/sigil/transmission/apply_effects(atom/movable/AM) - if(istype(AM, /obj/mecha)) + if(istype(AM, /obj/vehicle/sealed/mecha)) var/obj/vehicle/sealed/mecha/M = AM - var/mob/living/O = M.occupant + var/mob/living/O = M.occupants var/obj/item/stock_parts/cell/C = M.cell if(!C) return diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm index 0b4d1a6452156..252da75cdcc98 100644 --- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm @@ -77,7 +77,7 @@ /mob/living/simple_animal/bot, /obj/item/storage/secure/safe/caps_spare, /obj/machinery/door, - /obj/mecha + /obj/vehicle/sealed/mecha )) // The reason this is not simply an isturf is because we likely don't want to hit random machinery like holopads and such! if(source.a_intent == INTENT_HARM && !is_type_in_typecache(target, always_hit_typecache)) diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 1755df54f3b51..47006acb3c59f 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -209,6 +209,34 @@ /obj/item/mmi/relaymove(mob/user) return //so that the MMI won't get a warning about not being able to move if it tries to move +/obj/item/mmi/proc/brain_check(mob/user) + var/mob/living/brain/B = brainmob + if(!B) + if(user) + to_chat(user, "\The [src] indicates that there is no brain present!") + return FALSE + if(!B.key || !B.mind) + if(user) + to_chat(user, "\The [src] indicates that their mind is completely unresponsive!") + return FALSE + if(!B.client) + if(user) + to_chat(user, "\The [src] indicates that their mind is currently inactive.") + return FALSE + if(B.suiciding || brain?.suicided) + if(user) + to_chat(user, "\The [src] indicates that their mind has no will to live!") + return FALSE + if(B.stat == DEAD) + if(user) + to_chat(user, "\The [src] indicates that the brain is dead!") + return FALSE + if(brain?.organ_flags & ORGAN_FAILING) + if(user) + to_chat(user, "\The [src] indicates that the brain is damaged!") + return FALSE + return TRUE + /obj/item/mmi/syndie name = "\improper Syndicate Man-Machine Interface" desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs and AIs created with it." diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 377b58e4e0aa8..b4ed2cc042912 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -131,7 +131,7 @@ /mob/living/simple_animal/hostile/proc/ListTargets() //Step 1, find out what we can see var/atom/target_from = GET_TARGETS_FROM(src) if(!search_objects) - var/static/target_list = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha)) //mobs are handled via ismob(A) + var/static/target_list = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) //mobs are handled via ismob(A) . = list() for(var/atom/A as() in dview(vision_range, get_turf(target_from), SEE_INVISIBLE_MINIMUM)) if((ismob(A) && A != src) || target_list[A.type]) diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm index a7afb760b183f..5decee97a4547 100644 --- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm +++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm @@ -237,12 +237,14 @@ else if(prob(retreat_chance)) //Speed boost if possible - if(mecha.overload_action && mecha.overload_action.owner && !mecha.leg_overload_mode) - mecha.overload_action.Activate(TRUE) - addtimer(CALLBACK(mecha.overload_action, TYPE_PROC_REF(/datum/action/vehicle/sealed/mecha/mech_defense_mode, Activate), FALSE), 100) //10 seconds of speeeeed, then toggle off + if(LAZYACCESSASSOC(mecha.occupant_actions, src, /datum/action/vehicle/sealed/mecha/mech_overload_mode) && !mecha.leg_overload_mode) + var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_overload_mode] + mecha.leg_overload_mode = FALSE + action.Trigger(TRUE) + addtimer(CALLBACK(action, /datum/action/vehicle/sealed/mecha/mech_overload_mode.proc/Trigger, FALSE), 100) //10 seconds of speeeeed, then toggle off retreat_distance = 50 - addtimer(VARSET_CALLBACK(src, retreat_distance, 0), 100) + addtimer(VARSET_CALLBACK(src, retreat_distance, 0), 10 SECONDS) @@ -290,6 +292,6 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/Goto(target, delay, minimum_distance) if(mecha) - SSmove_manager.move_to(mecha, target, minimum_distance, mecha.step_in * mecha.step_multiplier) + SSmove_manager.move_to(mecha, target, minimum_distance, mecha.movedelay * mecha.step_multiplier) else ..() diff --git a/code/modules/multiz/zmimic/mimic_movable.dm b/code/modules/multiz/zmimic/mimic_movable.dm index 158e489aed342..e6221bb474a31 100644 --- a/code/modules/multiz/zmimic/mimic_movable.dm +++ b/code/modules/multiz/zmimic/mimic_movable.dm @@ -54,7 +54,7 @@ /atom/movable/openspace/acid_act() return -/atom/movable/openspace/mech_melee_attack(obj/mecha/M) +/atom/movable/openspace/mech_melee_attack(obj/vehicle/sealed/mecha/M) return 0 /atom/movable/openspace/blob_act(obj/structure/blob/B) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 55f784a0f1055..69d750c50f744 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -175,7 +175,6 @@ /obj/vehicle/sealed/mecha/Initialize(mapload) . = ..() - events = new add_radio() add_cabin() if(enclosed) @@ -512,7 +511,7 @@ to_chat(user, "You short out the mech suit's internal controls.") equipment_disabled = TRUE log_message("System emagged detected", LOG_MECHA, color="red") - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/mecha, restore_equipment)), 15 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/vehicle/sealed/mecha, restore_equipment)), 15 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) //////////////////////////// ///// Action processing //// @@ -672,7 +671,7 @@ playsound(src,turnsound,40,TRUE) return TRUE - set_glide_size(DELAY_TO_GLIDE_SIZE(movedelay)) + //set_glide_size(DELAY_TO_GLIDE_SIZE(movedelay)) //Otherwise just walk normally . = step(src,direction, dir) @@ -836,8 +835,8 @@ if(AI.stat || !AI.client) to_chat(user, "[AI.name] is currently unresponsive, and cannot be uploaded.") return - if(occupant) //Normal AIs cannot steal mechs! - to_chat(user, "Access denied. [name] is [occupant ? "currently occupied" : "secured with a DNA lock"].") + if(LAZYLEN(occupants) >= max_occupants) //Normal AIs cannot steal mechs! + to_chat(user, "Access denied. [name] is [LAZYLEN(occupants) >= max_occupants ? "currently fully occupied" : "secured with a DNA lock"].") return AI.control_disabled = FALSE AI.radio_enabled = TRUE @@ -995,24 +994,22 @@ /obj/vehicle/sealed/mecha/proc/mmi_moved_inside(obj/item/mmi/M, mob/user) if(!(Adjacent(M) && Adjacent(user))) return FALSE - if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) - to_chat(user, "Consciousness matrix not detected!") - return FALSE - else if(mmi_as_oc.brainmob.stat) - to_chat(user, "Beta-rhythm below acceptable level!") + if(!M.brain_check(user)) return FALSE - if(!user.transferItemToLoc(mmi_as_oc, src)) - to_chat(user, "\the [mmi_as_oc] is stuck to your hand, you cannot put it in \the [src]!") + + var/mob/living/brain/B = M.brainmob + if(!user.transferItemToLoc(M, src)) + to_chat(user, "\the [M] is stuck to your hand, you cannot put it in \the [src]!") return FALSE - var/mob/living/brainmob = mmi_as_oc.brainmob + + M.mecha = src add_occupant(B)//Note this forcemoves the brain into the mech to allow relaymove mecha_flags |= SILICON_PILOT B.reset_perspective(src) B.remote_control = src - brainmob.update_mobility() - brainmob.update_mouse_pointer() - update_icon() + B.update_mobility() + B.update_mouse_pointer() setDir(dir_in) log_message("[M] moved in as pilot.", LOG_MECHA) if(!internal_damage) diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm index 43ef82d56a402..f772c44da25ee 100644 --- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm @@ -110,7 +110,7 @@ return /obj/item/mecha_parts/mecha_equipment/medical/sleeper/Topic(href,href_list) - .. = ..() + . = ..() if(.) return if(!(usr in chassis.occupants)) @@ -280,7 +280,7 @@ STOP_PROCESSING(SSobj, src) return ..() -obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M) +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M) if(..()) if(istype(M)) return 1 @@ -457,7 +457,7 @@ obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/ output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All" return output || "None" -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/load_syringe(obj/item/reagent_containers/syringe/S) +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/load_syringe(obj/item/reagent_containers/syringe/S, mob/user) if(syringes.lenUnable to load syringe!") @@ -465,7 +465,7 @@ obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/ S.reagents.trans_to(src, S.reagents.total_volume, transfered_by = user) S.forceMove(src) syringes += S - occupant_message("Syringe loaded.") + to_chat(user, "[icon2html(src, user)]Syringe loaded.") update_equip_info() return 1 to_chat(user, "[icon2html(src, user)][src]'s syringe chamber is full!") diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index 026c0ee0dc6dc..39628edc0e0a4 100644 --- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm @@ -99,7 +99,7 @@ return TRUE return FALSE -/obj/item/mecha_parts/mecha_equipment/drill/attach(obj/mecha/M) +/obj/item/mecha_parts/mecha_equipment/drill/attach(obj/vehicle/sealed/mecha/M) ..() var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering) butchering.butchering_enabled = TRUE diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index 147cb4d937e69..eeb3592b20289 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -37,7 +37,7 @@ if(!cargo_holder) return if(ismecha(target)) - var/obj/vehicle/sealed/mecha/M = target + var/obj/O = target if(istype(O, /obj/machinery/door/firedoor)) var/obj/machinery/door/firedoor/D = O D.try_to_crowbar(src, source) @@ -333,7 +333,7 @@ return "[..()] \[D|C|A\]" - +/* /obj/item/mecha_parts/mecha_equipment/cable_layer name = "cable layer" @@ -349,7 +349,7 @@ . = ..() cable = new(src, 0) -/obj/item/mecha_parts/mecha_equipment/cable_layer/can_attach(obj/mecha/working/M) +/obj/item/mecha_parts/mecha_equipment/cable_layer/can_attach(obj/vehicle/sealed/mecha/working/M) if(..()) if(istype(M)) return 1 @@ -469,6 +469,7 @@ //NC.mergeConnectedNetworksOnTurf() last_piece = NC return 1 +*/ //Dunno where else to put this so shrug /obj/item/mecha_parts/mecha_equipment/ripleyupgrade diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 969340a5bbf3e..856d912b4194c 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -193,8 +193,8 @@ log_message("Honked from [src.name]. HONK!", LOG_MECHA) var/turf/T = get_turf(src) - message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Mecha Honker in [ADMIN_VERBOSEJMP(T)]") - log_game("[key_name(chassis.occupant)] used a Mecha Honker in [AREACOORD(T)]") + message_admins("[ADMIN_LOOKUPFLW(source)] used a Mecha Honker in [ADMIN_VERBOSEJMP(T)]") + log_game("[key_name(source)] used a Mecha Honker in [AREACOORD(T)]") return 1 diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index cfb39333472c4..50328620a69fe 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -173,7 +173,7 @@ occupant.update_mouse_pointer() if(!equipment_disabled && occupants) //prevent spamming this message with back-to-back EMPs to_chat(occupants, "Error -- Connection to equipment control unit has been lost.") - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/mecha, restore_equipment)), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/vehicle/sealed/mecha, restore_equipment)), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) equipment_disabled = 1 /obj/vehicle/sealed/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) diff --git a/code/modules/vehicles/mecha/medical/medical.dm b/code/modules/vehicles/mecha/medical/medical.dm deleted file mode 100644 index b25175cd046d7..0000000000000 --- a/code/modules/vehicles/mecha/medical/medical.dm +++ /dev/null @@ -1,19 +0,0 @@ -/obj/mecha/medical - internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_MEDICAL) - -/obj/mecha/medical/mechturn(direction) - setDir(direction) - playsound(src,'sound/mecha/mechmove01.ogg',40,1) - return 1 - -/obj/mecha/medical/mechstep(direction) - var/result = step(src,direction) - if(result) - playsound(src,'sound/mecha/mechstep.ogg',25,1) - return result - -/obj/mecha/medical/mechsteprand() - var/result = step_rand(src) - if(result) - playsound(src,'sound/mecha/mechstep.ogg',25,1) - return result From 0e0ae1f96a31f445d05599b6c0faf3b174879ac8 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 02:10:31 -0400 Subject: [PATCH 18/41] BEGONE SLEEPS!!! --- code/datums/action.dm | 1 + .../modules/mob/living/simple_animal/hostile/mecha_pilot.dm | 2 +- code/modules/vehicles/mecha/_mecha.dm | 6 ++---- code/modules/vehicles/mecha/combat/durand.dm | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/code/datums/action.dm b/code/datums/action.dm index 344a8bd46de91..64fa8d8c5d3c4 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -174,6 +174,7 @@ return ..() /datum/action/item_action/Trigger() + . = ..() if(!..()) return FALSE if(target) diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm index 5decee97a4547..cf3b1e9ba087e 100644 --- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm +++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm @@ -65,7 +65,7 @@ if(spawn_mecha_type) var/obj/vehicle/sealed/mecha/M = new spawn_mecha_type (get_turf(src)) if(istype(M)) - enter_mecha(M) + INVOKE_ASYNC(src, .proc/enter_mecha, M) /mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/enter_mecha(obj/vehicle/sealed/mecha/M) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 69d750c50f744..f1f6f6bd0ef37 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -37,11 +37,9 @@ ///How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain. var/normal_step_energy_drain = 10 - /* //Beestation stuff var/step_multiplier = 1 var/step_restricted = 0 //applied on_entered() by things which slow or restrict mech movement. Resets to zero at the end of every movement - */ ///How much energy the mech will consume each time it moves. this is the current active energy consumed var/step_energy_drain = 10 @@ -554,13 +552,13 @@ if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful) to_chat(L, "You don't want to harm other living beings!") return - selected.action(user, target, params) + INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, params) return if((selected.range & MECHA_MELEE) && Adjacent(target)) if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM)) to_chat(L, "You don't want to harm other living beings!") return - selected.action(user, target, params) + INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, params) return if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK) || !istype(target, /atom) || !Adjacent(target)) return diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm index 76a28d726aa91..e540ad05dc085 100644 --- a/code/modules/vehicles/mecha/combat/durand.dm +++ b/code/modules/vehicles/mecha/combat/durand.dm @@ -55,7 +55,7 @@ if(defense_mode) var/datum/action/action = LAZYACCESSASSOC(occupant_actions, M, /datum/action/vehicle/sealed/mecha/mech_defense_mode) if(action) - action.Trigger(FALSE) + INVOKE_ASYNC(action, /datum/action.proc/Trigger, FALSE) return ..() ///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA. From a87bfddba7541b4bcb81dbd00cabbeac7d32b205 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 02:17:41 -0400 Subject: [PATCH 19/41] fixes 2 --- .../objects/items/grenades/discogrenade.dm | 8 +++++++ code/modules/vehicles/mecha/_mecha.dm | 21 ++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/code/game/objects/items/grenades/discogrenade.dm b/code/game/objects/items/grenades/discogrenade.dm index afedfeffbf463..7fc7d9813a04a 100644 --- a/code/game/objects/items/grenades/discogrenade.dm +++ b/code/game/objects/items/grenades/discogrenade.dm @@ -58,6 +58,14 @@ addtimer(CALLBACK(src, PROC_REF(prime)), rand(10, 60)) randomiseLightColor() +/proc/rand_hex_color() + var/list/colors = list("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f") + var/color="" + for (var/i=0;i<6;i++) + color = color+pick(colors) + return color + + /obj/item/grenade/discogrenade/subgrenade/prime(mob/living/lanced_by) if(dud_flags) active = FALSE diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index f1f6f6bd0ef37..24e4d9ee9185d 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -239,10 +239,12 @@ /obj/vehicle/sealed/mecha/update_icon_state() if((mecha_flags & SILICON_PILOT) && silicon_icon_state) icon_state = silicon_icon_state - else if(LAZYLEN(occupants)) - icon_state = initial(icon_state) - else - icon_state = initial(icon_state)+ "-open" + return ..() + if(LAZYLEN(occupants)) + icon_state = base_icon_state + return ..() + icon_state = "[base_icon_state]-open" + return ..() /obj/vehicle/sealed/mecha/get_cell() @@ -495,13 +497,16 @@ cookedalive.fire_stacks += 1 cookedalive.IgniteMob() +///Displays a special speech bubble when someone inside the mecha speaks /obj/vehicle/sealed/mecha/proc/display_speech_bubble(datum/source, list/speech_args) SIGNAL_HANDLER - var/list/speech_bubble_recipients = get_hearers_in_view(7,src) - for(var/mob/M as anything in speech_bubble_recipients) - if(M.client) + var/list/speech_bubble_recipients = list() + for(var/mob/listener in get_hearers_in_view(7, src)) + if(listener.client) speech_bubble_recipients.Add(M.client) - INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), image('icons/mob/talk.dmi', src, "machine[say_test(raw_message)]",MOB_LAYER+1), speech_bubble_recipients, 30) + + var/image/mech_speech = image('icons/mob/effects/talk.dmi', src, "machine[say_test(speech_args[SPEECH_MESSAGE])]",MOB_LAYER+1) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay_global), mech_speech, speech_bubble_recipients, 3 SECONDS) /obj/vehicle/sealed/mecha/on_emag(mob/user) ..() From 7697bbbb329ffd6e61e45e89427db83fc8d816a2 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 02:42:01 -0400 Subject: [PATCH 20/41] CONFLICT FREEEEE --- code/game/atoms.dm | 2 +- code/game/machinery/doors/airlock.dm | 6 +++--- .../machinery/porta_turret/portable_turret.dm | 13 +++++++------ code/modules/vehicles/mecha/_mecha.dm | 15 +++++++-------- code/modules/vehicles/mecha/mecha_actions.dm | 2 +- code/modules/vehicles/mecha/working/ripley.dm | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d753341651c9e..7140ed47710c8 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1692,7 +1692,7 @@ */ /atom/proc/setClosed() return - + /** * Instantiates the AI controller of this atom. Override this if you want to assign variables first. * diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index adf6ab80fef69..9c732c50bb8b5 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -382,16 +382,16 @@ note = null update_icon() -/obj/machinery/door/airlock/Bumped(atom/movable/AM) +/obj/machinery/door/airlock/Bumped(atom/movable/AM, mob/living/mobs) if(operating || (obj_flags & EMAGGED)) return if(ismecha(AM)) var/obj/vehicle/sealed/mecha/mecha = AM if(density) if(mecha.occupants) - if(world.time - mecha.occupants.last_bumped <= 10) + if(world.time - mobs.last_bumped <= 10) return - mecha.occupants.last_bumped = world.time + mobs.last_bumped = world.time if(locked && (allowed(mecha.occupants) || check_access_list(mecha.operation_req_access)) && aac) aac.request_from_door(src) return diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 16d183f64e064..e2d57cf84e806 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -450,14 +450,15 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/porta_turret) else if(check_anomalies) //non humans who are not simple animals (xenos etc) if(!in_faction(C)) targets += C + for(var/A in GLOB.mechas_list) if((get_dist(A, base) < scan_range) && can_see(base, A, scan_range)) - var/obj/vehicle/sealed/mecha/mech = A - for(var/O in mech.occupants) - var/mob/living/occupant = O - if(!in_faction(occupant)) //If there is a user and they're not in our faction - if(assess_perp(occupant) >= 4) - targets += mech + var/obj/vehicle/sealed/mecha/mech = A + for(var/O in mech.occupants) + var/mob/living/occupant = O + if(!in_faction(occupant)) //If there is a user and they're not in our faction + if(assess_perp(occupant) >= 4) + targets += mech if(check_anomalies && GLOB.blobs.len && (mode == TURRET_LETHAL)) for(var/obj/structure/blob/B in view(scan_range, T)) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 24e4d9ee9185d..a65272d3acd39 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -503,10 +503,10 @@ var/list/speech_bubble_recipients = list() for(var/mob/listener in get_hearers_in_view(7, src)) if(listener.client) - speech_bubble_recipients.Add(M.client) + speech_bubble_recipients += listener.client - var/image/mech_speech = image('icons/mob/effects/talk.dmi', src, "machine[say_test(speech_args[SPEECH_MESSAGE])]",MOB_LAYER+1) - INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay_global), mech_speech, speech_bubble_recipients, 3 SECONDS) + var/image/mech_speech = image('icons/mob/talk.dmi', src, "machine[say_test(speech_args[SPEECH_MESSAGE])]",MOB_LAYER+1) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), mech_speech, speech_bubble_recipients, 3 SECONDS) /obj/vehicle/sealed/mecha/on_emag(mob/user) ..() @@ -692,14 +692,13 @@ flick(phase_state, src) var/turf/target = get_step(src, dir) if(target.flags_1 & NOJAUNT_1) - occupant_message("Phasing anomaly detected, emergency deactivation initiated.") - sleep(step_in*3*step_multiplier) + to_chat(src, "Phasing anomaly detected, emergency deactivation initiated.") + sleep(movedelay*3*step_multiplier) phasing = FALSE return if(do_teleport(src, get_step(src, dir), no_effects = TRUE)) use_power(phasing_energy_drain) - addtimer(VARSET_CALLBACK(src, movedelay, TRUE), movedelay*3*step_multiplier)\ - return + addtimer(VARSET_CALLBACK(src, movedelay, TRUE), movedelay*3*step_multiplier) . = ..() if(.) //mech was thrown/door/whatever return @@ -1020,7 +1019,7 @@ log_game("[key_name(user)] has put the MMI/posibrain of [key_name(B)] into [src] at [AREACOORD(src)]") return TRUE -/obj/vehicle/sealed/mecha/container_resist_act(mob/living/user) +/obj/vehicle/sealed/mecha/container_resist(mob/living/user) if(isAI(user)) var/mob/living/silicon/ai/AI = user if(!AI.can_shunt) diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index ff9992c6d36d5..0751522dbad84 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -24,7 +24,7 @@ return if(!chassis || !(owner in chassis.occupants)) return - chassis.container_resist_act(owner) + chassis.container_resist(owner) /datum/action/vehicle/sealed/mecha/mech_toggle_internals name = "Toggle Internal Airtank Usage" diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index fd3911764ce94..b612d4afe1ee3 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -198,7 +198,7 @@ output += "
" return output -/obj/vehicle/sealed/mecha/working/ripley/relay_container_resist_act(mob/living/user, obj/O) +/obj/vehicle/sealed/mecha/working/ripley/relay_container_resist(mob/living/user, obj/O) to_chat(user, "You lean on the back of [O] and start pushing so it falls out of [src].") if(do_after(user, 300, target = O)) if(!user || user.stat != CONSCIOUS || user.loc != src || O.loc != src ) From 54a411ae8a0cb01e9cf70c11a41529895df4f87f Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 02:43:43 -0400 Subject: [PATCH 21/41] fix maps --- .../RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm | 4 +--- _maps/RandomRuins/SpaceRuins/mechtransport.dmm | 4 +--- _maps/RandomZLevels/caves.dmm | 4 +--- _maps/RandomZLevels/snowdin.dmm | 5 +---- _maps/RandomZLevels/spacebattle.dmm | 4 +--- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm index 6950eb4ac43ca..a4485e0b8c544 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm @@ -9,9 +9,7 @@ /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "d" = ( -/obj/vehicle/sealed/mecha/working/ripley/mining{ - ruin_mecha = 1 - }, +/obj/vehicle/sealed/mecha/working/ripley/mining, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "e" = ( diff --git a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm index 8c709f4b4f953..387bf8c59ec14 100644 --- a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm +++ b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm @@ -101,9 +101,7 @@ /turf/open/floor/mineral/titanium/yellow/airless, /area/ruin/space/has_grav/powered/mechtransport) "A" = ( -/obj/vehicle/sealed/mecha/working/ripley{ - ruin_mecha = 1 - }, +/obj/vehicle/sealed/mecha/working/ripley, /turf/open/floor/mineral/titanium/yellow/airless, /area/ruin/space/has_grav/powered/mechtransport) "B" = ( diff --git a/_maps/RandomZLevels/caves.dmm b/_maps/RandomZLevels/caves.dmm index 8ea1777a37b09..b1d42f210d6e0 100644 --- a/_maps/RandomZLevels/caves.dmm +++ b/_maps/RandomZLevels/caves.dmm @@ -2116,9 +2116,7 @@ }, /area/awaymission/caves/BMP_asteroid) "gC" = ( -/obj/vehicle/sealed/mecha/working/ripley/mining{ - ruin_mecha = 1 - }, +/obj/vehicle/sealed/mecha/working/ripley/mining, /turf/open/floor/plasteel/recharge_floor, /area/awaymission/caves/BMP_asteroid) "gD" = ( diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm index 91b1509e0a07a..6d7be173ac6ff 100644 --- a/_maps/RandomZLevels/snowdin.dmm +++ b/_maps/RandomZLevels/snowdin.dmm @@ -10932,10 +10932,7 @@ /turf/open/floor/plasteel/dark, /area/awaymission/snowdin/post/mining_main/mechbay) "In" = ( -/obj/vehicle/sealed/mecha/working/ripley/mining{ - dir = 1; - ruin_mecha = 1 - }, +/obj/vehicle/sealed/mecha/working/ripley/mining, /obj/effect/turf_decal/bot, /turf/open/floor/mech_bay_recharge_floor, /area/awaymission/snowdin/post/mining_main/mechbay) diff --git a/_maps/RandomZLevels/spacebattle.dmm b/_maps/RandomZLevels/spacebattle.dmm index bfebb690d9aef..d246db97cdce5 100644 --- a/_maps/RandomZLevels/spacebattle.dmm +++ b/_maps/RandomZLevels/spacebattle.dmm @@ -778,9 +778,7 @@ /turf/open/floor/plating, /area/awaymission/spacebattle/cruiser) "dL" = ( -/obj/vehicle/sealed/mecha/working/ripley/firefighter{ - ruin_mecha = 1 - }, +/obj/vehicle/sealed/mecha/working/ripley/firefighter /turf/open/floor/plating, /area/awaymission/spacebattle/cruiser) "dM" = ( From bb4a2609e33f613b20e2bcd3e929a6c82073922e Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 02:51:58 -0400 Subject: [PATCH 22/41] I think I inherited it right? --- code/modules/vehicles/mecha/_mecha.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index a65272d3acd39..44f990211301c 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -623,7 +623,7 @@ /obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move)) return FALSE - COOLDOWN_START(src, cooldown_vehicle_move, movedelay) + COOLDOWN_START(src, cooldown_vehicle_move, (movedelay * step_multiplier) + step_restricted) if(completely_disabled) return FALSE if(!direction) @@ -674,6 +674,7 @@ playsound(src,turnsound,40,TRUE) return TRUE + //set_glide_size(DELAY_TO_GLIDE_SIZE(movedelay)) //Otherwise just walk normally . = step(src,direction, dir) From 798b7dfc6826c0fbc626b0bbb6a7c5424827f367 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 03:16:00 -0400 Subject: [PATCH 23/41] https://github.com/tgstation/tgstation/pull/53470/ --- code/__DEFINES/mecha.dm | 9 +++ code/__DEFINES/vehicles.dm | 9 --- code/_globalvars/bitfields.dm | 17 +++++ code/modules/cargo/bounties/mech.dm | 4 +- code/modules/vehicles/mecha/_mecha.dm | 69 ++++++++++--------- .../mecha/equipment/tools/work_tools.dm | 2 +- .../mecha/equipment/weapons/weapons.dm | 2 +- code/modules/vehicles/mecha/mecha_wreckage.dm | 4 +- code/modules/vehicles/mecha/working/ripley.dm | 25 ++++--- code/modules/vehicles/sealed.dm | 5 +- 10 files changed, 87 insertions(+), 59 deletions(-) diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm index bf62e6b67ba1d..c94a6f2eeda30 100644 --- a/code/__DEFINES/mecha.dm +++ b/code/__DEFINES/mecha.dm @@ -4,6 +4,15 @@ #define MECHA_INT_TANK_BREACH (1<<3) #define MECHA_INT_CONTROL_LOST (1<<4) +//Mech flags +#define ADDING_ACCESS_POSSIBLE (1<<0) +#define ADDING_MAINT_ACCESS_POSSIBLE (1<<1) +#define CANSTRAFE (1<<2) +#define LIGHTS_ON (1<<3) +#define SILICON_PILOT (1<<4) +#define IS_ENCLOSED (1<<5) +#define HAS_LIGHTS (1<<6) + #define MECHA_MELEE (1 << 0) #define MECHA_RANGED (1 << 1) diff --git a/code/__DEFINES/vehicles.dm b/code/__DEFINES/vehicles.dm index 3c14abc593895..8710b4b2bc958 100644 --- a/code/__DEFINES/vehicles.dm +++ b/code/__DEFINES/vehicles.dm @@ -4,14 +4,5 @@ #define VEHICLE_CONTROL_DRIVE 2 #define VEHICLE_CONTROL_KIDNAPPED 4 //! Can't leave vehicle voluntarily, has to resist. -//Mech flags -#define ADDING_ACCESS_POSSIBLE (1<<0) -#define ADDING_MAINT_ACCESS_POSSIBLE (1<<1) -#define CANSTRAFE (1<<2) -#define LIGHTS_ON (1<<3) -#define SILICON_PILOT (1<<4) -#define IS_ENCLOSED (1<<5) -#define HAS_LIGHTS (1<<6) - //Car trait flags #define CAN_KIDNAP 1 diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index c626316f73a81..d01b929771bae 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -272,3 +272,20 @@ DEFINE_BITFIELD(trauma_flags, list( "CLONEABLE" = TRAUMA_CLONEABLE, "NOT_RANDOM" = TRAUMA_NOT_RANDOM, )) + +DEFINE_BITFIELD(internal_damage, list( + "MECHA_INT_FIRE" = MECHA_INT_FIRE, + "MECHA_INT_TEMP_CONTROL" = MECHA_INT_TEMP_CONTROL, + "MECHA_INT_TANK_BREACH" = MECHA_INT_TANK_BREACH, + "MECHA_INT_CONTROL_LOST" = MECHA_INT_CONTROL_LOST, +)) + +DEFINE_BITFIELD(mecha_flags, list( + "ADDING_ACCESS_POSSIBLE" = ADDING_ACCESS_POSSIBLE, + "ADDING_MAINT_ACCESS_POSSIBLE" = ADDING_MAINT_ACCESS_POSSIBLE, + "CANSTRAFE" = CANSTRAFE, + "LIGHTS_ON" = LIGHTS_ON, + "SILICON_PILOT" = SILICON_PILOT, + "IS_ENCLOSED" = IS_ENCLOSED, + "HAS_LIGHTS" = HAS_LIGHTS, +)) diff --git a/code/modules/cargo/bounties/mech.dm b/code/modules/cargo/bounties/mech.dm index 053c4817724df..32fa49d4bc940 100644 --- a/code/modules/cargo/bounties/mech.dm +++ b/code/modules/cargo/bounties/mech.dm @@ -13,10 +13,10 @@ /datum/bounty/item/mech/mark_high_priority(scale_reward) return ..(max(scale_reward * 0.7, 1.2)) -/datum/bounty/item/mech/ripleymkii +/datum/bounty/item/mech/ripleymk2 name = "APLU MK-II \"Ripley\"" reward = 13000 - wanted_types = list(/obj/vehicle/sealed/mecha/working/ripley/mkii) + wanted_types = list(/obj/vehicle/sealed/mecha/working/ripley/mk2) /datum/bounty/item/mech/firefighter name = "APLU \"Firefighter\"" diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 44f990211301c..62ba8bbd4c3da 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -31,7 +31,7 @@ light_system = MOVABLE_LIGHT light_on = FALSE light_power = 1 - light_range = 5 + light_range = 4 ///What direction will the mech face when entered/powered on? Defaults to South. var/dir_in = SOUTH ///How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain. @@ -263,7 +263,7 @@ mob_occupant.update_mouse_pointer() /obj/vehicle/sealed/mecha/CheckParts(list/parts_list) - ..() + . = ..() cell = locate(/obj/item/stock_parts/cell) in contents scanmod = locate(/obj/item/stock_parts/scanning_module) in contents capacitor = locate(/obj/item/stock_parts/capacitor) in contents @@ -667,8 +667,16 @@ if(!allow_diagonal_movement && ISDIAGONALDIR(direction)) return TRUE + var/keyheld = FALSE + if(strafe) + for(var/D in return_drivers()) + var/mob/driver = D + if(driver.client?.keys_held["Alt"]) + keyheld = TRUE + break + //if we're not facing the way we're going rotate us - if(dir != direction && !strafe || forcerotate) + if(dir != direction && !strafe || forcerotate || keyheld) setDir(direction) if(turnsound) playsound(src,turnsound,40,TRUE) @@ -680,10 +688,6 @@ . = step(src,direction, dir) if(strafe) - for(var/D in return_drivers()) - var/mob/driver = D - if(driver.client?.keys_held["Alt"]) - return setDir(olddir) @@ -793,7 +797,8 @@ to_chat(user, "Take control of exosuit?
") /obj/vehicle/sealed/mecha/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) - if(!..()) + . = ..() + if(!.) return //Transfer from core or card to mech. Proc is called by mech. @@ -818,15 +823,15 @@ AI.remote_control = null to_chat(AI, "You have been downloaded to a mobile storage device. Wireless connection offline.") to_chat(user, "Transfer successful: [AI.name] ([rand(1000,9999)].exe) removed from [name] and stored within local memory.") + return if(AI_MECH_HACK) //Called by AIs on the mech AI.linked_core = new /obj/structure/AIcore/deactivated(AI.loc) - if(AI.can_dominate_mechs) - if(LAZYLEN(occupants)) //Oh, I am sorry, were you using that? - to_chat(AI, "Occupants detected! Forced ejection initiated!") - to_chat(occupants, "You have been forcibly ejected!") - ejectall() //IT IS MINE, NOW. SUCK IT, RD! - ai_enter_mech(AI, interaction) + if(AI.can_dominate_mechs && LAZYLEN(occupants)) //Oh, I am sorry, were you using that? + to_chat(AI, "Occupants detected! Forced ejection initiated!") + to_chat(occupants, "You have been forcibly ejected!") + ejectall() //IT IS MINE, NOW. SUCK IT, RD! + AI.can_shunt = FALSE //ONE AI ENTERS. NO AI LEAVES. if(AI_TRANS_FROM_CARD) //Using an AI card to upload to a mech. AI = card.AI @@ -845,10 +850,10 @@ AI.radio_enabled = TRUE to_chat(user, "Transfer successful: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed.") card.AI = null - ai_enter_mech(AI, interaction) + ai_enter_mech(AI) //Hack and From Card interactions share some code, so leave that here for both to use. -/obj/vehicle/sealed/mecha/proc/ai_enter_mech(mob/living/silicon/ai/AI, interaction) +/obj/vehicle/sealed/mecha/proc/ai_enter_mech(mob/living/silicon/ai/AI) AI.ai_restore_power() mecha_flags |= SILICON_PILOT moved_inside(AI) @@ -856,8 +861,6 @@ AI.controlled_mech = src AI.remote_control = src AI.mobility_flags = ALL //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow. - if(interaction == AI_MECH_HACK) - AI.can_shunt = FALSE //ONE AI ENTERS. NO AI LEAVES. to_chat(AI, AI.can_dominate_mechs ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!" :\ "You have been uploaded to a mech's onboard computer.") to_chat(AI, "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions.") @@ -960,21 +963,20 @@ initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats) initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe) -/obj/vehicle/sealed/mecha/proc/moved_inside(mob/living/H) - . = FALSE - if(!(H?.client)) - return - if(ishuman(H) && !Adjacent(H)) - return - add_occupant(H) - H.forceMove(src) - H.update_mouse_pointer() - add_fingerprint(H) - log_message("[H] moved in as pilot.", LOG_MECHA) +/obj/vehicle/sealed/mecha/proc/moved_inside(mob/living/newoccupant) + if(!(newoccupant?.client)) + return FALSE + if(ishuman(newoccupant) && !Adjacent(newoccupant)) + return FALSE + add_occupant(newoccupant) + newoccupant.forceMove(src) + newoccupant.update_mouse_pointer() + add_fingerprint(newoccupant) + log_message("[newoccupant] moved in as pilot.", LOG_MECHA) setDir(dir_in) playsound(src, 'sound/machines/windowdoor.ogg', 50, TRUE) if(!internal_damage) - SEND_SOUND(H, sound('sound/mecha/nominal.ogg',volume=50)) + SEND_SOUND(newoccupant, sound('sound/mecha/nominal.ogg',volume=50)) return TRUE /obj/vehicle/sealed/mecha/proc/mmi_move_inside(obj/item/mmi/M, mob/user) @@ -1082,7 +1084,6 @@ mmi.mecha = null mmi.update_icon() L.mobility_flags = NONE - update_icon() setDir(dir_in) return ..() @@ -1091,21 +1092,21 @@ RegisterSignal(M, COMSIG_MOB_DEATH, .proc/mob_exit) RegisterSignal(M, COMSIG_MOB_CLICKON, .proc/on_mouseclick) RegisterSignal(M, COMSIG_MOB_SAY, .proc/display_speech_bubble) + . = ..() update_icon() - return ..() /obj/vehicle/sealed/mecha/remove_occupant(mob/M) UnregisterSignal(M, COMSIG_MOB_DEATH) UnregisterSignal(M, COMSIG_MOB_CLICKON) UnregisterSignal(M, COMSIG_MOB_SAY) - update_icon() M.clear_alert("charge") M.clear_alert("mech damage") if(M.client) M.update_mouse_pointer() M.client.view_size.resetToDefault() zoom_mode = 0 - return ..() + . = ..() + update_icon() ///////////////////////// ////// Access stuff ///// diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index eeb3592b20289..61aa3206b583d 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -497,7 +497,7 @@ return TRUE /obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/vehicle/sealed/mecha/M) - var/obj/vehicle/sealed/mecha/working/ripley/mkii/N = new /obj/vehicle/sealed/mecha/working/ripley/mkii(get_turf(M),1) + var/obj/vehicle/sealed/mecha/working/ripley/mk2/N = new (get_turf(M),1) if(!N) return QDEL_NULL(N.cell) diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 856d912b4194c..6a8acdedb4dc1 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -49,7 +49,7 @@ if(kickback) chassis.newtonian_move(newtonian_target) chassis.log_message("Fired from [src.name], targeting [target].", LOG_MECHA) - return ..() + return //Base energy weapon type /obj/item/mecha_parts/mecha_equipment/weapon/energy diff --git a/code/modules/vehicles/mecha/mecha_wreckage.dm b/code/modules/vehicles/mecha/mecha_wreckage.dm index 12455e6546abe..fe4c5f03b894b 100644 --- a/code/modules/vehicles/mecha/mecha_wreckage.dm +++ b/code/modules/vehicles/mecha/mecha_wreckage.dm @@ -161,11 +161,11 @@ welder_salvage += part parts -= part -/obj/structure/mecha_wreckage/ripley/mkii +/obj/structure/mecha_wreckage/ripley/mk2 name = "\improper Ripley MK-II wreckage" icon_state = "ripleymkii-broken" -/obj/structure/mecha_wreckage/ripley/mkii/Initialize(mapload) +/obj/structure/mecha_wreckage/ripley/mk2/Initialize(mapload) . = ..() var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso, /obj/item/mecha_parts/part/ripley_left_arm, diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index b612d4afe1ee3..01a9efe1e420d 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -36,13 +36,12 @@ if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) //we can reach it and it's in front of us? grab it! ore.forceMove(ore_box) -/obj/vehicle/sealed/mecha/working/ripley/mob_exit(mob/M, silent, forced) - ..() - update_icon() - -/obj/vehicle/sealed/mecha/working/ripley/moved_inside(mob/living/carbon/human/H) - ..() - update_icon() +/obj/vehicle/sealed/mecha/working/ripley/generate_actions() //isnt allowed to have internal air + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe) /obj/vehicle/sealed/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage, ignore_threshold = FALSE) if (!enclosed) @@ -61,7 +60,7 @@ cargo.Cut() return ..() -/obj/vehicle/sealed/mecha/working/ripley/mkii +/obj/vehicle/sealed/mecha/working/ripley/mk2 desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection" name = "\improper APLU MK-II \"Ripley\"" icon_state = "ripleymkii" @@ -70,11 +69,19 @@ slow_pressure_step_in = 3 //step_in while in normal pressure conditions movedelay = 4 armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) - wreckage = /obj/structure/mecha_wreckage/ripley/mkii + wreckage = /obj/structure/mecha_wreckage/ripley/mk2 enclosed = TRUE enter_delay = 40 silicon_icon_state = null +/obj/vehicle/sealed/mecha/working/ripley/mk2/generate_actions() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe) + /obj/vehicle/sealed/mecha/working/ripley/firefighter desc = "Autonomous Power Loader Unit MK-III. This model is refitted with a pressurized cabin and additional hazard protection." name = "\improper APLU MK-III \"Firefighter\"" diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index 052a32cdec398..b938d6bc32963 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -97,9 +97,12 @@ user.put_in_hands(inserted_key) inserted_key = null +/obj/vehicle/sealed/obj_destruction(damage_flag) + explosion(loc, 0, 1, 2, 3, 0) + return ..() + /obj/vehicle/sealed/Destroy() DumpMobs() - explosion(loc, 0, 1, 2, 3, 0) return ..() /obj/vehicle/sealed/proc/DumpMobs(randomstep = TRUE) From 2dc0304d4e16da739381e3bf48afc9f7d70c99e6 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 12 Oct 2023 05:17:52 -0400 Subject: [PATCH 24/41] hacky bs lmaooo --- code/modules/vehicles/_vehicle.dm | 1 + code/modules/vehicles/mecha/_mecha.dm | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm index 593c84a1f2d83..820715d677745 100644 --- a/code/modules/vehicles/_vehicle.dm +++ b/code/modules/vehicles/_vehicle.dm @@ -8,6 +8,7 @@ density = TRUE anchored = FALSE COOLDOWN_DECLARE(cooldown_vehicle_move) + COOLDOWN_DECLARE(cooldown_vehicle_move_two) var/list/mob/occupants //mob = bitflags of their control level. var/max_occupants = 1 var/max_drivers = 1 diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 62ba8bbd4c3da..d7d69711dfae2 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -28,6 +28,7 @@ anchored = TRUE emulate_door_bumps = TRUE COOLDOWN_DECLARE(mecha_bump_smash) + light_system = MOVABLE_LIGHT light_on = FALSE light_power = 1 @@ -621,9 +622,10 @@ return FALSE /obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) - if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move)) + if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move_two)) return FALSE - COOLDOWN_START(src, cooldown_vehicle_move, (movedelay * step_multiplier) + step_restricted) + COOLDOWN_START(src, cooldown_vehicle_move, (movedelay * step_multiplier)) + COOLDOWN_START(src, cooldown_vehicle_move_two, COOLDOWN_TIMELEFT(src, cooldown_vehicle_move) + step_restricted) if(completely_disabled) return FALSE if(!direction) From 5acfc9f40a282c6c8d2f5e4de7b98f81b643f5a9 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:03:57 -0500 Subject: [PATCH 25/41] fix bad cooldown --- code/modules/vehicles/_vehicle.dm | 1 - code/modules/vehicles/mecha/_mecha.dm | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm index 820715d677745..593c84a1f2d83 100644 --- a/code/modules/vehicles/_vehicle.dm +++ b/code/modules/vehicles/_vehicle.dm @@ -8,7 +8,6 @@ density = TRUE anchored = FALSE COOLDOWN_DECLARE(cooldown_vehicle_move) - COOLDOWN_DECLARE(cooldown_vehicle_move_two) var/list/mob/occupants //mob = bitflags of their control level. var/max_occupants = 1 var/max_drivers = 1 diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index d7d69711dfae2..bf924d9f769ce 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -28,7 +28,7 @@ anchored = TRUE emulate_door_bumps = TRUE COOLDOWN_DECLARE(mecha_bump_smash) - + light_system = MOVABLE_LIGHT light_on = FALSE light_power = 1 @@ -622,10 +622,9 @@ return FALSE /obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) - if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move_two)) + if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move)) return FALSE - COOLDOWN_START(src, cooldown_vehicle_move, (movedelay * step_multiplier)) - COOLDOWN_START(src, cooldown_vehicle_move_two, COOLDOWN_TIMELEFT(src, cooldown_vehicle_move) + step_restricted) + COOLDOWN_START(src, cooldown_vehicle_move, COOLDOWN_TIMELEFT(src, cooldown_vehicle_move) + step_restricted) if(completely_disabled) return FALSE if(!direction) From 9f3d2d046553e0c73b400c4fe37932911a7ee8e9 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:08:32 -0500 Subject: [PATCH 26/41] add back ripley --- code/datums/components/armor_plate.dm | 4 +- code/game/turfs/turf_integrity.dm | 2 +- .../simple_animal/hostile/megafauna/drake.dm | 2 +- code/modules/vehicles/mecha/working/ripley.dm | 235 ++++++++++++++++++ 4 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 code/modules/vehicles/mecha/working/ripley.dm diff --git a/code/datums/components/armor_plate.dm b/code/datums/components/armor_plate.dm index 9e977af51de59..773716e61e687 100644 --- a/code/datums/components/armor_plate.dm +++ b/code/datums/components/armor_plate.dm @@ -12,7 +12,7 @@ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(examine)) RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(applyplate)) RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, PROC_REF(dropplates)) - if(istype(parent, /obj/mecha/working/ripley)) + if(istype(parent, /obj/vehicle/sealed/mecha/working/ripley)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(apply_mech_overlays)) if(_maxamount) @@ -85,7 +85,7 @@ for(var/i in 1 to amount) new upgrade_item(get_turf(parent)) -/datum/component/armor_plate/proc/apply_mech_overlays(obj/mecha/mech, list/overlays) +/datum/component/armor_plate/proc/apply_mech_overlays(obj/vehicle/sealed/mecha/mech, list/overlays) SIGNAL_HANDLER if(amount) diff --git a/code/game/turfs/turf_integrity.dm b/code/game/turfs/turf_integrity.dm index add791ee2c6e9..7c65f54de265b 100644 --- a/code/game/turfs/turf_integrity.dm +++ b/code/game/turfs/turf_integrity.dm @@ -318,7 +318,7 @@ // Mechs //==================================== -/turf/mech_melee_attack(obj/mecha/M) +/turf/mech_melee_attack(obj/vehicle/sealed/mecha/M) if (!can_hit) return FALSE M.do_attack_animation(src) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 5489c9516c566..0c45954db43dc 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -361,7 +361,7 @@ Difficulty: Medium var/throwtarget = get_edge_target_turf(src, throw_dir) L.throw_at(throwtarget, 3) visible_message("[L] is thrown clear of [src]!") - for(var/obj/mecha/M in orange(1, src)) + for(var/obj/vehicle/sealed/mecha/M in orange(1, src)) M.take_damage(75, BRUTE, MELEE, 1) for(var/mob/M in range(7, src)) diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm new file mode 100644 index 0000000000000..01a9efe1e420d --- /dev/null +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -0,0 +1,235 @@ +/obj/vehicle/sealed/mecha/working/ripley + desc = "Autonomous Power Loader Unit MK-I. Designed primarily around heavy lifting, the Ripley can be outfitted with utility equipment to fill a number of roles." + name = "\improper APLU MK-I \"Ripley\"" + icon_state = "ripley" + base_icon_state = "ripley" + silicon_icon_state = "ripley-empty" + movedelay = 1.5 //Move speed, lower is faster. + var/fast_pressure_step_in = 1.5 //step_in while in low pressure conditions + var/slow_pressure_step_in = 2.0 //step_in while in normal pressure conditions + max_temperature = 20000 + max_integrity = 200 + lights_power = 7 + deflect_chance = 15 + armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 0) + max_equip = 6 + wreckage = /obj/structure/mecha_wreckage/ripley + internals_req_access = list(ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_MINING) + var/list/cargo = new + var/cargo_capacity = 15 + var/hides = 0 + enclosed = FALSE //Normal ripley has an open cockpit design + enter_delay = 10 //can enter in a quarter of the time of other mechs + exit_delay = 10 + +/obj/vehicle/sealed/mecha/working/ripley/Move() + . = ..() + if(.) + collect_ore() + update_pressure() + +/obj/vehicle/sealed/mecha/working/ripley/proc/collect_ore() + if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in cargo + if(ore_box) + for(var/obj/item/stack/ore/ore in range(1, src)) + if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) //we can reach it and it's in front of us? grab it! + ore.forceMove(ore_box) + +/obj/vehicle/sealed/mecha/working/ripley/generate_actions() //isnt allowed to have internal air + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe) + +/obj/vehicle/sealed/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage, ignore_threshold = FALSE) + if (!enclosed) + possible_int_damage -= (MECHA_INT_TEMP_CONTROL + MECHA_INT_TANK_BREACH) //if we don't even have an air tank, these two doesn't make a ton of sense. + . = ..() + + +/obj/vehicle/sealed/mecha/working/ripley/Initialize(mapload) + . = ..() + AddComponent(/datum/component/armor_plate,3,/obj/item/stack/sheet/animalhide/goliath_hide,list(MELEE = 10, BULLET = 5, LASER = 5)) + +/obj/vehicle/sealed/mecha/working/ripley/Destroy() + for(var/atom/movable/A in cargo) + A.forceMove(drop_location()) + step_rand(A) + cargo.Cut() + return ..() + +/obj/vehicle/sealed/mecha/working/ripley/mk2 + desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection" + name = "\improper APLU MK-II \"Ripley\"" + icon_state = "ripleymkii" + base_icon_state = "ripleymkii" + fast_pressure_step_in = 1.75 //step_in while in low pressure conditions + slow_pressure_step_in = 3 //step_in while in normal pressure conditions + movedelay = 4 + armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) + wreckage = /obj/structure/mecha_wreckage/ripley/mk2 + enclosed = TRUE + enter_delay = 40 + silicon_icon_state = null + +/obj/vehicle/sealed/mecha/working/ripley/mk2/generate_actions() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/strafe) + +/obj/vehicle/sealed/mecha/working/ripley/firefighter + desc = "Autonomous Power Loader Unit MK-III. This model is refitted with a pressurized cabin and additional hazard protection." + name = "\improper APLU MK-III \"Firefighter\"" + icon_state = "firefighter" + base_icon_state = "firefighter" + max_temperature = 65000 + max_integrity = 250 + fast_pressure_step_in = 2 //step_in while in low pressure conditions + slow_pressure_step_in = 4 //step_in while in normal pressure conditions + movedelay = 4 + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + rad_flags = RAD_PROTECT_CONTENTS + lights_power = 7 + armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 0) + max_equip = 5 // More armor, less tools + wreckage = /obj/structure/mecha_wreckage/ripley/firefighter + enclosed = TRUE + enter_delay = 40 + silicon_icon_state = null + + +/obj/vehicle/sealed/mecha/working/ripley/deathripley + desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE" + name = "\improper DEATH-RIPLEY" + icon_state = "deathripley" + base_icon_state = "deathripley" + fast_pressure_step_in = 2 //step_in while in low pressure conditions + slow_pressure_step_in = 4 //step_in while in normal pressure conditions + movedelay = 4 + slow_pressure_step_in = 3 + lights_power = 7 + wreckage = /obj/structure/mecha_wreckage/ripley/deathripley + step_energy_drain = 0 + enclosed = TRUE + enter_delay = 40 + silicon_icon_state = null + +/obj/vehicle/sealed/mecha/working/ripley/deathripley/Initialize(mapload) + . = ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill + ME.attach(src) + +/obj/vehicle/sealed/mecha/working/ripley/deathripley/real + desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE. FOR REAL" + +/obj/vehicle/sealed/mecha/working/ripley/deathripley/real/Initialize(mapload) + . = ..() + for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) + E.detach() + qdel(E) + LAZYCLEARLIST(equipment) + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/real + ME.attach(src) + +/obj/vehicle/sealed/mecha/working/ripley/mining + desc = "An old, dusty mining Ripley." + name = "\improper APLU \"Miner\"" + obj_integrity = 75 //Low starting health + +/obj/vehicle/sealed/mecha/working/ripley/mining/Initialize(mapload) + . = ..() + if(cell) + cell.charge = FLOOR(cell.charge * 0.25, 1) //Starts at very low charge + if(prob(70)) //Maybe add a drill + if(prob(15)) //Possible diamond drill... Feeling lucky? + var/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill/D = new + D.attach(src) + else + var/obj/item/mecha_parts/mecha_equipment/drill/D = new + D.attach(src) + + else //Add plasma cutter if no drill + var/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/P = new + P.attach(src) + + //Add ore box to cargo + cargo.Add(new /obj/structure/ore_box(src)) + + //Attach hydraulic clamp + var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new + HC.attach(src) + for(var/obj/item/mecha_parts/mecha_tracking/B in trackers)//Deletes the beacon so it can't be found easily + qdel(B) + + var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new + scanner.attach(src) + +/obj/vehicle/sealed/mecha/working/ripley/Exit(atom/movable/O) + if(O in cargo) + return 0 + return ..() + +/obj/vehicle/sealed/mecha/working/ripley/Topic(href, href_list) + ..() + if(href_list["drop_from_cargo"]) + var/obj/O = locate(href_list["drop_from_cargo"]) in cargo + if(O) + to_chat(occupants, "[icon2html(src, occupants)]You unload [O].") + O.forceMove(drop_location()) + cargo -= O + log_message("Unloaded [O]. Cargo compartment capacity: [cargo_capacity - src.cargo.len]", LOG_MECHA) + return + + +/obj/vehicle/sealed/mecha/working/ripley/contents_explosion(severity, target) + for(var/X in cargo) + var/obj/O = X + if(prob(30/severity)) + cargo -= O + O.forceMove(drop_location()) + . = ..() + +/obj/vehicle/sealed/mecha/working/ripley/get_stats_part() + var/output = ..() + output += "Cargo Compartment Contents:
" + if(cargo.len) + for(var/obj/O in cargo) + output += "Unload : [O]
" + else + output += "Nothing" + output += "
" + return output + +/obj/vehicle/sealed/mecha/working/ripley/relay_container_resist(mob/living/user, obj/O) + to_chat(user, "You lean on the back of [O] and start pushing so it falls out of [src].") + if(do_after(user, 300, target = O)) + if(!user || user.stat != CONSCIOUS || user.loc != src || O.loc != src ) + return + to_chat(user, "You successfully pushed [O] out of [src]!") + O.forceMove(drop_location()) + cargo -= O + else + if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded. + to_chat(user, "You fail to push [O] out of [src]!") + +/** + * Makes the mecha go faster and halves the mecha drill cooldown if in Lavaland pressure. + * + * Checks for Lavaland pressure, if that works out the mech's speed is equal to fast_pressure_step_in and the cooldown for the mecha drill is halved. If not it uses slow_pressure_step_in and drill cooldown is normal. + */ +/obj/vehicle/sealed/mecha/working/ripley/proc/update_pressure() + var/turf/T = get_turf(loc) + + if(lavaland_equipment_pressure_check(T)) + movedelay = fast_pressure_step_in + for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) + drill.equip_cooldown = initial(drill.equip_cooldown)/2 + else + movedelay = slow_pressure_step_in + for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) + drill.equip_cooldown = initial(drill.equip_cooldown) From 9f428903456b50569d8cedb9262b0c82c7e570a6 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:09:54 -0500 Subject: [PATCH 27/41] occupants --- code/datums/components/armor_plate.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/armor_plate.dm b/code/datums/components/armor_plate.dm index 773716e61e687..74a20a7e725a6 100644 --- a/code/datums/components/armor_plate.dm +++ b/code/datums/components/armor_plate.dm @@ -92,6 +92,6 @@ var/overlay_string = "ripley-g" if(amount >= 3) overlay_string += "-full" - if(!LAZYLEN(mech.occupant)) + if(!LAZYLEN(mech.occupants)) overlay_string += "-open" overlays += overlay_string From 9c2d1d8bb3295c3814f799d06b486cc3c5c5d9bd Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:19:15 -0500 Subject: [PATCH 28/41] 515 --- .../living/simple_animal/hostile/mecha_pilot.dm | 6 +++--- code/modules/vehicles/mecha/_mecha.dm | 14 +++++++------- code/modules/vehicles/mecha/combat/durand.dm | 6 ++++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm index cf3b1e9ba087e..48af70c824969 100644 --- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm +++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm @@ -65,7 +65,7 @@ if(spawn_mecha_type) var/obj/vehicle/sealed/mecha/M = new spawn_mecha_type (get_turf(src)) if(istype(M)) - INVOKE_ASYNC(src, .proc/enter_mecha, M) + INVOKE_ASYNC(src, PROC_REF(enter_mecha), M) /mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/enter_mecha(obj/vehicle/sealed/mecha/M) @@ -233,7 +233,7 @@ if(LAZYACCESSASSOC(mecha.occupant_actions, src, /datum/action/vehicle/sealed/mecha/mech_defense_mode) && !mecha.defense_mode) var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_defense_mode] action.Trigger(TRUE) - addtimer(CALLBACK(action, /datum/action/vehicle/sealed/mecha/mech_defense_mode.proc/Trigger, FALSE), 100) //10 seconds of defense, then toggle off + addtimer(CALLBACK(action, TYPE_PROC_REF(/datum/action/vehicle/sealed/mecha/mech_defense_mode, Trigger), FALSE), 100) //10 seconds of defense, then toggle off else if(prob(retreat_chance)) //Speed boost if possible @@ -241,7 +241,7 @@ var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_overload_mode] mecha.leg_overload_mode = FALSE action.Trigger(TRUE) - addtimer(CALLBACK(action, /datum/action/vehicle/sealed/mecha/mech_overload_mode.proc/Trigger, FALSE), 100) //10 seconds of speeeeed, then toggle off + addtimer(CALLBACK(action, TYPE_PROC_REF(/datum/action/vehicle/sealed/mecha/mech_overload_mode, Trigger), FALSE), 100) //10 seconds of speeeeed, then toggle off retreat_distance = 50 addtimer(VARSET_CALLBACK(src, retreat_distance, 0), 10 SECONDS) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index bf924d9f769ce..80080504429d4 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -178,8 +178,8 @@ add_cabin() if(enclosed) add_airtank() - RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE , .proc/disconnect_air) - RegisterSignal(src, COMSIG_MOVABLE_MOVED, .proc/play_stepsound) + RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE , PROC_REF(disconnect_air)) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(play_stepsound)) spark_system.set_up(2, 0, src) spark_system.attach(src) smoke_system.set_up(3, src) @@ -558,13 +558,13 @@ if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful) to_chat(L, "You don't want to harm other living beings!") return - INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, params) + INVOKE_ASYNC(selected, TYPE_PROC_REF(/obj/item/mecha_parts/mecha_equipment, action), user, target, params) return if((selected.range & MECHA_MELEE) && Adjacent(target)) if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM)) to_chat(L, "You don't want to harm other living beings!") return - INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, params) + INVOKE_ASYNC(selected, TYPE_PROC_REF(/obj/item/mecha_parts/mecha_equipment, action), user, target, params) return if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK) || !istype(target, /atom) || !Adjacent(target)) return @@ -1090,9 +1090,9 @@ /obj/vehicle/sealed/mecha/add_occupant(mob/M, control_flags) - RegisterSignal(M, COMSIG_MOB_DEATH, .proc/mob_exit) - RegisterSignal(M, COMSIG_MOB_CLICKON, .proc/on_mouseclick) - RegisterSignal(M, COMSIG_MOB_SAY, .proc/display_speech_bubble) + RegisterSignal(M, COMSIG_MOB_DEATH, PROC_REF(mob_exit)) + RegisterSignal(M, COMSIG_MOB_CLICKON, PROC_REF(on_mouseclick)) + RegisterSignal(M, COMSIG_MOB_SAY, PROC_REF(display_speech_bubble)) . = ..() update_icon() diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm index e540ad05dc085..feeb5f59f125f 100644 --- a/code/modules/vehicles/mecha/combat/durand.dm +++ b/code/modules/vehicles/mecha/combat/durand.dm @@ -55,7 +55,7 @@ if(defense_mode) var/datum/action/action = LAZYACCESSASSOC(occupant_actions, M, /datum/action/vehicle/sealed/mecha/mech_defense_mode) if(action) - INVOKE_ASYNC(action, /datum/action.proc/Trigger, FALSE) + INVOKE_ASYNC(action, TYPE_PROC_REF(/datum/action, Trigger), FALSE) return ..() ///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA. @@ -207,7 +207,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe playsound(src, 'sound/mecha/mech_shield_raise.ogg', 50, FALSE) set_light(l_range = MINIMUM_USEFUL_LIGHT_RANGE , l_power = 5, l_color = "#00FFFF") icon_state = "shield" - RegisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE, .proc/resetdir) + RegisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE, PROC_REF(resetdir)) else flick("shield_drop", src) playsound(src, 'sound/mecha/mech_shield_drop.ogg', 50, FALSE) @@ -218,6 +218,8 @@ own integrity back to max. Shield is automatically dropped if we run out of powe switching = FALSE /obj/durand_shield/proc/resetdir(datum/source, olddir, newdir) + SIGNAL_HANDLER + setDir(newdir) /obj/durand_shield/take_damage() From efa128049ee31b16473096cd90f013e1a6954952 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Thu, 16 Nov 2023 09:41:40 -0500 Subject: [PATCH 29/41] guh --- code/modules/vehicles/mecha/_mecha.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 80080504429d4..4586dcb6363ae 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -624,7 +624,8 @@ /obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move)) return FALSE - COOLDOWN_START(src, cooldown_vehicle_move, COOLDOWN_TIMELEFT(src, cooldown_vehicle_move) + step_restricted) + COOLDOWN_START(src, cooldown_vehicle_move, movedelay + step_restricted) + step_restricted = 0 if(completely_disabled) return FALSE if(!direction) From 04e12a6ccddbc017fae92d9c5528fb236b2fe820 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 7 Dec 2023 12:54:14 -0500 Subject: [PATCH 30/41] remove backslashes --- code/modules/vehicles/mecha/_mecha.dm | 38 ++++++++++---------- code/modules/vehicles/mecha/mecha_actions.dm | 2 +- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 4586dcb6363ae..e592a72ee8131 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -1,22 +1,22 @@ -//////////////////WELCOME TO MECHA.DM, ENJOY YOUR STAY\\\\\\\\\\\\\\\\\ +/***************** WELCOME TO MECHA.DM, ENJOY YOUR STAY *****************/ /** - * Mechs are now (finally) vehicles, this means you can make them multicrew - * They can also grant select ability buttons based on occupant bitflags - * - * Movement is handled through vehicle_move() which is called by relaymove - * Clicking is done by way of signals registering to the entering mob - * NOTE: MMIS are NOT mobs but instead contain a brain that is, so you need special checks - * AI also has special checks becaus it gets in and out of the mech differently - * Always call remove_occupant(mob) when leaving the mech so the mob is removed properly - * - * For multi-crew, you need to set how the occupants recieve ability bitflags corresponding to their status on the vehicle(i.e: driver, gunner etc) - * Abilities can then be set to only apply for certain bitflags and are assigned as such automatically - * - * Clicks are wither translated into mech_melee_attack (see mech_melee_attack.dm) - * Or are used to call action() on equipped gear - * Cooldown for gear is on the mech because exploits - */ + * Mechs are now (finally) vehicles, this means you can make them multicrew + * They can also grant select ability buttons based on occupant bitflags + * + * Movement is handled through vehicle_move() which is called by relaymove + * Clicking is done by way of signals registering to the entering mob + * NOTE: MMIS are NOT mobs but instead contain a brain that is, so you need special checks + * AI also has special checks becaus it gets in and out of the mech differently + * Always call remove_occupant(mob) when leaving the mech so the mob is removed properly + * + * For multi-crew, you need to set how the occupants recieve ability bitflags corresponding to their status on the vehicle(i.e: driver, gunner etc) + * Abilities can then be set to only apply for certain bitflags and are assigned as such automatically + * + * Clicks are wither translated into mech_melee_attack (see mech_melee_attack.dm) + * Or are used to call action() on equipped gear + * Cooldown for gear is on the mech because exploits + */ /obj/vehicle/sealed/mecha name = "mecha" desc = "Exosuit" @@ -28,7 +28,6 @@ anchored = TRUE emulate_door_bumps = TRUE COOLDOWN_DECLARE(mecha_bump_smash) - light_system = MOVABLE_LIGHT light_on = FALSE light_power = 1 @@ -180,10 +179,13 @@ add_airtank() RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE , PROC_REF(disconnect_air)) RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(play_stepsound)) + spark_system.set_up(2, 0, src) spark_system.attach(src) + smoke_system.set_up(3, src) smoke_system.attach(src) + add_cell() add_scanmod() add_capacitor() diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index 0751522dbad84..257668dba141d 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -1,4 +1,4 @@ -//////////////////////MECHA ACTIONS\\\\\\\\\\\\\\\\\\\\\ +/***************** MECHA ACTIONS *****************/ /obj/vehicle/sealed/mecha/generate_action_type() . = ..() From 14a5426eba73d321d0915a7664b1f3a9fa148f32 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 7 Dec 2023 13:16:59 -0500 Subject: [PATCH 31/41] retry --- _maps/RandomZLevels/spacebattle.dmm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/_maps/RandomZLevels/spacebattle.dmm b/_maps/RandomZLevels/spacebattle.dmm index 19fa853653ebb..dfb119c24c95c 100644 --- a/_maps/RandomZLevels/spacebattle.dmm +++ b/_maps/RandomZLevels/spacebattle.dmm @@ -777,10 +777,6 @@ /obj/vehicle/sealed/mecha/medical/odysseus, /turf/open/floor/plating, /area/awaymission/spacebattle/cruiser) -"dL" = ( -/obj/vehicle/sealed/mecha/working/ripley/firefighter -/turf/open/floor/plating, -/area/awaymission/spacebattle/cruiser) "dM" = ( /obj/structure/closet/crate{ name = "Gold Crate" @@ -28026,8 +28022,8 @@ cc cA cc bT -dL -dL +cK +cK cK cK cK From d3d8feaa32eccd44e230897c4009258d86660dd7 Mon Sep 17 00:00:00 2001 From: RKz Date: Sun, 10 Dec 2023 18:29:16 -0500 Subject: [PATCH 32/41] https://github.com/tgstation/tgstation/pull/53624 --- code/modules/cargo/centcom_podlauncher.dm | 6 ++-- code/modules/cargo/supplypod.dm | 28 ++++++++-------- code/modules/vehicles/mecha/_mecha.dm | 32 ++++++++++++------- code/modules/vehicles/mecha/mecha_actions.dm | 2 +- .../tgui/interfaces/CentcomPodLauncher.js | 11 +++++-- 5 files changed, 48 insertions(+), 31 deletions(-) diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index ef0dc5b3b1b78..5b0fa37365a16 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -157,7 +157,7 @@ data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here data["effectBurst"] = effectBurst //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom - data["reverseOptionList"] = temp_pod.reverseOptionList + data["reverse_option_list"] = temp_pod.reverse_option_list data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) data["podName"] = temp_pod.name @@ -387,7 +387,7 @@ . = TRUE if("reverseOption") var/reverseOption = params["reverseOption"] - temp_pod.reverseOptionList[reverseOption] = !temp_pod.reverseOptionList[reverseOption] + temp_pod.reverse_option_list[reverseOption] = !temp_pod.reverse_option_list[reverseOption] . = TRUE if("effectTarget") //Toggle: Launch at a specific mob (instead of at whatever turf you click on). Used for the supplypod smite if (specificTarget) @@ -840,7 +840,7 @@ temp_pod.effectCircle = dataToLoad["effectCircle"] //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here effectBurst = dataToLoad["effectBurst"] //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area temp_pod.reversing = dataToLoad["effectReverse"] //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom - temp_pod.reverseOptionList = dataToLoad["reverseOptionList"] + temp_pod.reverse_option_list = dataToLoad["reverse_option_list"] specificTarget = dataToLoad["effectTarget"] //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites temp_pod.adminNamed = dataToLoad["effectName"] //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) temp_pod.name = dataToLoad["podName"] diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index 3996b929e3bd5..675b9dd87b553 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -56,7 +56,7 @@ var/effectShrapnel = FALSE var/shrapnel_type = /obj/projectile/bullet/shrapnel var/shrapnel_magnitude = 3 - var/list/reverseOptionList = list("Mobs"=FALSE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE) + var/list/reverse_option_list = list("Mobs"=FALSE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE, "Mecha"=FALSE) var/list/turfs_in_cargo = list() /obj/structure/closet/supplypod/bluespacepod @@ -358,7 +358,7 @@ if(to_insert.invisibility == INVISIBILITY_ABSTRACT) return FALSE if(ismob(to_insert)) - if(!reverseOptionList["Mobs"]) + if(!reverse_option_list["Mobs"]) return FALSE if(!isliving(to_insert)) //let's not put ghosts or camera mobs inside return FALSE @@ -377,30 +377,30 @@ return FALSE if(istype(obj_to_insert, /obj/effect/supplypod_rubble)) return FALSE - /* - if((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && reverseOptionList["Underfloor"]) + if((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && reverse_option_list["Underfloor"]) return TRUE - else if ((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && !reverseOptionList["Underfloor"]) + else if ((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && !reverse_option_list["Underfloor"]) return FALSE - */ - if(isProbablyWallMounted(obj_to_insert) && reverseOptionList["Wallmounted"]) + if(isProbablyWallMounted(obj_to_insert) && reverse_option_list["Wallmounted"]) return TRUE - else if (isProbablyWallMounted(obj_to_insert) && !reverseOptionList["Wallmounted"]) + else if (isProbablyWallMounted(obj_to_insert) && !reverse_option_list["Wallmounted"]) return FALSE - if(!obj_to_insert.anchored && reverseOptionList["Unanchored"]) + if(!obj_to_insert.anchored && reverse_option_list["Unanchored"]) return TRUE - if(obj_to_insert.anchored && reverseOptionList["Anchored"]) + if(obj_to_insert.anchored && !ismecha(obj_to_insert) && reverse_option_list["Anchored"]) //Mecha are anchored but there is a separate option for them + return TRUE + if(ismecha(obj_to_insert) && reverse_option_list["Mecha"]) return TRUE return FALSE else if (isturf(to_insert)) - if(isfloorturf(to_insert) && reverseOptionList["Floors"]) + if(isfloorturf(to_insert) && reverse_option_list["Floors"]) return TRUE - if(isfloorturf(to_insert) && !reverseOptionList["Floors"]) + if(isfloorturf(to_insert) && !reverse_option_list["Floors"]) return FALSE - if(isclosedturf(to_insert) && reverseOptionList["Walls"]) + if(isclosedturf(to_insert) && reverse_option_list["Walls"]) return TRUE - if(isclosedturf(to_insert) && !reverseOptionList["Walls"]) + if(isclosedturf(to_insert) && !reverse_option_list["Walls"]) return FALSE return FALSE return TRUE diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index e592a72ee8131..48d5397567e5a 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -185,7 +185,7 @@ smoke_system.set_up(3, src) smoke_system.attach(src) - + add_cell() add_scanmod() add_capacitor() @@ -633,12 +633,12 @@ if(!direction) return FALSE if(internal_tank?.connected_port) - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)]Unable to move while connected to the air system port!") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(construction_state) - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect.") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE @@ -647,19 +647,30 @@ return FALSE if(!Process_Spacemove(direction)) return FALSE - if(!has_charge(step_energy_drain)) - return FALSE if(zoom_mode) - to_chat(occupants, "[icon2html(src, occupants)]Unable to move while in zoom mode!") + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Unable to move while in zoom mode!") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(!cell) - to_chat(occupants, "[icon2html(src, occupants)]Missing power cell.") + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Missing power cell.") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(!scanmod || !capacitor) - to_chat(occupants, "[icon2html(src, occupants)]Missing [scanmod? "capacitor" : "scanning module"].") + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Missing [scanmod? "capacitor" : "scanning module"].") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) + return FALSE + if(!use_power(step_energy_drain)) + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Insufficient power to move!") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(lavaland_only && is_mining_level(z)) - to_chat(occupants, "[icon2html(src, occupants)]Invalid Environment.") + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + to_chat(occupants, "[icon2html(src, occupants)]Invalid Environment.") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE var/olddir = dir @@ -673,8 +684,7 @@ var/keyheld = FALSE if(strafe) - for(var/D in return_drivers()) - var/mob/driver = D + for(var/mob/driver as anything in return_drivers()) if(driver.client?.keys_held["Alt"]) keyheld = TRUE break diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index 257668dba141d..4d34a15650908 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -160,7 +160,7 @@ chassis.leg_overload_mode = !chassis.leg_overload_mode button_icon_state = "mech_overload_[chassis.leg_overload_mode ? "on" : "off"]" chassis.log_message("Toggled leg actuators overload.", LOG_MECHA) - if(!chassis.leg_overload_mode) + if(chassis.leg_overload_mode) chassis.movedelay = min(1, round(chassis.movedelay * 0.5)) chassis.step_energy_drain = max(chassis.overload_step_energy_drain_min,chassis.step_energy_drain*chassis.leg_overload_coeff) chassis.balloon_alert(owner,"Toggled leg actuators overload.") diff --git a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js b/tgui/packages/tgui/interfaces/CentcomPodLauncher.js index dd20e8fb13ea1..a4b0ddd6fa492 100644 --- a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js +++ b/tgui/packages/tgui/interfaces/CentcomPodLauncher.js @@ -26,7 +26,7 @@ export const CentcomPodLauncher = (props, context) => { theme="admin" title={compact ? 'Use against Helen Weinstein' : 'Supply Pod Menu (Use against Helen Weinstein)'} overflow="hidden" - width={compact ? 435 : 690} + width={compact ? 435 : 730} height={compact ? 360 : 440}> @@ -135,6 +135,13 @@ const REVERSE_OPTIONS = [ { title: 'Walls', icon: 'square', + + }, + { + title: 'Mechs', + key: 'Mecha', + icon: 'truck', + }, ]; @@ -711,7 +718,7 @@ const ReverseMenu = (props, context) => { inline icon={option.icon} disabled={!data.effectReverse} - selected={option.key ? data.reverseOptionList[option.key] : data.reverseOptionList[option.title]} + selected={option.key ? data.reverse_option_list[option.key] : data.reverse_option_list[option.title]} tooltip={option.title} onClick={() => act('reverseOption', { From a07b6a153236cf0ba51d1ce91837363d4f185e7c Mon Sep 17 00:00:00 2001 From: RKz Date: Sun, 10 Dec 2023 18:39:47 -0500 Subject: [PATCH 33/41] https://github.com/tgstation/tgstation/pull/54529 --- beestation.dme | 1 + code/__DEFINES/mecha.dm | 2 ++ code/_globalvars/time_vars.dm | 2 ++ code/modules/vehicles/mecha/_mecha.dm | 24 +++++++------------ .../vehicles/mecha/combat/reticence.dm | 4 +--- 5 files changed, 14 insertions(+), 19 deletions(-) create mode 100644 code/_globalvars/time_vars.dm diff --git a/beestation.dme b/beestation.dme index 0922591b66ce0..40627625c4178 100644 --- a/beestation.dme +++ b/beestation.dme @@ -298,6 +298,7 @@ #include "code\_globalvars\misc.dm" #include "code\_globalvars\regexes.dm" #include "code\_globalvars\religion.dm" +#include "code\_globalvars\time_vars.dm" #include "code\_globalvars\traits.dm" #include "code\_globalvars\xenoartifact.dm" #include "code\_globalvars\lists\achievements.dm" diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm index c94a6f2eeda30..0bd8ef0adb6bd 100644 --- a/code/__DEFINES/mecha.dm +++ b/code/__DEFINES/mecha.dm @@ -12,6 +12,8 @@ #define SILICON_PILOT (1<<4) #define IS_ENCLOSED (1<<5) #define HAS_LIGHTS (1<<6) +#define QUIET_STEPS (1<<7) +#define QUIET_TURNS (1<<8) #define MECHA_MELEE (1 << 0) #define MECHA_RANGED (1 << 1) diff --git a/code/_globalvars/time_vars.dm b/code/_globalvars/time_vars.dm new file mode 100644 index 0000000000000..5f302dab1635d --- /dev/null +++ b/code/_globalvars/time_vars.dm @@ -0,0 +1,2 @@ +GLOBAL_VAR_INIT(year, time2text(world.realtime,"YYYY")) +GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? // = 2017??? // = 2023??? diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 48d5397567e5a..429e4fc3b5f8c 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -101,13 +101,13 @@ ///Typepath for the wreckage it spawns when destroyed var/wreckage - var/list/equipment = new + var/list/equipment = list() ///Current active equipment var/obj/item/mecha_parts/mecha_equipment/selected ///Current active equipment var/max_equip = 3 - ///Whether our steps are silent, for example in zero-G + ///Whether our steps are silent due to no gravity var/step_silent = FALSE ///Sound played when the mech moves var/stepsound = 'sound/mecha/mechstep.ogg' @@ -591,8 +591,9 @@ /obj/vehicle/sealed/mecha/proc/play_stepsound() SIGNAL_HANDLER - if(stepsound) - playsound(src,stepsound,40,1) + if(mecha_flags & QUIET_STEPS) + return + playsound(src, stepsound, 40, TRUE) /obj/vehicle/sealed/mecha/proc/disconnect_air() SIGNAL_HANDLER @@ -617,10 +618,9 @@ to_chat(occupants, "[icon2html(src, occupants)]The [src] push off [movable_backup] to propel yourself.") return TRUE - if(movedelay <= world.time && active_thrusters && movement_dir && active_thrusters.thrust(movement_dir)) + if(active_thrusters?.thrust(movement_dir)) step_silent = TRUE return TRUE - return FALSE /obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) @@ -691,9 +691,9 @@ //if we're not facing the way we're going rotate us if(dir != direction && !strafe || forcerotate || keyheld) - setDir(direction) - if(turnsound) + if(dir != direction && !(mecha_flags & QUIET_TURNS) && !step_silent) playsound(src,turnsound,40,TRUE) + setDir(direction) return TRUE @@ -1136,14 +1136,6 @@ req_access = list() return allowed(M) -//////////////////////////////// -/////// Messages and Log /////// -//////////////////////////////// - -GLOBAL_VAR_INIT(year, time2text(world.realtime,"YYYY")) -GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? // = 2017??? -//why is this here - /////////////////////// ///// Power stuff ///// /////////////////////// diff --git a/code/modules/vehicles/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm index 13d595b2cb348..c177124e7943d 100644 --- a/code/modules/vehicles/mecha/combat/reticence.dm +++ b/code/modules/vehicles/mecha/combat/reticence.dm @@ -12,13 +12,11 @@ wreckage = /obj/structure/mecha_wreckage/reticence operation_req_access = list(ACCESS_THEATRE) internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_THEATRE) - mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS + mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS | QUIET_STEPS | QUIET_TURNS internal_damage_threshold = 25 max_equip = 2 step_energy_drain = 3 color = "#87878715" - stepsound = null - turnsound = null /obj/vehicle/sealed/mecha/combat/reticence/loaded/Initialize(mapload) . = ..() From 180db33f43c524fd358f4f763e22b2216821ecff Mon Sep 17 00:00:00 2001 From: RKz Date: Sun, 10 Dec 2023 18:43:46 -0500 Subject: [PATCH 34/41] prettier --- tgui/packages/tgui/interfaces/CentcomPodLauncher.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js b/tgui/packages/tgui/interfaces/CentcomPodLauncher.js index a4b0ddd6fa492..47c687f8de36c 100644 --- a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js +++ b/tgui/packages/tgui/interfaces/CentcomPodLauncher.js @@ -135,13 +135,11 @@ const REVERSE_OPTIONS = [ { title: 'Walls', icon: 'square', - }, { title: 'Mechs', key: 'Mecha', icon: 'truck', - }, ]; From 1e9ad2a54f63b964e8d49836288f9043a84dc4fc Mon Sep 17 00:00:00 2001 From: RKz Date: Tue, 12 Dec 2023 07:52:11 -0500 Subject: [PATCH 35/41] https://github.com/tgstation/tgstation/pull/54454 --- code/modules/vehicles/mecha/_mecha.dm | 42 +++++++++---------- code/modules/vehicles/mecha/combat/combat.dm | 2 +- .../mecha/equipment/weapons/weapons.dm | 3 +- code/modules/vehicles/mecha/mecha_actions.dm | 3 ++ .../vehicles/mecha/medical/odysseus.dm | 6 +-- .../modules/vehicles/mecha/working/working.dm | 1 + code/modules/vehicles/sealed.dm | 1 + 7 files changed, 30 insertions(+), 28 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 429e4fc3b5f8c..af32ff599c693 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -216,14 +216,10 @@ var/obj/item/mecha_parts/mecha_equipment/equip = E equip.detach(loc) qdel(equip) - if(cell) - QDEL_NULL(cell) - if(scanmod) - QDEL_NULL(scanmod) - if(capacitor) - QDEL_NULL(capacitor) - if(internal_tank) - QDEL_NULL(internal_tank) + QDEL_NULL(cell) + QDEL_NULL(scanmod) + QDEL_NULL(capacitor) + QDEL_NULL(internal_tank) STOP_PROCESSING(SSobj, src) LAZYCLEARLIST(equipment) assume_air(cabin_air) @@ -364,18 +360,20 @@ . += "It's equipped with:" for(var/obj/item/mecha_parts/mecha_equipment/ME in visible_equipment) . += "[icon2html(ME, user)] \A [ME]." - if(!enclosed) - if(mecha_flags & SILICON_PILOT) - . += "[src] appears to be piloting itself..." - else - for(var/occupante in occupants) - . += "You can see [occupante] inside." - if(ishuman(user)) - var/mob/living/carbon/human/H = user - for(var/O in H.held_items) - if(istype(O, /obj/item/gun)) - . += "It looks like you can hit the pilot directly if you target the center or above." - break //in case user is holding two guns + if(enclosed) + return + if(mecha_flags & SILICON_PILOT) + . += "[src] appears to be piloting itself..." + else + for(var/occupante in occupants) + . += "You can see [occupante] inside." + if(ishuman(user)) + var/mob/living/carbon/human/H = user + for(var/held_item in H.held_items) + if(!isgun(held_item)) + continue + . += "It looks like you can hit the pilot directly if you target the center or above." + break //in case user is holding two guns //processing internal damage, temperature, air regulation, alert updates, lights power use. /obj/vehicle/sealed/mecha/process() @@ -478,7 +476,7 @@ if(mecha_flags & LIGHTS_ON) var/lights_energy_drain = 2 - use_power(lights_energy_drain) + use_power(lights_energy_drain*delta_time) for(var/b in occupants) var/mob/living/occupant = b @@ -881,7 +879,7 @@ ///Handles an actual AI (simple_animal mecha pilot) entering the mech /obj/vehicle/sealed/mecha/proc/aimob_enter_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) - if(pilot_mob && pilot_mob.Adjacent(src)) + if(pilot_mob?.Adjacent(src)) if(occupants) return LAZYADD(occupants, src) diff --git a/code/modules/vehicles/mecha/combat/combat.dm b/code/modules/vehicles/mecha/combat/combat.dm index 11dfb5a7672a1..6a6636b4b45a6 100644 --- a/code/modules/vehicles/mecha/combat/combat.dm +++ b/code/modules/vehicles/mecha/combat/combat.dm @@ -9,4 +9,4 @@ /obj/vehicle/sealed/mecha/combat/restore_equipment() mouse_pointer = 'icons/mecha/mecha_mouse.dmi' - . = ..() + return ..() diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 6a8acdedb4dc1..b1806bc50b538 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -48,8 +48,7 @@ if(kickback) chassis.newtonian_move(newtonian_target) - chassis.log_message("Fired from [src.name], targeting [target].", LOG_MECHA) - return + chassis.log_message("Fired from [name], targeting [target].", LOG_ATTACK) //Base energy weapon type /obj/item/mecha_parts/mecha_equipment/weapon/energy diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index 4d34a15650908..393ec643fbc01 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -128,6 +128,9 @@ toggle_strafe() /obj/vehicle/sealed/mecha/proc/toggle_strafe() + if(!(mecha_flags & CANSTRAFE)) + to_chat(occupants, "[icon2html(src, occupants)]This mecha does not support strafing.") + return strafe = !strafe to_chat(occupants, "[icon2html(src, occupants)]Toggled strafing mode [strafe?"on":"off"].") diff --git a/code/modules/vehicles/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm index 1cd8ea3b60b6f..5317579d39dd2 100644 --- a/code/modules/vehicles/mecha/medical/odysseus.dm +++ b/code/modules/vehicles/mecha/medical/odysseus.dm @@ -15,12 +15,12 @@ /obj/vehicle/sealed/mecha/medical/odysseus/moved_inside(mob/living/carbon/human/H) . = ..() - if(.) + if(. && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD)) var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] hud.add_hud_to(H) /obj/vehicle/sealed/mecha/medical/odysseus/remove_occupant(mob/M) - if(isliving(M)) + if(isliving(M) && HAS_TRAIT_FROM(M, TRAIT_MEDICAL_HUD, src)) var/mob/living/L = M var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] hud.remove_hud_from(L) @@ -28,7 +28,7 @@ /obj/vehicle/sealed/mecha/medical/odysseus/mmi_moved_inside(obj/item/mmi/M, mob/user) . = ..() - if(.) + if(. && !HAS_TRAIT(M, TRAIT_MEDICAL_HUD)) var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] var/mob/living/brain/B = M.brainmob hud.add_hud_to(B) diff --git a/code/modules/vehicles/mecha/working/working.dm b/code/modules/vehicles/mecha/working/working.dm index f979a57ada429..3709fb91d544f 100644 --- a/code/modules/vehicles/mecha/working/working.dm +++ b/code/modules/vehicles/mecha/working/working.dm @@ -1,2 +1,3 @@ /obj/vehicle/sealed/mecha/working internal_damage_threshold = 60 + allow_diagonal_movement = TRUE diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index b938d6bc32963..1bf76cdff7314 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -99,6 +99,7 @@ /obj/vehicle/sealed/obj_destruction(damage_flag) explosion(loc, 0, 1, 2, 3, 0) + log_message("[src] exploded due to destruction", LOG_ATTACK) return ..() /obj/vehicle/sealed/Destroy() From 481c04427414510644ad705568db7e6f8be51290 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Wed, 20 Dec 2023 00:55:14 -0500 Subject: [PATCH 36/41] delete unused reference --- code/modules/vehicles/mecha/_mecha.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index af32ff599c693..340af88093b57 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -475,8 +475,7 @@ checking = checking.loc if(mecha_flags & LIGHTS_ON) - var/lights_energy_drain = 2 - use_power(lights_energy_drain*delta_time) + use_power(2) for(var/b in occupants) var/mob/living/occupant = b From 425f879f5cdffa321a1ac313f56402f671454911 Mon Sep 17 00:00:00 2001 From: RKz Date: Fri, 5 Jan 2024 07:49:53 -0500 Subject: [PATCH 37/41] https://github.com/BeeStation/BeeStation-Hornet/pull/10304 --- code/modules/vehicles/mecha/_mecha.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 340af88093b57..c3b9e3d09e2fb 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -1124,8 +1124,8 @@ ///////////////////////// /obj/vehicle/sealed/mecha/proc/operation_allowed(mob/M) - req_access = operation_req_access - req_one_access = list() + req_access = list() + req_one_access = operation_req_access return allowed(M) /obj/vehicle/sealed/mecha/proc/internals_access_allowed(mob/M) From f3c4d8442d8a0d0fd877d89aec0c027359dac297 Mon Sep 17 00:00:00 2001 From: RKz Date: Fri, 26 Jan 2024 02:38:32 -0500 Subject: [PATCH 38/41] update_appearance --- code/modules/vehicles/mecha/_mecha.dm | 55 ++++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index c3b9e3d09e2fb..c00e3a73a0414 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -201,7 +201,7 @@ diag_hud_set_mechstat() become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT) update_step_speed() - update_icon() + update_appearance() /obj/vehicle/sealed/mecha/Destroy() for(var/M in occupants) @@ -878,13 +878,14 @@ ///Handles an actual AI (simple_animal mecha pilot) entering the mech /obj/vehicle/sealed/mecha/proc/aimob_enter_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) - if(pilot_mob?.Adjacent(src)) - if(occupants) - return - LAZYADD(occupants, src) - pilot_mob.mecha = src - pilot_mob.forceMove(src) - update_icon() + if(!pilot_mob?.Adjacent(src)) + return + if(occupants) + return + LAZYADD(occupants, src) + pilot_mob.mecha = src + pilot_mob.forceMove(src) + update_appearance() ///Handles an actual AI (simple_animal mecha pilot) exiting the mech /obj/vehicle/sealed/mecha/proc/aimob_exit_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) @@ -892,7 +893,7 @@ if(pilot_mob.mecha == src) pilot_mob.mecha = null pilot_mob.forceMove(get_turf(src)) - update_icon() + update_appearance() ///////////////////////////////////// @@ -1007,30 +1008,30 @@ to_chat(user, "You stop inserting the MMI.") return FALSE -/obj/vehicle/sealed/mecha/proc/mmi_moved_inside(obj/item/mmi/M, mob/user) - if(!(Adjacent(M) && Adjacent(user))) +/obj/vehicle/sealed/mecha/proc/mmi_moved_inside(obj/item/mmi/brain_obj, mob/user) + if(!(Adjacent(brain_obj) && Adjacent(user))) return FALSE - if(!M.brain_check(user)) + if(!brain_obj.brain_check(user)) return FALSE - var/mob/living/brain/B = M.brainmob - if(!user.transferItemToLoc(M, src)) - to_chat(user, "\the [M] is stuck to your hand, you cannot put it in \the [src]!") + var/mob/living/brain/brain_mob = brain_obj.brainmob + if(!user.transferItemToLoc(brain_obj, src)) + to_chat(user, "\the [brain_obj] is stuck to your hand, you cannot put it in \the [src]!") return FALSE - M.mecha = src - add_occupant(B)//Note this forcemoves the brain into the mech to allow relaymove + brain_obj.mecha = src + add_occupant(brain_mob)//Note this forcemoves the brain into the mech to allow relaymove mecha_flags |= SILICON_PILOT - B.reset_perspective(src) - B.remote_control = src - B.update_mobility() - B.update_mouse_pointer() + brain_mob.reset_perspective(src) + brain_mob.remote_control = src + brain_mob.update_mobility() + brain_mob.update_mouse_pointer() setDir(dir_in) - log_message("[M] moved in as pilot.", LOG_MECHA) + log_message("[brain_obj] moved in as pilot.", LOG_MECHA) if(!internal_damage) - SEND_SOUND(M, sound('sound/mecha/nominal.ogg',volume=50)) - log_game("[key_name(user)] has put the MMI/posibrain of [key_name(B)] into [src] at [AREACOORD(src)]") + SEND_SOUND(brain_obj, sound('sound/mecha/nominal.ogg',volume=50)) + log_game("[key_name(user)] has put the MMI/posibrain of [key_name(brain_mob)] into [src] at [AREACOORD(src)]") return TRUE /obj/vehicle/sealed/mecha/container_resist(mob/living/user) @@ -1093,7 +1094,7 @@ L.reset_perspective() remove_occupant(L) mmi.mecha = null - mmi.update_icon() + mmi.update_appearance() L.mobility_flags = NONE setDir(dir_in) return ..() @@ -1104,7 +1105,7 @@ RegisterSignal(M, COMSIG_MOB_CLICKON, PROC_REF(on_mouseclick)) RegisterSignal(M, COMSIG_MOB_SAY, PROC_REF(display_speech_bubble)) . = ..() - update_icon() + update_appearance() /obj/vehicle/sealed/mecha/remove_occupant(mob/M) UnregisterSignal(M, COMSIG_MOB_DEATH) @@ -1117,7 +1118,7 @@ M.client.view_size.resetToDefault() zoom_mode = 0 . = ..() - update_icon() + update_appearance() ///////////////////////// ////// Access stuff ///// From dca48583d2884d4ed86875e2964da86118e860d9 Mon Sep 17 00:00:00 2001 From: RKz Date: Sat, 27 Apr 2024 10:50:15 -0400 Subject: [PATCH 39/41] set mech weapons as firer to blacklist them from hitting themselves --- code/modules/vehicles/mecha/equipment/weapons/weapons.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index b1806bc50b538..4b4abdf3ab144 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -37,6 +37,7 @@ spread = round((i / projectiles_per_shot - 0.5) * variance) var/obj/projectile/A = new projectile(get_turf(src)) + A.firer = chassis A.preparePixelProjectile(target, source, params, spread) A.fire() From c01fa3e7d2740d608ae91be324774ef9fb648371 Mon Sep 17 00:00:00 2001 From: RKz Date: Sat, 27 Apr 2024 12:45:37 -0400 Subject: [PATCH 40/41] fixes mech z-fall & punch force & diagonal movement --- code/modules/vehicles/mecha/_mecha.dm | 21 ++++++++++++------- code/modules/vehicles/mecha/combat/gygax.dm | 1 - .../vehicles/mecha/medical/odysseus.dm | 2 +- .../modules/vehicles/mecha/working/working.dm | 1 - 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index c00e3a73a0414..aa4460e5c5bd0 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -25,7 +25,9 @@ max_integrity = 300 armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0) movedelay = 1 SECONDS - anchored = TRUE + force = 5 + move_force = MOVE_FORCE_VERY_STRONG + move_resist = MOVE_FORCE_EXTREMELY_STRONG emulate_door_bumps = TRUE COOLDOWN_DECLARE(mecha_bump_smash) light_system = MOVABLE_LIGHT @@ -60,6 +62,7 @@ var/construction_state = MECHA_LOCKED ///Contains flags for the mecha var/mecha_flags = ADDING_ACCESS_POSSIBLE | CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS + ///Spark effects are handled by this datum var/datum/effect_system/spark_spread/spark_system = new ///How powerful our lights are @@ -67,7 +70,9 @@ ///Just stop the mech from doing anything var/completely_disabled = FALSE ///Whether this mech is allowed to move diagonally - var/allow_diagonal_movement = FALSE + var/allow_diagonal_movement = TRUE + ///Whether this mech moves into a direct as soon as it goes to move. Basically, turn and step in the same key press. + var/pivot_step = FALSE ///Whether or not the mech destroys walls by running into it. var/bumpsmash = FALSE @@ -88,10 +93,11 @@ var/list/trackers = list() var/max_temperature = 25000 - ///health percentage below which internal damage is possible - var/internal_damage_threshold = 50 + ///Bitflags for internal damage var/internal_damage = NONE + ///health percentage below which internal damage is possible + var/internal_damage_threshold = 50 ///required access level for mecha operation var/list/operation_req_access = list() @@ -132,7 +138,6 @@ ////Action vars ///Ref to any active thrusters we might have - var/obj/item/mecha_parts/mecha_equipment/thrusters/active_thrusters ///Bool for energy shield on/off @@ -199,9 +204,10 @@ diag_hud_set_mechhealth() diag_hud_set_mechcell() diag_hud_set_mechstat() + update_appearance() + become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT) update_step_speed() - update_appearance() /obj/vehicle/sealed/mecha/Destroy() for(var/M in occupants) @@ -691,7 +697,8 @@ if(dir != direction && !(mecha_flags & QUIET_TURNS) && !step_silent) playsound(src,turnsound,40,TRUE) setDir(direction) - return TRUE + if(!pivot_step) //If we pivot step, we don't return here so we don't just come to a stop + return TRUE //set_glide_size(DELAY_TO_GLIDE_SIZE(movedelay)) diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm index 873788e979ee2..1ab526e29d6c7 100644 --- a/code/modules/vehicles/mecha/combat/gygax.dm +++ b/code/modules/vehicles/mecha/combat/gygax.dm @@ -3,7 +3,6 @@ name = "\improper Gygax" icon_state = "gygax" base_icon_state = "gygax" - allow_diagonal_movement = TRUE movedelay = 3 dir_in = 1 //Facing North. max_integrity = 250 diff --git a/code/modules/vehicles/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm index 5317579d39dd2..c20faa339563c 100644 --- a/code/modules/vehicles/mecha/medical/odysseus.dm +++ b/code/modules/vehicles/mecha/medical/odysseus.dm @@ -3,7 +3,6 @@ name = "\improper Odysseus" icon_state = "odysseus" base_icon_state = "odysseus" - allow_diagonal_movement = TRUE movedelay = 2 max_temperature = 15000 max_integrity = 120 @@ -12,6 +11,7 @@ deflect_chance = 15 step_energy_drain = 6 internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_MEDICAL) + pivot_step = TRUE /obj/vehicle/sealed/mecha/medical/odysseus/moved_inside(mob/living/carbon/human/H) . = ..() diff --git a/code/modules/vehicles/mecha/working/working.dm b/code/modules/vehicles/mecha/working/working.dm index 3709fb91d544f..f979a57ada429 100644 --- a/code/modules/vehicles/mecha/working/working.dm +++ b/code/modules/vehicles/mecha/working/working.dm @@ -1,3 +1,2 @@ /obj/vehicle/sealed/mecha/working internal_damage_threshold = 60 - allow_diagonal_movement = TRUE From 59e2c0fa71cf7e4e4c6af3856124d5b824cc9ab0 Mon Sep 17 00:00:00 2001 From: RKz Date: Fri, 17 May 2024 03:36:41 -0400 Subject: [PATCH 41/41] fix self-healing exploit --- code/modules/vehicles/mecha/mecha_defense.dm | 2 ++ code/modules/vehicles/sealed.dm | 13 ++++++++++++- icons/mecha/mecha.dmi | Bin 96409 -> 138799 bytes 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index 6bb70469c1dc1..8de46dd4d5091 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -296,6 +296,8 @@ /obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W) . = ..() + if(user in src.occupants) //Fuck with any attempts by the current user to self heal whilst piloting + return if(user.a_intent == INTENT_HARM) return . = TRUE diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index 1bf76cdff7314..15936654d245c 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -1,6 +1,6 @@ /obj/vehicle/sealed flags_1 = PREVENT_CONTENTS_EXPLOSION_1 - var/enter_delay = 20 + var/enter_delay = 2 SECONDS var/mouse_pointer /obj/vehicle/sealed/CanAllowThrough(atom/movable/mover, turf/target) @@ -30,6 +30,17 @@ if(ismob(gone)) remove_occupant(gone) +/* +/obj/vehicle/sealed/after_add_occupant(mob/M) + . = ..() + ADD_TRAIT(M, TRAIT_HANDS_BLOCKED, VEHICLE_TRAIT) + + +/obj/vehicle/sealed/after_remove_occupant(mob/M) + . = ..() + REMOVE_TRAIT(M, TRAIT_HANDS_BLOCKED, VEHICLE_TRAIT) +*/ + /obj/vehicle/sealed/proc/mob_try_enter(mob/M) if(!istype(M)) return FALSE diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi index 7e6460abfd1d32e5c7df3f421a363e3934b8c369..0cf378e5911f14182eb58985ef4194f2a07f1f2e 100644 GIT binary patch literal 138799 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�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

Q;-23 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%0A8sLD4%XsMA3@p z$GbI2ZuUl|UdnMyC$f;^U~b@}UnBPSMMpa^&)s%n%*kpde`-f@HEywz92z|Q>-&F$ zZnh+Np12Sx=A&(XKE=W`aGIT9T;m!&YaohEPWrMW-HJ0Lx6_}!yR04h^uARU7<*J4 z1?Iax!vUCqzex-)E={FyeKXLE=Y8pNYBBEy!TvBX0~9)b(0DDLOk`x7dNuPXJ^6kt zR!)^JIA)Ovb?PD{FH}= z_XueOVqHULQ0~)EehxkxY^79Xd;0zjGx92vx&-EMz69bWPMgaxr%UJp&y|#ePTJbq z3hAY?eBwYhJ}9~VD{4JJSXYcHYW)FD`O*rKWg z@HW3BN|A3D;E8R4`%dh&sYQm%-@JKKkDl*wbGs`ZDlxPi4wqDs3h$3>-g28jzh(^o zoAm6fVh488s35-aTF+P_h-kBNT-7D*0l)V0^#|I_8&0;qL(I_`(FU|T^jgz zN!LUPj@~9f?n*d{vD56_&XF@GC=on=NbY%yQ6tVFRKjQSiI0a3*Mv;QD=%h5Z6YQ6 zd{qTPFnq7#;YR^#tv84zeG96^vMCI6{g5-3>g>H=KyA-(LVyuEX(6iG)~f{@tA0Ku zjRQO_S;hwBK;99(%Vg=@d5QOgEi`{{hyK0~v>(IQD5iUJk4Qe!3l(@+#GKD6(=v3< zVP@$<3MU;>beV8r(3h+Q3GW<_`1xqPw_$j(o*|6eDQAhr!MgT=QOLx#8LpRIqdanV z_$~-)8MMrYo-V-9-F^>a(>K?ZZ)KV5fvks*VDNS(A1K-YDkamDdf0Wi6h*P%n>e{LcFp!8 z%ZBY&{z5f`2HyZhf%54M#qzhIIc304fI#HE^9Ls z+Iwf+8^os>YCfdB@CD~X*4mvokzqiKn%a_bx9gfl>{~-QwTCX&&*=BkOTCWyM5mCJ zgwf(({s?{a&@Y~UIowUh81$@@W@(MYe|0H%z%LI6M-vb9TES$s-xE=gP7tQbYyDy3 zHI1<*eHy@d517idCm#&14rH{)Xh@dh}c+l}c5j?+ZsKr2_xraKUnOF>J5&C!8Z&1u~ayB*fq1w9r<39~H_!#6%;OwaeFkysHPB z)Z>4~`Xk)NeL_74Pb}u}JyErK@#e14Wp_rr{Z}g{Ri2E_qhA^?O+g7eDE3ejm0x?W zsONp#&c8wQaps4A0Ad5$@igntDY;e*t!&f{!bk{(D4ayD!iHBpe!|7w=Ct-`9KPOJ zssN-cFwf*x!^e~GX95+Z7+H54I2)pgjmjrcmfplolW1hZLtvNnr zk4)1B=DDK^^yx$15+qe<<;eVo85Fo28C}{+GiXbKwm7{X92Y0v)c;QMi366DC{u)Z zkV$>k3h+He0)}-j*Z{pPs?t&h^fWEMiT@51eQO2~nkt9*TgH8G?}WS@O1W#;&lBaj z_HoiI>LaVpAr{bW=6UjS8LpP)i1F5J7dJt^Nl`uoF548y4Wb0Fj&flt!ONPzWdS!- zCiGrWcpp&+Wcvb~8d)bwt&pXx^9@2w3A-e7boXiNZJvPn)*GUloL8E^x0*6`a~wQXbX0XGFfy#4%fa6hFtAey4L3q$L+p12Ts-Nl&IjZFoZt zZ>R)l<^rYIpSq`dZj{6622D^Ct?c*HW##UFP0*)qizsZpOJwDsQid*ry#A}HEIUi5RGlq|!);8nAW z6a!xUoX*;yKRNVUw_`ZM>s|El&bEJ*Q3=f#qpY&w>KP?X&}|q%6gW6V(jH$nPb9 zvGI^@w4>6Mv%q}1iBBg3n})`^o|;)sCDzDkKmK%fMF|AL3(Cj0owO<3LQyYHv)hl;^d zipS1)?pru<5l-MHq$N<}{_m~;MOF2yK>5zJ{BYg;M=;+f^#hXgC(JjNxc8~ny+^P? zYKnNdk;GIu-wwwUh}*me4sQk(n)6!VIhXPd04zZc#OlCeUeof_bAw$Jt9Q*d z%RZTuyQXfh0xeuaI3o5hRrN!*s#z5OLK=!#BMOM)9Ul&2QlZ#biu=cXOfL>@$k2Uc z7z`YocFDZWhm+mD>RRSro`o3W=;f~uZ8~)i(#XMns~4%h^qge5&$#Zqdy}A#Q#eCuU1}PDKnLKXB zhc+5{_Xf^iQsLJJdzXVcA?OiKq+r$fZyxzkPC>Kdu%>kHDA4D?pa=uIh}Tfv%!h{~ z>CSE;Ry?F1g8z98r|=7=ASnxqIzh4#5dW@^gGVWefiEfX%^_S!!Mk$~em&tkDH ztI^kCO>cM+_PWFRtb~r5qL_FtWPOW1FWoU>)Cq#2806zq&EvMsy0rWSD)m8SVB0;Q z^bp?95f>+EN8b2{<%G0!Bxp>IAt@JD zu{c=;Z{RH3Xc>djO|6cNj&X2*RNvuZ5M9Bozm#<91Q`rk6_|`*J5K9AiI1Zg=kz6C zB9hn5f%WSN$BhKfin@85WQ}{4Rsm1jBW0Q31Cle9-WFLdtbbZli`|Ki@{(Cgma4I| zb8?W&)_s=Pa@&VNWr}G7{d-Q6#!{{eB`N}C84<5hDZD@v^#RU|mg;}~HH#=V%p>}% zs*$DiB46>kFYocxW_0y~9qNc@H>lwwCYPgef0nxKGN+?>tb{2z;tyv;6sxnA*c9{q zPtRq4Hqom64L|(^S@)wBfl9yTLe_<;$q>hfiF>4_OcH*)pJx6k?vYi*O8dI{vwuJdG!vdG+9~P_a@?GDVYTC;R5Ow&bAx zt3Uko;dG<+mu*|CehwR+E)wJS=ZYvF+2-Z7HxZWPz5vYgs?!D^0c6FM`4jS;hkm>9 zhKcs_g_pJtv7SnS26QDZAT|coU?8`p<}h{|ijlAu;N}x)q`7YiN-%3Wc-38}b3ZUI z-2c8e<1_R#JX+CoRe*}HzAIHzz5M(XKh{_4{KV1MX$Ffe`m1*qDS-)##QgXh`-gnYeJ~SsrQR?wVce}^C8P|63$A@-W9j&M zu>#6>ftbUH`2#LZxSls+30dfmYcmkHEidr_(nR-%w@j5=g~m6Y9~m)jPN+~SVqPpR?qu5 z^;O)_)WFv?%B3@F(Clc<3`*H5#TO|$Ms!*j(B7NN1MoVmRa=97R~JdMx8y+LGoSNG z6Nh^;>^$oc$u3{;Gk68<_pXY2W^~Ki?|F0~SY}*(XxK^(wWv$YIUq*qPdkEEW_4TlR3H~C&|{yu8I zfj|tsLD~0pSF>m9g-xCR3-Z(rm-4V5J$2eujLv^f**#+dx-jR~-#mS%Ul+JVD9st` zqp^^xWyT5>7IfAuXxn{BRqd^P|0Pm z^4L=jy0W0%l^n?;>2%w@r4wIv@V_)6hGGnKy`XpyO7}=jXm1h%cgcCbw-oYQQ)E)y zZ$0eDa>I!UoN+az2F@g(H9kJIQ(nrXBR^seJimPZN_SECz5B)f34!QzqfV8qrwQTF z-*0e-bRWC>5)E3MA($zTDLWYpw-ZgdnW zX^j!O%(~9!UI9jCDWD%%YLwZ~<-0U1%TGKa-MJd__i!OtDf(aqOL7+#D^$P@ct_L5 zaiY|kEHhRy`*}*njV4Px>3eg9SBGJCr*JZ+#|+SG&EAa2HU$&)ZV}QVUbmq0`Jb&^ z)-L4ul|nwwj5tP{gN&$UOmuiJ8;Vr<7L9t(V4JnHTx%Zq(y8GrQ|fS~dt@mu@vzQ% zcDV!ARN!711-!Aj(22TnXjLiMSOh=JiC4U1AJ|E4P|!x?J`M@W&9TeBPrDpZ1jW19 zD9Olg?j8?C>1Sw5(;=TfeDkxY-TKY}fz!?j0l)OOx)f6g8w%4291YSUL!RxS0tnRO zK1Hw00BCcL60Vj(pKI)ru&wbA^U@%OBQ0gYJyJ#E{ow|55HME%H9GT0hliTUo5&AO zK&~eqU^UphG|n4oz2UV|V zc0}w7){~8PP;X1e>4n~!QyJ^OTh? z)cEl~b+8Wer)SB=IqMQnXOsoJDa0OA;71m*Q@L)yqjheOBd+q@jPvfh5P1mSZ;rTS zL``2FEoP@(MfEE-AM-66nzN>`60_;#l_(t66K-6uJA)6zuGS(r&#Xqn<#1vycP`N8 zL$%`DoP`e8o}4$30bl#eCP;g8tKrX|QYLBmQcv%kkgqd0Mh)pQ3`IJKi>uun-+I*I z^Fmg2^pKy(oyf^pLfR^c!pn<-JOTsKGG?izG;~K6vg|M1{OkcfOa)-if)xSt=&+}u zwA0FfIy5zhCU#S8-4SFU*pz+Kc9f6Xq355%C=5gPOlcX{wZF$1!AVTjQOhG3GdxS8 zlvM&B9)|{7yplGQAy^WESK?QPGIN^w%)^p_8d1L4?Lou&tm*T;mG{F_&xv%OIvE25 zQmiSclo@c zdkT|rryaKw4KrkkR}Y;03tv*fdY36dS;^K8OG*l`#S$a zSutHmGlE5<{HNH3N%cSnS7E679bKirc`T8kTwX4@OYZ6g#~t{8++8tMXZ>p9LAzYl zqc6ai@Zc8ie$V{L{*UMB_%Rc;OYYsR*_;4^)OB22IQ#K&IROUY6QSIqn3-#5kOvz$ zR3~C1z4Ewte|N3CWf_G$ZTD@vZ>Dye@Bn(T2^sW2I8eMWujl!Cr!hSyWsBdSyu`PW zIP&VR*!VS^qO6JjxI5$AJ_$Z^lCBfNo%C$k-)+uZ3}i_-6^*R(ZafSl!}F0w(dUIaWszw;PBDwc6iOtxEqi1QZOztGD9*8nu>%eaM?1z{`H(X%aGi(R`kD& z2&qquVe=B)ouQkfruOw2@`bs0AZcgU8DGWvZc9Jxp@a-V{IJn-4ndAy6&T1T`!Qui zxe3%XD55KQ9?Q;azIjN}(ECT_FHEAZo>CYoafcG(?t*Ctv)~NhCcg9Pcv5~2LG@Hv z9HruwU4#^hl(!?Dac7bY`+AJ9AXKYAC2y7Kk&k|N{1cxk`|H)|C6;tLATHKFjD z4;5{+$0Sp@-fsEt2ve0Y9}=lr{y*G){1Cs05WD*N55-gz$Zs)aX(xu@-JuBo;y|OZ z``9KpYi|)ny`mKz$*s;F9uAPrWsU%F`LB@Ox_3f(VwAb`)!>r`0A4!zQh(cXUl1J zQ-(};=Y%lS)sdj=78VwMm!#aJ#At(TFSE(fS9J7&llO0eU-f1*@4bV1h+;mLK8#J? zKki7)0wjo)tVt=&$PlY+DU_&@OjB{mE&p7^!;VWk_Adv22?^3_UzI3ZM$lf{h-%&o zDkmT&2;p=q<|B!!Z?_y<(>rs{`}xSRt}i_{fibuXC>yXvcUL35 zVUj0_A_oeICLlz4G0w*&o9y=FnEV%%X%+-=jRe%#}@W;H)ZVQ9Yv$e$~L*)CAjK=au71edZeKhmuvQJH|TFd5}vt_u6+2SE8 zfI_jAK|Tl@4~)@Z^4Ep_CZ885!u(brf;DLaTK-@1KO~j|AB@57tw>9Zjo)jJO+GMI zlF}%S6>CQ$c`;)B6z60h9Z%IV`_4mGqdSvYt-G$!u2Txi$=9V?H6Ds-*VX$CrS;R; z_6^cVjgI^LlnX(TpxQz;We_CA9OGPre*3e(Qo+SjtuO+lf6cv_V0_&cbU}hb$}``k zFfOF?hdKU`RDBQ&vE{&e5B$14YS>=Z9{+=em19l-@U^hQr|J`wJk6uPSh<;puBk<@ z!XRo4tcBXLU48$99_EkYOmQrs_QiPFZq7V!i z9p);iUe*t{mJ1P$n`j+xHDpv@ha`B|Gd0~Kq)S!#xs*4d%v{Cq^AI}Z52MrBY&X%z zEClP&_sM)PGLo49Cmuit_G7$R2+nJ4(hT#(y^ap=Xi`!*V61W;Q}~Y;hsD4XGO&$v zRIU+#Zwp0%ET$><`XN@djA{8GUlk)wi#0wlA3fz5cgxCTky!JMV*eezB!f+!r$|6Y zGNb%qA<&ZDa}AnrjuK+_HAg6A^l#66cK;?J%v7Q5_=YRFA*J-L~enFv8FgEM^w&!SfMy9O^E|4rBC}o`#GM* zU|%vH{3G+6+rTKwK<;;rEju6=`^M!;yp`=k0WfwIWUKC6al5uTw+tZRvnl1$tZU7u z4FQ$JwdVWpD8?Wl-r~0|1VHcVT?Jm_k*T{CQA0TC+wu^#x`dUGCe*Bj<;mWp3|zu` zS7-&xgk+QvNC#sFtFQ-H`Ky3*RtpD>t+DSnxVVlMb>=ae)bgx4NDBsx_vwPXHqkXz zM;>l__8k=MP8jk}JI&`yGI{^Rw8QK4sB@U(K&fP3ln+*p=uC@2h9m+BW1p&T>vQp~ zjnWwAU9%m6sv}6>L0wdm*jzy2KLlu3nzxWciPuGJ7=gWgC1$p1{$X9w#qYDZ{Ho$!SrW-CkfI_K70>& zg*u??e%@k4ud7nk7!Q(Us$8*_&ikMLR1xLHdz`#`9#RwK1Z$S2ZiAl9b8`y7{L*V0 zwLEn-Z(v^828`wS#=!*QTR$m_(gUm2VFX`sB#n44?7hAl-Ul**MS1vLX8@W}e@h{n zof7#s#qdLtrSVIfp0oJ@z2$qV<1HxeFL#~~ahZQBofizd`ejm|(DyOI@^hU9X5<5w zAWj=dl7q&kqiMA5%~0goZU#z z3h)Z>@P(J$aMWh{xY|A+&r4uFNXohfkdnwtgNGG1|DAx;93tlSl_2wX+r}slJc*>f z1G#iC>#B?NLVAAoaRmJ85->N1$(QBbLQ`<=~Ua}T*BaE6F zHc8j}>w~vxqy!1x3<)m4&$FH9jr6oNFQ?OajT-YM9t!V%-~_z&{aM8lrt%~#6HkB2 zc=n7L=7H7f7yKNmMFBlnb=X?i(%<_2g;2r?aQEeK0_&)R=eTv3)FwFbdN5~zBjfRN zx$(1;9>K-wPi#!UU1Ex}oJd2^+b578gFh8Ww7(%F)IvU#1x?tAp__M-SBenuBIGfvoYcFXpBS=!}{GDwY)2U043Ed@p&~o zMB)-rNCi{7aOwxqttqd3acC>Z|M|o7pw+$Uux+!Hv1;E`=ws5~)`()dj~s8SZoMT2 zf+6sfFfPV08T=ysc`O#J+48O%Qq;7eVbxqR$NyS26=8`+XMi+$I z#LYYy+e>4)68Do$pR>KohR*C&KwXEK(_THTDU&w630JH41vMtyb+XffSZa)pP2c(O zf=*big?YZCxjG%d8$~pC&Ie`e9tS2IBQ3`6&f(@otZOGH?Z4iwYZMHtv}$n$@kxmC z_zF=~^|1W;l7B~(Z-_?~XRcG5m_M0+L<0IjQ>$GxLi}_vtYyw#j`9S7_d3udZf}Lw zAA61w8f1iCEZ?(dd!o9z&_R*H#iRmbqpU*YK2-3h3kdgh7#cfr=)&0ghUV*~&-&`- zHkE$7Pl9`uUo!%TN>W{T8rLAsb@Q17i^ZBb4;}whYq4Hpvfw6HJL$g^3*FpjM3t7f zB3XU8zhr~V8F@!}Ns|#bPzSkvTCvGR=*Gx&1|)8`_$bc5ZG5Wrgkxl~VqpXH>`)t% zAJmPx#SORp@^vnhkBEm4PW&uho0}jNFEYCmVJ7DJ97xZsTtookG^c)BbLXy=>#DcZ zQgcIQAqU`LmD3x3&k~ly@3J{MMHFXPQin_?a)BpX@ou4zvtVfv{l%V^?9KeO_(tcy z5J#a>oxI;~Q{KOe0QtS};{Ia8uP>Kc>w7pwTgt-mqs7IN;3i0wIwfOA#h`kJ`}E*_ zM;_gew;9c+2A;mYOAaog9|}*~g4jB$T@~S-;)%Jkg4ipql3?F?jQ@C!qCfkhpcSSa zt6>Qn`BHXgH;7c?vX3or=?m0tc6z1x?jWRiPT!(|4d$+lZP%gKvQ$o3w-v2fjtToK za2aw^{1EoVygq-*XQ~}PU;5^3Rj}a0om>5?A$O*6z`o|rrx*+5WF#N1b|F|42*aav z7pFOZM)j9mL`4=`>4$)?(m}qacUw9iqnZ)fC$CX&lC(2MG5T@H5Ni@WNQ1HQ`3^sq zHUJ+t3s()f%~JZNTKS48%Qf$D*_%TX1|p+J`bP(J5+g4!^jwl!tI4F1EHZ7Rm6$Bj zKb*&Xx~9I0`R@^zoaz}qsou_%rR(Cy&(Wv8cMbP=5aGmz@#blA>5?5KALO@LA3ScZ z4#j;GEaU`6Z@iR@gxbFcet&#cmpL2+_J#j$+`b7I)sy(|QRfRt-dX$Bqdp4tV5G^- z3<;N}iObf2ux6bO;XRI)L3~w3YgG(@37A>MOGg>;`d5D4`mzvhE+>^W&$;cSThE6{ z{o7nn!6y|cKZHAQUzyvteELi|h&wkOk`J{N{appNeFq=!qVF@=)Qf3$POUrFR1n9E z(159#CpA=e9!e{Rp3FN?`Eoq(>~o_$Ucibn_2gk(6vgBvyqfMU!ho0zfAOSbg3gxo z9fm^LxqtwF$S0Z@!wMs*#U<{&ZfQBtynmRf2h%2JT>d6p3^ebAm%q~twWj%Zrb6Wd z`73CTKGv%Hm`J9TQx0G5+_)xxrQ-o1Bhs=wGd7=ndikB7WJsgTfLQZvVRs4Z7%$6n zu}zPOX4U)_v@y`DDhqKt>43GO6VqqpRF-3?4uCK%x2;K%5W>8f1~bdoaeHccBMBZ- z2*EHTs3W&W&pTToTWhu%TK|!@4FxHON%1J|T=5tM(CB)6zJAn!^lh{Al~66ntLUP} zRGP|nb1dx2-q^8}Y8RlIflm^Gg*Ejsu9dSNU73j!E<}~bN8Fv){6ees)jZhtiuKd; zQIzWSB&}n#?0k#`O_1$%W*|TFrydQ)1#?h-SE2b*_X@_NZ5$k#h$QlX)v68eX7|m1 zaHeUI;aLx=TF|@#{CDA~YnB_wo?rs;?$DI!W7SW2pW$@qB@wf7Z@)tBGCUvn%#PDg zd|?%MDUKlI7AQTov?<~z8YSe$os$(*ippXaQ-hJ+V0w8}`v$%Z#`k(hnn%FlUHVF} zbhqZ{t{Cv`5)SR5BNSq_7mIV`>4`L3&KDkGE`U9Keuv}RI&hx7=|Kb+!@ma+=|a{l zKXcEDBE&T3#+`egqIFd5``GHrbX%6T*n`!7Qp$O^4sR@RHH6{ytrk0V0Nt;10wE<) zVB7t$U$2NSJ2&TB(EOfP7AXIOOZuNpd|f>Po`=ntn$N`WC&0c2?YM?DG(o=iSu{w~fZcF`9$A@R* zy0k6ljMXNpjbD9SYkAtY9rv2es|ru)U7Vr=R0e}S(qgKYiHv~twJ|Uj1v?SDOl<{) zZ~e!vK;7rV;p#HMDuuLI-vPS4NJr&rb(x^l^LGUjW=gBT^YTNx zu4|O!Rv2W$NHE2*gp1g-k#5cy{i^sc~UOGd&*&>O$cz;WzpY-N+T;7 zF{f^Chxz7<&>(@T%@-UpN)6yyiquK}r9y4w_6U2Mu*pe0EaJ*Vie z`0}Ed?_Nykkdd*j3DSScIu!Dn#PRjXzlAz^9$neTdiV%o)5jVq0t9JR^U-)E?JwG; zgM0dI2;Y#SF5w}rm!RQgd~v3HH}pqGWK2dv<+x3Nuw4s!I_q68*ts&5TlzoS8$VX`cZSU^w5sJEXp0RQX5Tf5`L8KOv*OHfKJYv7;tDB8LwIC= z`UA()2iLAb_%7Iqa{`T>b4fzlgiSKOb#1=ZnFI6n1tsw%d_*{~X9eNCGk}WsIo2Bx ze3wG=*yxqGSn6hX;?%)iz7y87+d4niUh7(_rvU3@JH0 zVaG*OO8(UeKE0sG33d(s?HVwVB=FuH&&oyrm%-+|jmT!CI$x38dYIFAQ~$d}9ZV%T zFwjmQLdy{JyC0)x7J#j$V|%JNre;MBD#6fy0*V>Q$a^8&eqx6IB+>xr=`cFL;_k?s z$|@j%rumYy{wM4NUjI{TPxw8?2rXI+hfsNzcg~xOIqk-P^NIINO<^L3uR7#kO~?>J zsRCoPLIba<3G}fZtBQeCRRBAm&)%=BN@}YuY%>f8?peJGJiNHY_0;q6dW=dUVVG_$ zEh?Uc{zv_Ywx9r4D{@~0s<44YR0(VF6&9>glIAtNzgUX9=*c!wDFjY4Ofa&AnB~3p zcqdRVqWNE#C_h0WQkBSohhMMpLz@3w zndo40d*f9C;vd50sax^2yi?O>AT8gF2{w|L^+%5%-{^5@8$W*dGfaQnlko+-r|Vgf zzXVCz!Uq$#X4@4obZmsD)Ns!IVTyo@#;Zj2JFL}P;!ETfsCt|I^>G9BQv?U2wf}aU z#mmt(@w$Mv={qt$I}e2yE*$+ec+6F%?OzKcPP+J7w}$+E(^pk8=sI{vvsuPmVm$xM=uc-ad?VVogzBk$Y{H1sKbBeU4^bIFsg}ffm_fNMd zo5hW)?}aW`;a6H;3U`g+lr(382TV4}r_P5>P!Z3i^|HYAXvsl>nzQ`C+lu9txa#4u z=$px=3IUzk-#S&4efGY;{rOBwJt3 zjHj$s)13Bqle!mqi^FIl~u!bd$xJ1=l5;(J*`DPFj;d3&9k^M z&DF2@%=y2u;x))&nDo%F9`U1o$W$mqdsLsHj6u}<(TGci>eo`gcpeKDDs78^ z9Za-&Q|xM6z_dH_6D&4MedBf)?{XO-fq)UzBD6LFk>3pcd1OM7+}lag1ZVm*IHwCi`=6 zj?4VyQ@0Jt;%03vH*qVZ_6m*TF?o%=h-hV-OVt6$L5FA&j@}Ge#PQFp;r#(-#jc+a58PUj67`J!jio7G0g*do*GzF9#A%DTdEN^zps%iw^g z%H6U5bDy#Qx?H=g#-tZ``~5Z_oynVEHeJgQLrH!5h{2S`Kfv3R&xDTD2m=;#Wk5TY zhN9ad$qC|mqkR6cg-XuVmSv`FTzEAXIfIbazSrts(UiyM=hN)^HT_hG>NVhE3B%VK zRtaus4(~4hD;rW!9pku5Oz0Y%A!C>st-IgubI*Msia{owv$)7pBI?5~pcO*Ti3)dP zdJD;dzZ0?(Th|gZ7vmLzVRm9Mqbzc<)4$f_V3_tBRUNrW0fB(|+u+7iOBecOkV3#7 z@5$`;t%L3+eHrfqn+=5n`W2M&Ehe9fqD2pB1oOFuGa%YY$;rBc>7E~2e2`Dr{%gm) zN9U+cQ>n&Y33G)3RzLUX)z=MDW0-zDu^rJ~P4x&4t$d%si;o=y!_Atv1A21^%2Kul zX=}+J>#d-f6Usm}Q5m=%s&c>I(e{05@)gKiQ5LLN+H}4ia$ytsR`;Jjk(G66T*BMT z&-^&N1pX?NeFy>+DH*loL$~Z z4U47rLqY6nGFA2x9g3-_SnrwU96*|>t*DR&0uGzwK;0J=uA3o3-t|5;FloU)?zKoW z^huO<37nDY*Oz>sGORIk>fNN7o=$+*Oq$CniOA}cbJby=a2)B+Mt38ys1dLfEnDadQd7Tf_iojy>JU}IX3tHcN?bqAT`F~El9oAa4uKMj zn}&3ZWQdf{OQ*+V-#5LthK}Y0+V#}YUI-u6COHVib%E1?6VvVl!LEKu+3_5penB4K z?1midNq>`7;dDO~TgF$2RBvN5nYV;)bK;EwJrYbZ(j7*tyg_SM^69b{Y`mL)Q_SVp z2_FaJj1+3DLH|Z#Ir_TFV^Mv>2O4R8_lNi!Eh?2AxgDSIyq^#~PO4u4bDqh3pTEHv zv}knBZ!B4nVfzN zrLxqVvv5OXfD_3mRdXIllNV_+11qe{x#(J1Z5PUT1!f81PZuhJv-@-bZHykab$70VWBp1;c z2FZ&jr8@2yg*%54DEC_Ai!|^j*`?z%I zPRfBCT2ouwD`^d`MUM8(5f^=U@~}x`67ke=M^Q0e(9B9TUVO# zHq?eXowVy_X0)=^i8mugg~nS^XJn|7^T}%Av967E^QnkRMRVka+@+kY@9se%rEkk` zj1)W^Ww1>8N1bysek44&S=|bEqUg8NobLL?Ei=k(y6wjD<2?_>g(N>`het~P7Q{sW zo51mAl5~v*C$-jeMKs#%{?EO+Qi1HtC1<)vJpvLn?AlUW!r}+J$7ZQAK7|->Z8@*x zNLs9jHL8O<9@L(3rh3BjV(&pqw9g<2#yJ(hXi7r$Gjoh?bPElV$-1cBnTjL^D`ZBi zGFB#t8Y6nguqH@rK{7gqnzJzq@r=fI+$kE$q?UhHl=9DfIx=KcU3^#gE2+T@xwe3d zftrpU2}i1Y{5eSJ1Jp~7vL%98oJV~q#-+L~0+3AcPxc@Mua_!x`A61tKPK=Ktv~jA z-QNc-`0$qe4t7y-yQ4)nzwW{&x`iSwJwhWRgr;^KYulGjN zZdl#6KjqB;`p+H3W4!!-Q><>2q;BzFj042lf>^84vguUgz+B~F37y1`*dRJ>yX`}qm&{3 zHmd5i&e5->cOm`BtwqWF!FPzK7*+Z|Gk$@lmZlmi@+w-N5Ts8B^EH&=f9dWm-sL;o zNf72Cu>KGoUFoCGGeBD|!Ea?Z{1#?$NzR2b!l?FttL!{t&gs>1;a>PoQ*8!(<6&#- z=j_yZs{MJxg<-us`73`?74Nzs6S}r1p*Zq7eH=72eukkf;6rLMC~*#jz%?&HOm@#r zQ*1Wzh+Kl5pOLQCbAL$E-0Say=UESkByC)H_8;B8dkh6q{uLbVL9^M>uh{tPc0y(S zx6dKIfAnO->wJTD98E?K3h1FU20qjNUZEm1+FA=nG1YtqvqIt{K4rS^S((}@1)%5 zIe)Ve6zbTt?n|7aXIKQC>aO4aDbW9mEI%^8gb{6dvD)wRiv~N{)B~Px?(S1Mb=jQZ zV(x*L_GpY>3r4Kn`)be5QzbKGn}y+w zd?qd|xpt-EbOi_}p-y%9=&wtc^kfe5ZwIB`j#u^S@Y_VIRK1r!C$0Za zz#(F!>c*q$0fXKq^J=o0>#rwI%~m<@Exw6E>eYv_Tsb`Vz^A`bzjV<_=vv;!_m2l# zLpm2wMR~nEM@GB96aN;c&@hoy*NW7$d%0(NBj}vNg`8<<%(1l9HW8ncM$7Un80gQ| zU-sVsVP?<upln#8Y4dKP$dM$WNE+p~;1h+B~n}zTe9V?UeM~`l^ow{t=@QFCnQckM<)ai#+>wp5)gBEkGwTG;wFTeNLt6 zuv`h}eYta9W}SN?u+2D02@=L?ouVhV?wn(a8F;l_zqx6^fhMQai!?s!`*mR9WA|R( zM&4~lH+J8uv)E8CHz`-P@``LSm*j)n>pvqaLk^$)?K3P~xRd^AeEn!Z_i|FL$Nx;_ zbvm`$-)&d68|i?XhLSGbjkL?vjVXzB5gG0)ef73&H4HNHVti~N2ymZU*epk??F)IY zwj-?64)(7L1C>_D4${x!tRerHv~el1=#6sHE;kIn>aM|3|Hkv!8U}~L5r1~9*PQ@Vme{r zl@A@2Y&C=7S1tu#*+5Tm+#Vul%LSiJ-U-5Zke2M>VU$|elH#e#LFv++n+~aMw#;C{JTjTly50-3PkLh&2p3e!?o{0M2omUeFQ2k{$ z!#X6096y6@7|nWO-^X+EixHN4R$9MtDrfeiks)`$!YMa^;%aai3{|l`;QjX$O+9Qi zwXKn1`|nb!$*4od5jg~-+7LP36eKc3vAFtM<<5;ql63+7emCxxr%E&uCV2dQ%nWNX zjmC;Lx;`s6!)ajPaOl>9CEl#du>a>oU8JgjcV{`ib!l(~nop%N90i#0P9=e@=3QN} z$u}<`;d>uo%#1HeU`)dx#~^=cNl>9b&wk|l$WnL0n=Ul=?_VXxojHMR(vS_1D9BsDmLuWW{MPjvf_j-G zSu_mRaDoso$tK6JUYmNHZ3bk}lh<#ok#fuZrha{xnp`);P3cyltenH{au;Fcn)~`h z+}araH!$mp0oXJ9z^{n)gLlDCXk3{d)Km1+54>!?%^y$3-qgD_@-RMHFTXz`WYH~l zR(5h`FmSp0x9|4#1n?*o48il~<~}8`wB2B^81?Yp5Lt9a*EQLh3$5HfikXu;SwTS6 zy~9jcAF`6WcKJ!{Ew#o}wUS9>mPO>5O+2rxSnG=dV zym@u;u;Sb+37x@D(PBC-fo&|ksOINXLKLGF_Qi8bV-Q#T-s$e-??GP0+srfkGQuAd z7-Kv>Sn(dG{Qsyk#Z*TX(B0;z7reh201l0l9K9#JS1YYqvYYyqOQ8DIS$r(+QTT6= z5sOR^AdNEm0L{tarNSGEk?Pq&F1VMMI~Il);4qSgT5)C|K%xNCt@@+v?4;6yJRP6b zzazUO%Ht3;AxIw~Mit84YXp>oENi z!YJb-4QQem9BZE-4dMyP^j({3S*0#qjnrFYx<*In1ad06@dQae+@KhV{7^*wiHPk} zVlnyijz$Ji@$QY8pW@gt^Yd8emU8jlo`H|Ee(CEzOS~ScDsP~w}d$j-NG@m#t*C3$&IBazh3X2i=qg*jjd*} zP*I~vsYw(VIv}}-H#top)jZLgL0OHn{}@0o^aehh3jC9Ta*=IGmJxBSXWP`?k3 zLWv7RXW5)x@L}hhdZgCrn8K#(*}&ma-*AFt@~fe45S0@Isx#w`q+?awE63`%k@BBP z>nFzrGQy&<8`YT~Wufr=hL=tv{3UPhTDg7x;sX~H@BOA=|7h_~w5|zKu3kf@%(TB;6rKq?=wBc3wwp%GiD>s*E zX^FF7>ZMUMsEs%8H+V5grL4A_z&Ti~a`_aPc7AQ;C@m{HpB1Cri6|wlY^|gTJ!pz> z{C#}-54~`k(E$yagJ!~qFN2(EB7S2KeyJLUmA`UpN8Ivi=ER0RWi}sI&bH{ZS zxxy3aLf3PV6I%ZLA4;np@DV~HP)GfCTx8<-eqFjZEr~@R9QFgBp1JQCc^aGaVeUXi z=GfK6IqGG5>p4;817wV=-r}k(_Mq7nbzA2Cif}bP8~379n12@a}OMofZZsx%xqgQ+Tn8bE6dGdulDnck&Y^BRzo^`)5p1)4c_=zR6Y~0 z-Wz!d9RK>Om|92zDbe^crd-I`l#^n?(U9WghVwZad zgnhO_n8E7fuplvbls5!NPaT!YZs{KoH$k`}7B>miF6WcF+aBHvkGdtwBfX@us_e_B zZ)fo-+P5$Olf-hq(faPuV1+75XXn0Sj3%o|8Xf3b<7;>=OXcKvc=J?bVQ@E`^i~yWO}O@x9(t3Di4%+M zEF&9_JdL^}>*O6#0G`7v-F+d(kD}9Q(yXfk^Yq@_4j6I0eezbKwtT&dIJN65^OH6JTxiS9$>(lAMXA0=)!C>N-Q;8xU zD4Ec}_X7Rw_WeBa`bhd_1jQcURum-+w^0g;~ zSO*jYAk@WcEv(aL#x)~}cxiDm`wmS*kFm~QiL<}231xa9Oo8t!-@G6?)E&e!CCuR~ zmVA2t%$naTL5qdZuSidX@K+d)aT)5$1Iw9BVxr3xGX_{vswtXrjCEReo;}L(j?5b$ zlu7)h0h_5;+XE-d@%1K%pUAfu-5`urgw>P?@>o*n?qkndG$0zzscV!7qVw^yzAdse zjx+z8x)8b*bK|IM_JwXt^d6#RW8~^Fmh4fOuisrP9X_=iP47!%Q2`4{VK+i$um^=A zZ%|-mCX*9YnBO0yhziHyOCjsr%!nX2TUKq3@Ve`Dz0ArA)AKHx^oa!vdYZ>g7fK!C z_AY-OL~YdJS-mvfkN?Z*?R!gD{vKHV{b-d^b_C=R3pNLeix ziZ+U{Oc#IiNintXoJkW4qn$d=h`-vQO(Ni!-*Afx=Hw>|zB%VYnVNR8S&kXw8zd^g z+5_?g9X?SaeUVKh$yFj6|LMMX17(W~hp;C{b?L)zBWvTh3s4TK4x;l5<8d({*!jyY z(MQ+YpPaXb@O`J)nApU`;_$_@m|<34kVg%BN@O-gcO9n>L{qZni5^{sD)^rK5f`RCx`dQ3nJnd z3W<&SUv~@GHLOks4xBAhS9S=j88+L!J|&Cunc)6N2Y8!m^^T6_*F4vNCB6;?s`2_k z?68~^teRPgvYbRrK4$q=g@<{X;|u6DzIf65(zbEg(L~IB>N;q1cgM=Od#N7kT6qMm zka#I+z0fmxmD}#fXYi#ZRXuvTd|1@e$ld zht`5V<9^D#jdvg0F&`)FDG7~kH23W4yRz+P0wd0nBNILy*Ju$V3o!Q^RIqo|_-<(R z;_HI!k%7;|en}t-x-&&lL7Cg9iz7uenSh?&wy(9qTm{kUktf2`+*@NwxM81V zO8SY}teDa$S?8eLpY$6@l(Tr=ttA6IwYkP#kWzDh<+O;A0wn6$b-+&?xAKYp=lGIB z>}l~{UX)njQE2w0*^**~Vh6cd%;U?fsRTt$Y85&5)5Eq;i~Pjg!5z%QRNu`W`h9YN zBZUqLr~T_9#!petIlYAM;wup`GW4d2dcGd}RHH~`7oSvbXKr$El5iLYcWtdVE1h}5 zzY$8c%1M=$k}P!?SDKMM$rv4}{(?m(0Q^iOju>OctzMee`s@tvQ>}7%E}hrNm-fo( zJH9^OVobr@QbStZdbic8u>%7SjIU7v#SLCE!w7-S2toTv z);yspU&t3FORA}LFffB7KY`KRswSJN9KVNSnKahB%2;Cq-Ou?LecYYVZB+WG$cMN1 z%j&nRnF3~Vi@4O3G*xF8ADM+Hf>?5B^`naAQN~F#sLW3xsWE3)QMX>AUd4l&uM3j8 zs!OgTAzJ9&qs39EjDkVs`Dk=YAbHfmW~zRD`N39;Z5HNFtc=xHKP%lCWjs6n=c-Rc zzU#xjcv~+$&OZs{2RN-2=gH~Rm*>2-(gZAJY$YBOaIqr$dmag-#jEYvE|$-rW2@Pa zi92CYp4`Vq%PA7|>K&h3_uAu$8 z^^5!OvssaSx)8_XWZ2fq$Bm7T>6e#QvB>$Q-(7R%$#1N*nCEyf#wQj*e3J~#OL7<< zP>M!XE4QEJ#y|$4CBf8tNP4Ix>(nPm2NWHCf~1SMOcB^!>?loH?WB@j)fWnV%c*wO zQxX{G#GguQGlj+iQhUVf5{b$cB1OdAsZ_%I6gj=z+i?TFN7uo@LF3Y!34L*} zU9II=_fT}}fO_4-ysSo(EafGpCxHA6hRLa4_p-m({klW)yB=SHgE?+n7&cHM1@mMU z4&qa-lh7a&Sc&x-H(9P3TX+6FL!I#}uQ%g^V#pG@TG%ucSYHV;t@pU{Qw*S?7aPdi zzG!bDWn437wn)*7*EkD>1&5_s@E#dGww)6Q`^~~)9te(f`iDL07Ye?g>+vkJ1bx=B zGXyH3tv*w0UCmqqN>zo$*+27QfjSW_r6r|AdfL4Pk#h<)!KpY5!ROqcSky9tf86KS0e;O{uobkoZq^U|_Q*^veD}NOF|o_^Z-9L;l2R@L9fwjq7Dzz2|@psYs@MZ1MDk zruiFoSt)l1)~ zWR1kvwT@Dp;^$!95KdN`a(C@6I2m9f2m3f#H6!9;S9wuy)Km{khcTlIU4V(VH70$( z@&W-FVL+<T@&0CzE4NkejN`9TU}LN-*ty8dXFtmx4NCqemRI_-FkGMm}p z;HjFP9yRjiWrp{XO5+8{`8PkY*!@BUzi{M{AOZz5O7gf7VSHcMElH*V`7(+vxu2#G|AB@Wf(45icap=tU_drQYnMd+N79+)b=>AtRQN@Mb07}AN%ECy2GVr0B;2QwR=|P#vGdy`# z1eYeS=nSlGo0)${Xm9MDEYhG6xh_$AHpb24yxiEMR42CY;?t3u#!SlBSpKN+G6q~; zDaMJQ_4YjOKa9Hw6IPJ>gV6ox>0xsA`>f>JWsPDY@>1vqv(0Vcy|MZHTuyr-BsDD%3U9Ngm%*@PH2vgaj!=4WQ_V9`>L#28@FKPyP5eM}|-I z{rjw~7=qY1fI(u_`F`|bznEev^{ElX=sR?zChuNp{))Ff8><1*&SQIUC8Mzw#^u3D z2tR*BBXEob2TcQx^3{XZTNWC?o*lpNI@{*-cH8MD&N;d}*ezu<-e8C7mKSW7uC2j@ z`M6nJl^#8?YHpLYxG;G4ul}k3iE*4Mf4+2pCH+(|U*`4=4fgF(rIcJjkDHB+R&Ph< zc4%o)qx}G(If|)Tq}tkGBfqtWtRbuA?(4U^<%3cJ9ouFYw(`ik^K=U)}AI*$5mkXpLj4%!>QC zXfro)G-b)1lzrFiE^lK@q!BtKx}_beU@&^#x2&P$%1F+0o4vD`!yrBt$^b4}J^zS_ za*_?oza!}PmZSfvyf6x&ELAe3XclDvCImd!8!`urpsqk*C@2>CYcGFleUOja8k5K3 zJkt~iAwemO{PyHb=s#NxZ382rfA;LeMne-SR+*twUh@wG5B91yjz~by)7%i!YrB2- zeGU$z>-KM93Q5k^m^avZx&h|1UMGXk0uwn#P8id%=$}Vdub`rhmLj^>1C0G z7MLy%gIB{KA<`r2%&pjl=y=`d7!aR8o8q%)bF{aBb2N^$&*X0ehx?qs9(nIx-iLG5 z2jF|$9>J6zaJ^4FKA+K-3_qt|=OtF9sF8Sox6@!WLF3HZc?5{ItAJWTpxxvq7#rX) z1zuqLj!Rgv57oG)E4mX?^{O1kzp2c4tiv(P-u_atiY}{eAT=E>yPFvsp`zcvd9MLn z1YYV}Zdv88u=e24IHIkdDMK4lie41`hf?jNrU}W7F7__59@!7^?nw1;9XBwdngh-8 zTOk8VhufplGTTLvhW)#uZY-I0dwoT#H1@HCDUC3nQ}sC9e(!`pPA~WmM!{e00T?{e zaZSgtkulo~zE+{Li@@a=S#cf$XQ2$Qoz7zaA4mOtI&xmyo3M-x~u@B zFGrjg!h+Tnk;&QQI|9#*M61H>pjKjlds9l%g%>P94Fa=hNVrAm?2)17;fYc9tK-J% zC%Gq`y=JTg%%Xx71QQNHC2Y@sYzFx!?)&Zb4U&QJzL#`OFa>}!Pk+QP+L($FLhP&t8S#57sPZi4_lW;!e*BF#cv?xQpOp{q z0D7n(Gj-*FBdP!c{wp_)-3SodM$H+T)zEbbO6IcVNe=}eg#u_YcQtIEdDWPmUMJiV zk@B<`mam$1CP;Z!opyVBR$4C*GMpGj_)2#UC{Sh6r>*=gk>9CM5T#W!{#cCf1LQs<(@SdEflj5=}Dkcd9*?NI^FE{iMW;_00Xy z9=ncvu$3y}e3HJVgBqRzKkP1=mR!N9Qu{XOju6;qOYyp_`zu^~jQ;HS30bkP#+_ew z;&JZKTHkA(%aQoyIEfb6Pih!F{#>B=!b$@T0PieUfVXGuhc}qf?{~abasOK9?_i9^ zy$|@Vb8AYT?w;MPgrDE4r1kJeKn%VBWz#ZFaEOK@>nSay-sRvB2_;e4HsH|umOdLp zhVRZQgwxGDr>~k-vO&&B=!jGe_O^YCj!IAhwp!%bEgN>zJlp1f7zuyMnfZ@Cg%jNG zEBvI=gGm80(Xizip4K`b;id=Vz%3~|<>OABi+Hw-zq_-Ik zIyo53x3Fww4_BYwna;PpdflzV&6Ns=*w@?cZMk(s41C(H-bAkNWzJM4tf6D8M$iaM<_)goiP!S(~#*4xwaHM|DkhtNoc$CUZC-f!#cJ(txCH^Yk@YW=G>_@Au$xq+$$j0PaChv7zl)*Wa@WoB*u1q6d` z(Z(Z#V`*Ww(8NM58wz>}U4g0Sxul}2D(PM8ryCC;J$-s%4Mvp< zIc1SR+&PvVkpq{})e8Hn9nbj`6iFJ@w9DGA;jH&AfBPSi|Gz{oK6zg>0SUN$ffN9Oxl@YriPxQ6WCmX7vB9VtjyP^jUgdUZ5>O=wY0dmc@Pl#?<#aby5k|51Y%b*WO-GQTVK`KblS;tWu9lH0Q z^~%w*Me50yIOg|U7QKc?kLgUluEyr(yPPUdffiVu7t3}B`-rX{RE8UVsmXWe5i1dsGhR=dE!vnCe!

Omq;4q6NO=8qCS^XL8t7k*|(D9Dd1e*_RN8C86 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