diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm index e1097d3f68..0ca8a35149 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, /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 a9beb9540e..dbe8722b83 100644 --- a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm +++ b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm @@ -102,7 +102,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, /turf/open/floor/mineral/titanium/yellow/airless, /area/ruin/space/has_grav/powered/mechtransport) "B" = ( diff --git a/_maps/RandomZLevels/VR/snowdin_VR.dmm b/_maps/RandomZLevels/VR/snowdin_VR.dmm index c0977f00f0..d1e3373633 100644 --- a/_maps/RandomZLevels/VR/snowdin_VR.dmm +++ b/_maps/RandomZLevels/VR/snowdin_VR.dmm @@ -14451,7 +14451,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; icon_state = "ripley" }, diff --git a/_maps/RandomZLevels/away_mission/caves.dmm b/_maps/RandomZLevels/away_mission/caves.dmm index ed246ff8b5..e33659fbdd 100644 --- a/_maps/RandomZLevels/away_mission/caves.dmm +++ b/_maps/RandomZLevels/away_mission/caves.dmm @@ -2039,7 +2039,7 @@ }, /area/awaymission/caves/BMP_asteroid) "gC" = ( -/obj/mecha/working/ripley/mining, +/obj/vehicle/sealed/mecha/working/ripley/mining, /turf/open/floor/plasteel/recharge_floor, /area/awaymission/caves/BMP_asteroid) "gD" = ( diff --git a/_maps/RandomZLevels/away_mission/snowdin.dmm b/_maps/RandomZLevels/away_mission/snowdin.dmm index aa4dd61154..dae17bd259 100644 --- a/_maps/RandomZLevels/away_mission/snowdin.dmm +++ b/_maps/RandomZLevels/away_mission/snowdin.dmm @@ -14452,7 +14452,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 }, /obj/effect/turf_decal/bot, diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index b783678c86..39240ed7e5 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -31,12 +31,21 @@ #define COOLDOWN_OBJECTIVES "objectives" #define COOLDOWN_OBJ_ADMIN_PING "obj_admin_ping" + +//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" + //car cooldowns #define COOLDOWN_CAR_HONK "car_honk" //clown car cooldowns #define COOLDOWN_CLOWNCAR_RANDOMNESS "clown_car_randomness" + //TIMER COOLDOWN MACROS #define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]" diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index dad0f49832..ea4fc2c361 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -526,7 +526,19 @@ #define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" ///sent to targets during the process_hit proc of projectiles #define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init" // sent to targets during the process_hit proc of projectiles +// /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" +///sent from clicking while you have no equipment selected. Sent before cooldown and adjacency checks, so you can use this for infinite range things if you want. +#define COMSIG_MECHA_MELEE_CLICK "mecha_action_melee_click" + /// Prevents click from happening. + #define COMPONENT_CANCEL_MELEE_CLICK (1<<0) +///sent from clicking while you have equipment selected. +#define COMSIG_MECHA_EQUIPMENT_CLICK "mecha_action_equipment_click" + /// Prevents click from happening. + #define COMPONENT_CANCEL_EQUIPMENT_CLICK (1<<0) + // /mob/living/carbon/human signals #define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target) #define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index f893ab3dfe..cfd2cebbd0 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -207,7 +207,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, 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/logging.dm b/code/__DEFINES/logging.dm index bde3189272..87e7fe3ce4 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -39,6 +39,7 @@ #define LOG_ADMIN_PRIVATE (1 << 14) #define LOG_ASAY (1 << 15) #define LOG_VIRUS (1 << 16) +#define LOG_MECHA (1 << 17) #define LOG_SHUTTLE (1 << 18) #define LOG_VICTIM (1 << 19) diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm new file mode 100644 index 0000000000..4a90a32d08 --- /dev/null +++ b/code/__DEFINES/mecha.dm @@ -0,0 +1,31 @@ +#define MECHA_INT_FIRE (1<<0) +#define MECHA_INT_TEMP_CONTROL (1<<1) +#define MECHA_INT_SHORT_CIRCUIT (1<<2) +#define MECHA_INT_TANK_BREACH (1<<3) +#define MECHA_INT_CONTROL_LOST (1<<4) + +#define 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 QUIET_STEPS (1<<7) +#define QUIET_TURNS (1<<8) +///blocks using equipment and melee attacking. +#define CANNOT_INTERACT (1<<9) +/// posibrains can drive this mecha +#define MMI_COMPATIBLE (1<<10) + +#define MECHA_MELEE (1 << 0) +#define MECHA_RANGED (1 << 1) + +#define MECHA_FRONT_ARMOUR 1 +#define MECHA_SIDE_ARMOUR 2 +#define MECHA_BACK_ARMOUR 3 + +#define MECHA_LOCKED 0 +#define MECHA_SECURE_BOLTS 1 +#define MECHA_LOOSE_BOLTS 2 +#define MECHA_OPEN_HATCH 3 diff --git a/code/__DEFINES/vehicles.dm b/code/__DEFINES/vehicles.dm index 1ff14f9506..0255327ed9 100644 --- a/code/__DEFINES/vehicles.dm +++ b/code/__DEFINES/vehicles.dm @@ -11,6 +11,11 @@ ///changing around settings and the like. #define VEHICLE_CONTROL_SETTINGS (1<<4) + +///ez define for giving a single pilot mech all the flags it needs. +#define FULL_MECHA_CONTROL ALL + + //car_traits flags ///Will this car kidnap people by ramming into them? #define CAN_KIDNAP (1<<0) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index c7834dc5ef..239ef319d1 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -55,11 +55,6 @@ if(modifiers["shift"] && modifiers["ctrl"]) CtrlShiftClickOn(A) return - if(modifiers["middle"]) - 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(modifiers["shift"]) ShiftClickOn(A) return diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 773adc061f..c9e20bc01a 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -82,11 +82,6 @@ if(!modifiers["catcher"] && A.IsObscured()) return - if(ismecha(loc)) - var/obj/mecha/M = loc - M.click_action(A,src,params) - return TRUE - if(restrained()) DelayNextAction(CLICK_CD_HANDCUFFED) return RestrainedClickOn(A) diff --git a/code/_onclick/right_click.dm b/code/_onclick/right_click.dm index 4b2480eb8c..c1613561b4 100644 --- a/code/_onclick/right_click.dm +++ b/code/_onclick/right_click.dm @@ -11,10 +11,6 @@ if(!modifiers["catcher"] && A.IsObscured()) return - if(ismecha(loc)) - var/obj/mecha/M = loc - return M.click_action(A,src,params) - if(restrained()) DelayNextAction(CLICK_CD_HANDCUFFED) return RestrainedClickOn(A) diff --git a/code/_rendering/atom_huds/data_huds.dm b/code/_rendering/atom_huds/data_huds.dm index 413484b99b..d25dcb5380 100644 --- a/code/_rendering/atom_huds/data_huds.dm +++ b/code/_rendering/atom_huds/data_huds.dm @@ -381,14 +381,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 @@ -399,7 +399,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 @@ -407,7 +407,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/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm index 9a0665e91f..35997a8d89 100644 --- a/code/controllers/subsystem/traumas.dm +++ b/code/controllers/subsystem/traumas.dm @@ -159,7 +159,7 @@ SUBSYSTEM_DEF(traumas) /obj/item/storage/backpack/mime, /obj/item/reagent_containers/food/snacks/grown/banana/mime, /obj/item/grown/bananapeel/mimanapeel, /obj/item/cartridge/virus/mime, /obj/item/clothing/shoes/sneakers/mime, /obj/item/bedsheet/mime, /obj/item/reagent_containers/food/snacks/burger/mime, /obj/item/clothing/head/beret, - /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)), + /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/vehicle/sealed/mecha/combat/reticence)), "cats" = typecacheof(list(/obj/item/organ/ears/cat, /obj/item/organ/tail/cat, /obj/item/laser_pointer, /obj/item/toy/cattoy, /obj/item/clothing/head/kitty, /obj/item/clothing/head/collectable/kitty, /obj/item/melee/chainofcommand/tailwhip/kitty, /obj/item/stack/sheet/animalhide/cat)), @@ -169,7 +169,7 @@ SUBSYSTEM_DEF(traumas) /obj/structure/fluff/empty_sleeper/syndicate, /obj/item/implant/radio/syndicate, /obj/item/clothing/head/helmet/space/syndicate, /obj/machinery/nuclearbomb/syndicate, /obj/item/grenade/syndieminibomb, /obj/item/storage/backpack/duffelbag/syndie, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/gun/ballistic/automatic/shotgun/bulldog, /obj/item/gun/ballistic/automatic/c20r, /obj/item/gun/ballistic/automatic/m90, /obj/item/gun/ballistic/automatic/l6_saw, /obj/item/storage/belt/grenade/full, /obj/item/gun/ballistic/automatic/sniper_rifle/syndicate, /obj/item/gun/energy/kinetic_accelerator/crossbow, /obj/item/melee/transforming/energy/sword/saber, /obj/item/dualsaber, /obj/item/melee/powerfist, /obj/item/storage/box/syndie_kit, /obj/item/grenade/spawnergrenade/manhacks, /obj/item/grenade/chem_grenade/bioterrorfoam, /obj/item/reagent_containers/spray/chemsprayer/bioterror, /obj/item/ammo_box/magazine/m10mm, - /obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm195x129, /obj/item/antag_spawner/nuke_ops, /obj/mecha/combat/gygax/dark, /obj/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate, + /obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm195x129, /obj/item/antag_spawner/nuke_ops, /obj/vehicle/sealed/mecha/combat/gygax/dark, /obj/vehicle/sealed/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate, /obj/item/cartridge/virus/frame, /obj/item/chameleon, /obj/item/storage/box/syndie_kit/cutouts, /obj/item/clothing/suit/space/hardsuit/syndi, /obj/item/card/emag, /obj/item/storage/toolbox/syndicate, /obj/item/storage/book/bible/syndicate, /obj/item/encryptionkey/binary, /obj/item/encryptionkey/syndicate, /obj/item/aiModule/syndicate, /obj/item/clothing/shoes/magboots/syndie, /obj/item/powersink, /obj/item/sbeacondrop, /obj/item/sbeacondrop/bomb, /obj/item/syndicatedetonator, /obj/item/shield/energy, /obj/item/assault_pod, /obj/item/slimepotion/slime/sentience/nuclear, /obj/item/stack/telecrystal, /obj/item/jammer, /obj/item/codespeak_manual/unlimited, /obj/item/toy/cards/deck/syndicate, /obj/item/storage/secure/briefcase/syndie, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/toy/syndicateballoon, /obj/item/clothing/gloves/fingerless/pugilist/rapid, /obj/item/paper/fluff/ruins/thederelict/syndie_mission, /obj/item/organ/cyberimp/eyes/hud/security/syndicate, /obj/item/clothing/head/HoS/syndicate, diff --git a/code/datums/armor.dm b/code/datums/armor.dm index 88170541c6..b01b5ba238 100644 --- a/code/datums/armor.dm +++ b/code/datums/armor.dm @@ -1,5 +1,18 @@ #define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]-[wound]" +#define MELEE "melee" +#define BULLET "bullet" +#define LASER "laser" +#define ENERGY "energy" +#define BOMB "bomb" +#define BIO "bio" +#define RAD "rad" +#define FIRE "fire" +#define ACID "acid" +#define MAGIC "magic" +#define WOUND "wound" + + /proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0) . = locate(ARMORID) if (!.) diff --git a/code/datums/components/armor_plate.dm b/code/datums/components/armor_plate.dm index 763aef6a70..ee3d11924d 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/examine) RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/applyplate) RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/dropplates) - if(istype(parent, /obj/mecha/working/ripley)) + if(istype(parent, /obj/vehicle/sealed/mecha/working/ripley)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_mech_overlays) if(_maxamount) @@ -67,7 +67,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 @@ -80,11 +80,11 @@ 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) if(amount) var/overlay_string = "ripley-g" if(amount >= 3) overlay_string += "-full" - if(!mech.occupant) + if(LAZYLEN(mech.occupants)) overlay_string += "-open" overlays += overlay_string diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 925ac41a0b..1f57c1ced8 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -896,9 +896,6 @@ SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) dir = newdir -/atom/proc/mech_melee_attack(obj/mecha/M) - return - //If a mob logouts/logins in side of an object you can use this proc /atom/proc/on_log(login) if(loc) diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm index 081ffbbdc4..c75fe42884 100644 --- a/code/game/gamemodes/clown_ops/clown_weapons.dm +++ b/code/game/gamemodes/clown_ops/clown_weapons.dm @@ -243,7 +243,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 @@ -261,13 +261,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" @@ -280,23 +280,14 @@ wreckage = /obj/structure/mecha_wreckage/honker/dark max_equip = 3 -/obj/mecha/combat/honker/dark/GrantActions(mob/living/user, human_occupant = 0) - ..() - thrusters_action.Grant(user, src) - - -/obj/mecha/combat/honker/dark/RemoveActions(mob/living/user, human_occupant = 0) - ..() - thrusters_action.Remove(user) - -/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() +/obj/vehicle/sealed/mecha/combat/honker/dark/loaded/Initialize() . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/honker() ME.attach(src) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index d1781d9477..24e3215d82 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -107,19 +107,6 @@ return 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 return /obj/machinery/door/Move() @@ -362,7 +349,7 @@ C.bleed(DOOR_CRUSH_DAMAGE) else L.add_splatter_floor(location) - 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) /obj/machinery/door/proc/autoclose() diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index af7545d3c9..4c5aa6528f 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -77,11 +77,13 @@ return if (!( ismob(AM) )) if(ismecha(AM)) - var/obj/mecha/mecha = AM - if(mecha.occupant && src.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 e346439e03..cac7edf8c9 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -478,10 +478,12 @@ for(var/A in GLOB.mechas_list) if((get_dist(A, base) < scan_range) && can_see(base, 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 + 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((turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) && GLOB.blobs.len && (mode == TURRET_LETHAL)) for(var/obj/structure/blob/B in view(scan_range, base)) diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm deleted file mode 100644 index f9a86066ff..0000000000 --- a/code/game/mecha/combat/combat.dm +++ /dev/null @@ -1,11 +0,0 @@ -/obj/mecha/combat - force = 30 - internal_damage_threshold = 50 - armor = list("melee" = 30, "bullet" = 30, "laser" = 15, "energy" = 20, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - mouse_pointer = 'icons/mecha/mecha_mouse.dmi' - -/obj/mecha/combat/proc/max_ammo() //Max the ammo stored for Nuke Ops mechs, or anyone else that calls this - for(var/obj/item/I in equipment) - if(istype(I, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/)) - var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun = I - gun.projectiles_cache = gun.projectiles_cache_max diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm deleted file mode 100644 index 498266d043..0000000000 --- a/code/game/mecha/combat/durand.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/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" - step_in = 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" = 0, "fire" = 100, "acid" = 100) - max_temperature = 30000 - infra_luminosity = 8 - force = 40 - wreckage = /obj/structure/mecha_wreckage/durand - -/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) diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm deleted file mode 100644 index 71258d1ccb..0000000000 --- a/code/game/mecha/combat/gygax.dm +++ /dev/null @@ -1,68 +0,0 @@ -/obj/mecha/combat/gygax - desc = "A lightweight, security exosuit. Popular among private and corporate security." - name = "\improper Gygax" - icon_state = "gygax" - step_in = 3 - dir_in = 1 //Facing North. - max_integrity = 250 - deflect_chance = 5 - force = 20 - armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - max_temperature = 25000 - infra_luminosity = 6 - wreckage = /obj/structure/mecha_wreckage/gygax - internal_damage_threshold = 35 - max_equip = 3 - step_energy_drain = 3 - leg_overload_coeff = 300 - -/obj/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" - max_integrity = 300 - deflect_chance = 15 - force = 25 - armor = list("melee" = 40, "bullet" = 40, "laser" = 50, "energy" = 35, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - max_temperature = 35000 - leg_overload_coeff = 100 - operation_req_access = list(ACCESS_SYNDICATE) - internals_req_access = list(ACCESS_SYNDICATE) - wreckage = /obj/structure/mecha_wreckage/gygax/dark - max_equip = 4 - -/obj/mecha/combat/gygax/dark/loaded/Initialize() - . = ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/teleporter - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay - ME.attach(src) - max_ammo() - -/obj/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) - -/obj/mecha/combat/gygax/GrantActions(mob/living/user, human_occupant = 0) - ..() - overload_action.Grant(user, src) - -/obj/mecha/combat/gygax/dark/GrantActions(mob/living/user, human_occupant = 0) - ..() - thrusters_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) - ..() - thrusters_action.Remove(user) diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm deleted file mode 100644 index 11a1bc1e84..0000000000 --- a/code/game/mecha/combat/phazon.dm +++ /dev/null @@ -1,29 +0,0 @@ -/obj/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" - step_in = 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" = 0, "fire" = 100, "acid" = 100) - 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) diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm deleted file mode 100644 index ef1565502e..0000000000 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ /dev/null @@ -1,171 +0,0 @@ -//DO NOT ADD MECHA PARTS TO THE GAME WITH THE DEFAULT "SPRITE ME" SPRITE! -//I'm annoyed I even have to tell you this! SPRITE FIRST, then commit. - -/obj/item/mecha_parts/mecha_equipment - name = "mecha equipment" - icon = 'icons/mecha/mecha_equipment.dmi' - icon_state = "mecha_equip" - force = 5 - max_integrity = 300 - 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/energy_drain = 0 - var/obj/mecha/chassis = null - /// Bitflag. Determines the range of the equipment. - var/range = MELEE - /// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this. - var/mech_flags = NONE - var/salvageable = 1 - //var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed - var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates - var/harmful = FALSE //Controls if equipment can be used to attack by a pacifist. - //var/destroy_sound = 'sound/mecha/critdestr.ogg' - -/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 - 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 - return - -/obj/item/mecha_parts/mecha_equipment/Destroy() - if(chassis) - chassis.equipment -= src - if(chassis.selected == src) - chassis.selected = null - src.update_chassis_page() - //log_message("[src] is destroyed.", LOG_MECHA) - chassis.log_append_to_last("[src] is destroyed.",1) - if(chassis.occupant) - chassis.occupant_message("[src] is destroyed!") - SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50)) - //chassis.occupant.playsound_local(chassis, destroy_sound, 50) - //if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in. - // chassis.max_equip-- - chassis = null - return ..() - -/obj/item/mecha_parts/mecha_equipment/proc/critfail() - if(chassis) - mecha_log_message("Critical failure", color="red") - -/obj/item/mecha_parts/mecha_equipment/proc/get_equip_info() - if(!chassis) - return - var/txt = "* " - if(chassis.selected == src) - txt += "[src.name]" - else if(selectable) - txt += "[src.name]" - else - txt += "[src.name]" - - return txt - -/obj/item/mecha_parts/mecha_equipment/proc/is_ranged()//add a distance restricted equipment. Why not? - return range&RANGED //rename to MECHA_RANGE and MECHA_MELEE - -/obj/item/mecha_parts/mecha_equipment/proc/is_melee() - return range&MELEE - - -/obj/item/mecha_parts/mecha_equipment/proc/action_checks(atom/target) - if(!target) - return 0 - if(!chassis) - return 0 - if(!equip_ready) - return 0 - if(energy_drain && !chassis.has_charge(energy_drain)) - return 0 - if(crit_fail) - return 0 - 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 - -/obj/item/mecha_parts/mecha_equipment/proc/start_cooldown() - set_ready_state(0) - chassis.use_power(energy_drain) - addtimer(CALLBACK(src, .proc/set_ready_state, 1), equip_cooldown) - -/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target) - 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) - if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) - return 0 - -/obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, delay) - if(!chassis) - return - var/C = chassis.loc - . = do_after(chassis.occupant, delay, target=target) - if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) - return 0 - -/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M) - if(M.equipment.len[target] successfully loaded.") - mecha_log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") - else - O.anchored = initial(O.anchored) - else - occupant_message("Not enough room in cargo compartment!") - else - occupant_message("[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) - M.take_overall_damage(dam_force) - if(!M) - return - M.adjustOxyLoss(round(dam_force/2)) - M.updatehealth() - target.visible_message("[chassis] squeezes [target].", \ - "[chassis] squeezes [target].",\ - "You hear something crack.") - log_combat(chassis.occupant, M, "attacked", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [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 - - - -//This is pretty much just for the death-ripley -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill - name = "\improper KILL CLAMP" - desc = "They won't know what clamped them!" - energy_drain = 0 - dam_force = 0 - var/real_clamp = FALSE - -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/real - desc = "They won't know what clamped them! This time for real!" - energy_drain = 10 - dam_force = 20 - real_clamp = TRUE - -/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/action(atom/target) - if(!action_checks(target)) - return - if(!cargo_holder) - return - if(isobj(target)) - var/obj/O = target - if(!O.anchored) - if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) - chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") - O.anchored = TRUE - if(do_after_cooldown(target)) - cargo_holder.cargo += O - O.forceMove(chassis) - O.anchored = FALSE - occupant_message("[target] successfully loaded.") - mecha_log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") - else - O.anchored = initial(O.anchored) - else - occupant_message("Not enough room in cargo compartment!") - else - occupant_message("[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(real_clamp) - M.take_overall_damage(dam_force) - if(!M) - return - M.adjustOxyLoss(round(dam_force/2)) - M.updatehealth() - target.visible_message("[chassis] destroys [target] in an unholy fury.", \ - "[chassis] destroys [target] in an unholy fury.") - log_combat(chassis.occupant, M, "attacked", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])") - else - target.visible_message("[chassis] destroys [target] in an unholy fury.", \ - "[chassis] destroys [target] in an unholy fury.") - else if(chassis.occupant.a_intent == INTENT_DISARM) - if(real_clamp) - var/mob/living/carbon/C = target - var/play_sound = FALSE - var/limbs_gone = "" - var/obj/item/bodypart/affected = C.get_bodypart(BODY_ZONE_L_ARM) - if(affected != null) - affected.dismember(damtype) - play_sound = TRUE - limbs_gone = ", [affected]" - affected = C.get_bodypart(BODY_ZONE_R_ARM) - if(affected != null) - affected.dismember(damtype) - play_sound = TRUE - limbs_gone = "[limbs_gone], [affected]" - if(play_sound) - playsound(src, get_dismember_sound(), 80, TRUE) - target.visible_message("[chassis] rips [target]'s arms off.", \ - "[chassis] rips [target]'s arms off.") - log_combat(chassis.occupant, M, "dismembered of[limbs_gone],", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])") - else - target.visible_message("[chassis] rips [target]'s arms off.", \ - "[chassis] rips [target]'s arms off.") - else - step_away(M,chassis) - target.visible_message("[chassis] tosses [target] like a piece of paper.") - return 1 - - - -/obj/item/mecha_parts/mecha_equipment/extinguisher - name = "exosuit extinguisher" - desc = "Equipment for engineering exosuits. A rapid-firing high capacity fire extinguisher." - icon_state = "mecha_exting" - equip_cooldown = 5 - energy_drain = 0 - range = MELEE|RANGED - mech_flags = EXOSUIT_MODULE_WORKING - -/obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize() - . = ..() - 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. - 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.") - playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) - else - if(reagents.total_volume > 0) - playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) - var/direction = get_dir(chassis,target) - var/turf/T = get_turf(target) - var/turf/T1 = get_step(T,turn(direction, 90)) - var/turf/T2 = get_step(T,turn(direction, -90)) - - var/list/the_targets = list(T,T1,T2) - spawn(0) - for(var/a=0, a<5, a++) - var/obj/effect/particle_effect/water/W = new /obj/effect/particle_effect/water(get_turf(chassis)) - if(!W) - return - var/turf/my_target = pick(the_targets) - var/datum/reagents/R = new/datum/reagents(5) - W.reagents = R - R.my_atom = W - reagents.trans_to(W,1) - for(var/b=0, b<4, b++) - if(!W) - return - step_towards(W,my_target) - if(!W) - return - var/turf/W_turf = get_turf(W) - W.reagents.reaction(W_turf) - for(var/atom/atm in W_turf) - W.reagents.reaction(atm) - if(W.loc == my_target) - break - sleep(2) - return 1 - -/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) - if(..()) - if(istype(M)) - return 1 - return 0 - - - -/obj/item/mecha_parts/mecha_equipment/rcd - name = "mounted RCD" - desc = "An exosuit-mounted Rapid Construction Device." - icon_state = "mecha_rcd" - equip_cooldown = 10 - energy_drain = 250 - range = MELEE|RANGED - item_flags = NO_MAT_REDEMPTION - var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. - -/obj/item/mecha_parts/mecha_equipment/rcd/Initialize() - . = ..() - GLOB.rcd_list += src - -/obj/item/mecha_parts/mecha_equipment/rcd/Destroy() - GLOB.rcd_list -= src - return ..() - -/obj/item/mecha_parts/mecha_equipment/rcd/action(atom/target) - if(istype(target, /turf/open/space/transit))//>implying these are ever made -Sieve - return - - if(!isturf(target) && !istype(target, /obj/machinery/door/airlock)) - target = get_turf(target) - if(!action_checks(target) || get_dist(chassis, target)>3) - return - playsound(chassis, 'sound/machines/click.ogg', 50, 1) - - switch(mode) - if(0) - if(iswallturf(target)) - var/turf/closed/wall/W = target - occupant_message("Deconstructing [W]...") - if(do_after_cooldown(W)) - 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)) - 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)) - 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)) - 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)) - 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)) - 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) - . = ..() - -/obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list) - ..() - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - switch(mode) - if(0) - occupant_message("Switched RCD to Deconstruct.") - energy_drain = initial(energy_drain) - if(1) - occupant_message("Switched RCD to Construct.") - energy_drain = 2*initial(energy_drain) - if(2) - occupant_message("Switched RCD to Construct Airlock.") - energy_drain = 2*initial(energy_drain) - return - -/obj/item/mecha_parts/mecha_equipment/rcd/get_equip_info() - return "[..()] \[D|C|A\]" - - - - -/obj/item/mecha_parts/mecha_equipment/cable_layer - name = "cable layer" - desc = "Equipment for engineering exosuits. Lays cable along the exosuit's path." - icon_state = "mecha_wire" - var/datum/callback/event - var/turf/old_turf - var/obj/structure/cable/last_piece - var/obj/item/stack/cable_coil/cable - var/max_cable = 1000 - -/obj/item/mecha_parts/mecha_equipment/cable_layer/Initialize() - . = ..() - cable = new(src, 0) - -/obj/item/mecha_parts/mecha_equipment/cable_layer/can_attach(obj/mecha/working/M) - if(..()) - if(istype(M)) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/cable_layer/attach() - ..() - event = chassis.events.addEvent("onMove", CALLBACK(src, .proc/layCable)) - return - -/obj/item/mecha_parts/mecha_equipment/cable_layer/detach() - chassis.events.clearEvent("onMove",event) - return ..() - -/obj/item/mecha_parts/mecha_equipment/cable_layer/Destroy() - if(chassis) - chassis.events.clearEvent("onMove",event) - return ..() - -/obj/item/mecha_parts/mecha_equipment/cable_layer/action(var/obj/item/stack/cable_coil/target) - if(!action_checks(target)) - return - if(istype(target) && target.amount) - var/cur_amount = cable? cable.amount : 0 - var/to_load = max(max_cable - cur_amount,0) - if(to_load) - to_load = min(target.amount, to_load) - if(!cable) - cable = new(src, 0) - cable.amount += to_load - target.use(to_load) - occupant_message("[to_load] meters of cable successfully loaded.") - send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info()) - else - occupant_message("Reel is full.") - else - occupant_message("Unable to load [target] - no cable found.") - - -/obj/item/mecha_parts/mecha_equipment/cable_layer/Topic(href,href_list) - ..() - if(href_list["toggle"]) - set_ready_state(!equip_ready) - occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") - mecha_log_message("[equip_ready?"Dea":"A"]ctivated.") - return - if(href_list["cut"]) - if(cable && cable.amount) - var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) - m = min(m, cable.amount) - if(m) - use_cable(m) - new /obj/item/stack/cable_coil(get_turf(chassis), m) - else - occupant_message("There's no more cable on the reel.") - return - -/obj/item/mecha_parts/mecha_equipment/cable_layer/get_equip_info() - var/output = ..() - if(output) - return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]" - return - -/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/use_cable(amount) - if(!cable || cable.amount<1) - set_ready_state(1) - occupant_message("Cable depleted, [src] deactivated.") - mecha_log_message("Cable depleted, [src] deactivated.") - return - if(cable.amount < amount) - occupant_message("No enough cable to finish the task.") - return - cable.use(amount) - update_equip_info() - return 1 - -/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/reset() - last_piece = null - -/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/dismantleFloor(var/turf/new_turf) - if(isfloorturf(new_turf)) - var/turf/open/floor/T = new_turf - if(!isplatingturf(T)) - if(!T.broken && !T.burnt) - new T.floor_tile(T) - T.make_plating() - return !new_turf.intact - -/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/layCable(var/turf/new_turf) - if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) - return reset() - var/fdirn = turn(chassis.dir,180) - for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already - if(LC.d1 == fdirn || LC.d2 == fdirn) - return reset() - if(!use_cable(1)) - return reset() - var/obj/structure/cable/NC = new(new_turf, "red") - NC.d1 = 0 - NC.d2 = fdirn - NC.update_icon() - - var/datum/powernet/PN - if(last_piece && last_piece.d2 != chassis.dir) - last_piece.d1 = min(last_piece.d2, chassis.dir) - last_piece.d2 = max(last_piece.d2, chassis.dir) - last_piece.update_icon() - PN = last_piece.powernet - - if(!PN) - PN = new() - GLOB.powernets += PN - NC.powernet = PN - PN.cables += NC - NC.mergeConnectedNetworks(NC.d2) - - //NC.mergeConnectedNetworksOnTurf() - last_piece = NC - return 1 diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm deleted file mode 100644 index 86bbf81dd2..0000000000 --- a/code/game/mecha/mecha.dm +++ /dev/null @@ -1,1124 +0,0 @@ -#define MECHA_INT_FIRE (1<<0) -#define MECHA_INT_TEMP_CONTROL (1<<1) -#define MECHA_INT_SHORT_CIRCUIT (1<<2) -#define MECHA_INT_TANK_BREACH (1<<3) -#define MECHA_INT_CONTROL_LOST (1<<4) - -#define MELEE 1 -#define RANGED 2 - -#define FRONT_ARMOUR 1 -#define SIDE_ARMOUR 2 -#define BACK_ARMOUR 3 - - -/obj/mecha - name = "mecha" - desc = "Exosuit" - icon = 'icons/mecha/mecha.dmi' - density = TRUE //Dense. To raise the heat. - opacity = 1 ///opaque. Menacing. - anchored = TRUE //no pulling around. - resistance_flags = FIRE_PROOF | ACID_PROOF - layer = BELOW_MOB_LAYER//icon draw layer - infra_luminosity = 15 //byond implementation is bugged. - force = 5 - flags_1 = HEAR_1|BLOCK_FACE_ATOM_1 - attack_hand_speed = CLICK_CD_MELEE - attack_hand_is_action = TRUE - var/can_move = 0 //time of next allowed movement - var/mob/living/occupant = null - var/step_in = 10 //make a step in step_in/10 sec. - var/dir_in = SOUTH //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. - var/step_energy_drain = 10 - var/melee_energy_drain = 15 - 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) - var/list/facing_modifiers = list(FRONT_ARMOUR = 1.5, SIDE_ARMOUR = 1, BACK_ARMOUR = 0.5) - var/obj/item/stock_parts/cell/cell - var/state = 0 - var/list/log = new - var/last_message = 0 - var/add_req_access = 1 - var/maint_access = 0 - var/equipment_disabled = 0 //disabled due to EMP - var/dna_lock //dna-locking the mech - var/list/proc_res = list() //stores proc owners, like proc_res["functionname"] = owner reference - var/datum/effect_system/spark_spread/spark_system = new - var/lights = FALSE - 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/breach_time = 0 - var/recharge_rate = 0 - - var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it. - //inner atmos - var/use_internal_tank = 0 - var/internal_tank_valve = ONE_ATMOSPHERE - var/obj/machinery/portable_atmospherics/canister/internal_tank - var/datum/gas_mixture/cabin_air - var/obj/machinery/atmospherics/components/unary/portables_connector/connected_port = null - - 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 - - var/list/operation_req_access = list()//required access level for mecha operation - var/list/internals_req_access = list(ACCESS_ROBOTICS)//REQUIRED ACCESS LEVEL TO OPEN CELL COMPARTMENT - - var/wreckage - - var/list/equipment = new - var/obj/item/mecha_parts/mecha_equipment/selected - var/max_equip = 3 - var/datum/events/events - - var/stepsound = 'sound/mecha/mechstep.ogg' - var/turnsound = 'sound/mecha/mechturn.ogg' - - var/melee_cooldown = 10 - var/melee_can_hit = 1 - - //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_toggle_thrusters/thrusters_action = new - var/datum/action/innate/mecha/mech_defence_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 - var/thrusters_active = FALSE - var/defence_mode = FALSE - var/defence_mode_deflect_chance = 35 - var/leg_overload_mode = FALSE - var/leg_overload_coeff = 100 - var/zoom_mode = FALSE - var/smoke = 5 - var/smoke_ready = 1 - var/smoke_cooldown = 100 - var/phasing = FALSE - var/phasing_energy_drain = 200 - var/phase_state = "" //icon_state when phasing - var/strafe = FALSE //If we are strafing - - var/nextsmash = 0 - var/smashcooldown = 3 //deciseconds - - var/occupant_sight_flags = 0 //sight flags to give to the occupant (e.g. mech mining scanner gives meson-like vision) - var/mouse_pointer - - hud_possible = list (DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD) - -/obj/item/radio/mech //this has to go somewhere - -/obj/mecha/Initialize() - . = ..() - events = new - icon_state += "-open" - add_radio() - spark_system.set_up(2, 0, src) - spark_system.attach(src) - smoke_system.set_up(3, src) - smoke_system.attach(src) - add_cell() - START_PROCESSING(SSobj, src) - GLOB.poi_list |= src - mecha_log_message("[src.name] created.") - GLOB.mechas_list += src //global mech list - prepare_huds() - for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) - diag_hud.add_to_hud(src) - diag_hud_set_mechhealth() - diag_hud_set_mechcell() - diag_hud_set_mechstat() - return INITIALIZE_HINT_LATELOAD - -/obj/mecha/LateInitialize() - . = ..() - add_airtank() - add_cabin() - -/obj/mecha/get_cell() - return cell - -/obj/mecha/rust_heretic_act() - take_damage(500, BRUTE) - -/obj/mecha/Destroy() - 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. - else - M.forceMove(loc) - if(wreckage) - if(prob(30)) - explosion(get_turf(src), 0, 0, 1, 3) - 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)) - WR.crowbar_salvage += E - E.detach(WR) //detaches from src into WR - E.equip_ready = 1 - else - E.detach(loc) - qdel(E) - if(cell) - WR.crowbar_salvage += cell - cell.forceMove(WR) - cell.charge = rand(0, cell.charge) - if(internal_tank) - WR.crowbar_salvage += internal_tank - internal_tank.forceMove(WR) - else - for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) - E.detach(loc) - qdel(E) - if(cell) - qdel(cell) - if(internal_tank) - qdel(internal_tank) - if(AI) - AI.gib() //No wreck, no AI to recover - STOP_PROCESSING(SSobj, src) - GLOB.poi_list.Remove(src) - equipment.Cut() - cell = null - internal_tank = null - assume_air(cabin_air) - cabin_air = null - qdel(spark_system) - spark_system = null - qdel(smoke_system) - smoke_system = null - - GLOB.mechas_list -= src //global mech list - return ..() - -/obj/mecha/proc/restore_equipment() - equipment_disabled = 0 - if(istype(src, /obj/mecha/combat)) - mouse_pointer = 'icons/mecha/mecha_mouse.dmi' - 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/mecha/CheckParts(list/parts_list) - ..() - cell = locate(/obj/item/stock_parts/cell) in contents - var/obj/item/stock_parts/scanning_module/SM = locate() in contents - var/obj/item/stock_parts/capacitor/CP = locate() in contents - if(SM) - normal_step_energy_drain = 20 - (5 * SM.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 - qdel(SM) - if(CP) - armor = armor.modifyRating(energy = (CP.rating * 10)) //Each level of capacitor protects the mech against emp by 10% - qdel(CP) - -//////////////////////// -////// Helpers ///////// -//////////////////////// - -/obj/mecha/proc/add_airtank() - internal_tank = new /obj/machinery/portable_atmospherics/canister/air(src) - return internal_tank - -/obj/mecha/proc/add_cell(var/obj/item/stock_parts/cell/C=null) - if(C) - C.forceMove(src) - cell = C - return - cell = new /obj/item/stock_parts/cell/high/plus(src) - -/obj/mecha/proc/add_cabin() - cabin_air = new(200) - cabin_air.set_temperature(T20C) - cabin_air.set_moles(GAS_O2,O2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature())) - 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() - 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)) - if(!user.incapacitated()) - return 1 - return 0 - -//////////////////////////////////////////////////////////////////////////////// - -/obj/mecha/examine(mob/user) - . = ..() - var/integrity = obj_integrity*100/max_integrity - switch(integrity) - if(85 to 100) - . += "It's fully intact." - if(65 to 85) - . += "It's slightly damaged." - if(45 to 65) - . += "It's badly damaged." - if(25 to 45) - . += "It's heavily damaged." - else - . += "It's falling apart." - if(equipment && equipment.len) - . += "It's equipped with:" - for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) - . += "[icon2html(ME, user)] \A [ME]." - -//processing internal damage, temperature, air regulation, alert updates, lights power use. -/obj/mecha/process() - var/internal_temp_regulation = 1 - - if(internal_damage) - if(internal_damage & MECHA_INT_FIRE) - if(!(internal_damage & MECHA_INT_TEMP_CONTROL) && prob(5)) - clearInternalDamage(MECHA_INT_FIRE) - if(internal_tank) - var/datum/gas_mixture/int_tank_air = internal_tank.return_air() - if(int_tank_air.return_pressure() > internal_tank.maximum_pressure && !(internal_damage & MECHA_INT_TANK_BREACH)) - setInternalDamage(MECHA_INT_TANK_BREACH) - if(int_tank_air && int_tank_air.return_volume() > 0) //heat the air_contents - int_tank_air.set_temperature(min(6000+T0C, int_tank_air.return_temperature()+rand(10,15))) - if(cabin_air && cabin_air.return_volume()>0) - cabin_air.set_temperature(min(6000+T0C, cabin_air.return_temperature()+rand(10,15))) - if(cabin_air.return_temperature() > max_temperature/2) - take_damage(4/round(max_temperature/cabin_air.return_temperature(),0.1), BURN, 0, 0) - - if(internal_damage & MECHA_INT_TEMP_CONTROL) - internal_temp_regulation = 0 - - if(internal_damage & MECHA_INT_TANK_BREACH) //remove some air from internal tank - if(internal_tank) - assume_air_ratio(internal_tank.return_air(), 0.1) - - if(internal_damage & MECHA_INT_SHORT_CIRCUIT) - if(get_charge()) - spark_system.start() - cell.charge -= min(20,cell.charge) - cell.maxcharge -= min(20,cell.maxcharge) - - if(internal_temp_regulation) - if(cabin_air && cabin_air.return_volume() > 0) - var/delta = cabin_air.return_temperature() - T20C - cabin_air.set_temperature(cabin_air.return_temperature() - max(-10, min(10, round(delta/4,0.1)))) - - if(internal_tank) - var/datum/gas_mixture/tank_air = internal_tank.return_air() - - var/release_pressure = internal_tank_valve - var/cabin_pressure = cabin_air.return_pressure() - var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) - var/transfer_moles = 0 - if(pressure_delta > 0) //cabin pressure lower than release pressure - if(tank_air.return_temperature() > 0) - transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) - tank_air.transfer_to(cabin_air,transfer_moles) - else if(pressure_delta < 0) //cabin pressure higher than release pressure - var/datum/gas_mixture/t_air = return_air() - pressure_delta = cabin_pressure - release_pressure - if(t_air) - pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) - if(pressure_delta > 0) //if location pressure is lower than cabin pressure - 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.charge/cell.maxcharge - 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.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) - var/lights_energy_drain = 2 - use_power(lights_energy_drain) - -//Diagnostic HUD updates - diag_hud_set_mechhealth() - diag_hud_set_mechcell() - diag_hud_set_mechstat() - -/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. - return - -/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source) - . = ..() - if(speaker == occupant) - if(radio.broadcasting) - radio.talk_into(speaker, text, , spans, message_language) - //flick speech bubble - var/list/speech_bubble_recipients = list() - for(var/mob/M in get_hearers_in_view(7,src)) - if(M.client) - speech_bubble_recipients.Add(M.client) - INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, image('icons/mob/talk.dmi', src, "machine[say_test(raw_message)]",MOB_LAYER+1), speech_bubble_recipients, 30) - -//////////////////////////// -///// Action processing //// -//////////////////////////// - - -/obj/mecha/proc/click_action(atom/target,mob/user,params) - if(!occupant || occupant != user ) - return - if(!locate(/turf) in list(target,target.loc)) // Prevents inventory from being drilled - return - if(completely_disabled) - return - if(phasing) - occupant_message("Unable to interact with objects while phasing") - return - if(user.incapacitated()) - return - if(state) - occupant_message("Maintenance protocols in effect.") - return - if(!get_charge()) - return - if(src == target) - return - var/dir_to_target = get_dir(src,target) - if(dir_to_target && !(dir_to_target & dir))//wrong direction - return - if(internal_damage & MECHA_INT_CONTROL_LOST) - target = safepick(view(3,target)) - if(!target) - return - - var/mob/living/L = user - if(!Adjacent(target)) - if(selected && selected.is_ranged()) - if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful) - to_chat(user, "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!") - 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)) - return - target.mech_melee_attack(src) - melee_can_hit = 0 - spawn(melee_cooldown) - melee_can_hit = 1 - - -/obj/mecha/proc/range_action(atom/target) - return - - -////////////////////////////////// -//////// Movement procs //////// -////////////////////////////////// - -/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!") - mecha_log_message("Lost connection to gas port.") - -/obj/mecha/setDir(newdir) - . = ..() - occupant?.setDir(newdir) - -/obj/mecha/Process_Spacemove(var/movement_dir = 0) - . = ..() - if(.) - return 1 - if(thrusters_active && movement_dir && use_power(step_energy_drain)) - return 1 - - var/atom/movable/backup = get_spacemove_backup() - if(backup) - if(istype(backup) && movement_dir && !backup.anchored) - if(backup.newtonian_move(turn(movement_dir, 180))) - if(occupant) - to_chat(occupant, "You push off of [backup] to propel yourself.") - return 1 - -/obj/mecha/relaymove(mob/user,direction) - if(completely_disabled) - return - 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 - 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(state) - occupant_message("Maintenance protocols in effect.") - return - return domove(direction) - -/obj/mecha/proc/domove(direction) - if(can_move >= world.time) - return 0 - if(!Process_Spacemove(direction)) - return 0 - if(!has_charge(step_energy_drain)) - return 0 - if(defence_mode) - if(world.time - last_message > 20) - occupant_message("Unable to move while in defence mode") - last_message = world.time - return 0 - if(zoom_mode) - if(world.time - last_message > 20) - occupant_message("Unable to move while in zoom mode.") - last_message = world.time - return 0 - - 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 - return 1 - return 0 - -/obj/mecha/proc/mechturn(direction) - setDir(direction) - if(turnsound) - playsound(src,turnsound,40,1) - return 1 - -/obj/mecha/proc/mechstep(direction) - var/current_dir = dir - set_glide_size(DELAY_TO_GLIDE_SIZE(step_in)) - var/result = step(src,direction) - if(strafe) - setDir(current_dir) - if(result && stepsound) - playsound(src,stepsound,40,1) - return result - -/obj/mecha/proc/mechsteprand() - var/result = step_rand(src) - if(result && stepsound) - playsound(src,stepsound,40,1) - return result - -/obj/mecha/Bump(var/atom/obstacle) - if(phasing && get_charge() >= phasing_energy_drain && !throwing) - spawn() - if(can_move) - can_move = 0 - if(phase_state) - flick(phase_state, src) - forceMove(get_step(src,dir)) - use_power(phasing_energy_drain) - sleep(step_in*3) - can_move = 1 - else - if(..()) //mech was thrown - 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_step(src,dir))) - step(src,dir) - if(isobj(obstacle)) - var/obj/O = obstacle - if(!O.anchored) - step(obstacle, dir) - else if(ismob(obstacle)) - var/mob/M = obstacle - if(!M.anchored) - step(obstacle, dir) - - - - - -/////////////////////////////////// -//////// Internal damage //////// -/////////////////////////////////// - -/obj/mecha/proc/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null) - if(!islist(possible_int_damage) || isemptylist(possible_int_damage)) - return - if(prob(20)) - if(ignore_threshold || obj_integrity*100/max_integrity < internal_damage_threshold) - for(var/T in possible_int_damage) - if(internal_damage & T) - possible_int_damage -= T - var/int_dam_flag = safepick(possible_int_damage) - if(int_dam_flag) - 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) - qdel(ME) - return - -/obj/mecha/proc/setInternalDamage(int_dam_flag) - internal_damage |= int_dam_flag - log_append_to_last("Internal damage of type [int_dam_flag].",1) - SEND_SOUND(occupant, sound('sound/machines/warning-buzzer.ogg',wait=0)) - diag_hud_set_mechstat() - return - -/obj/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.") - if(MECHA_INT_FIRE) - occupant_message("Internal fire extinquished.") - if(MECHA_INT_TANK_BREACH) - occupant_message("Damaged internal tank has been sealed.") - internal_damage &= ~int_dam_flag - diag_hud_set_mechstat() - -///////////////////////////////////// -//////////// AI piloting //////////// -///////////////////////////////////// - -/obj/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. - if(user.can_dominate_mechs) - examine(user) //Get diagnostic information! - for(var/obj/item/mecha_parts/mecha_tracking/B in trackers) - to_chat(user, "Warning: Tracking Beacon detected. Enter at your own risk. Beacon Data:") - to_chat(user, "[B.get_mecha_info()]") - break - //Nothing like a big, red link to make the player feel powerful! - to_chat(user, "ASSUME DIRECT CONTROL?
") - else - examine(user) - if(occupant) - to_chat(user, "This exosuit has a pilot and cannot be controlled.") - return - var/can_control_mech = 0 - for(var/obj/item/mecha_parts/mecha_tracking/ai_control/A in trackers) - can_control_mech = 1 - to_chat(user, "[icon2html(src, user)] Status of [name]:\n[A.get_mecha_info()]") - break - if(!can_control_mech) - to_chat(user, "You cannot control exosuits without AI control beacons installed.") - return - to_chat(user, "Take control of exosuit?
") - -/obj/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. - switch(interaction) - if(AI_TRANS_TO_CARD) //Upload AI from mech to AI card. - if(!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 - to_chat(user, "No AI detected in the [name] onboard computer.") - return - AI.ai_restore_power()//So the AI initially has power. - AI.control_disabled = 1 - AI.radio_enabled = 0 - AI.disconnect_shell() - RemoveActions(AI, TRUE) - occupant = null - AI.forceMove(card) - card.AI = AI - AI.controlled_mech = null - AI.remote_control = null - icon_state = initial(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! - ai_enter_mech(AI, interaction) - - if(AI_TRANS_FROM_CARD) //Using an AI card to upload to a mech. - AI = card.AI - if(!AI) - to_chat(user, "There is no AI currently installed on this device.") - return - if(AI.deployed_shell) //Recall AI if shelled so it can be checked for a client - AI.disconnect_shell() - if(AI.stat || !AI.client) - to_chat(user, "[AI.name] is currently unresponsive, and cannot be uploaded.") - return - if(occupant || dna_lock) //Normal AIs cannot steal mechs! - to_chat(user, "Access denied. [name] is [occupant ? "currently occupied" : "secured with a DNA lock"].") - return - AI.control_disabled = 0 - AI.radio_enabled = 1 - 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) - -//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) - AI.ai_restore_power() - AI.forceMove(src) - occupant = AI - icon_state = initial(icon_state) - playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - if(!internal_damage) - SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) - AI.cancel_camera() - AI.controlled_mech = src - AI.remote_control = src - AI.mobility_flags = MOBILITY_FLAGS_DEFAULT //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. - 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) - if(pilot_mob && pilot_mob.Adjacent(src)) - if(occupant) - return - icon_state = initial(icon_state) - occupant = pilot_mob - pilot_mob.mecha = src - pilot_mob.forceMove(src) - GrantActions(pilot_mob)//needed for checks, and incase a badmin puts somebody in the mob - -/obj/mecha/proc/aimob_exit_mech(mob/living/simple_animal/hostile/syndicate/mecha_pilot/pilot_mob) - if(occupant == pilot_mob) - occupant = null - if(pilot_mob.mecha == src) - pilot_mob.mecha = null - icon_state = "[initial(icon_state)]-open" - pilot_mob.forceMove(get_turf(src)) - RemoveActions(pilot_mob) - - -///////////////////////////////////// -//////// Atmospheric stuff //////// -///////////////////////////////////// - -/obj/mecha/remove_air(amount) - if(use_internal_tank) - return cabin_air.remove(amount) - return ..() - -/obj/mecha/remove_air_ratio(ratio) - if(use_internal_tank) - return cabin_air.remove_ratio(ratio) - return ..() - -/obj/mecha/return_air() - if(use_internal_tank) - return cabin_air - return ..() - -/obj/mecha/proc/return_pressure() - var/datum/gas_mixture/t_air = return_air() - if(t_air) - . = t_air.return_pressure() - return - -/obj/mecha/return_temperature() - var/datum/gas_mixture/t_air = return_air() - if(t_air) - . = t_air.return_temperature() - return - -/obj/mecha/portableConnectorReturnAir() - return internal_tank.return_air() - - -/obj/mecha/MouseDrop_T(mob/M, mob/user) - if (!user.canUseTopic(src) || (user != M)) - return - if(!ishuman(user)) // no silicons or drones in mechas. - return - mecha_log_message("[user] tries to move in.") - if (occupant) - to_chat(usr, "The [name] is already occupied!") - log_append_to_last("Permission denied.") - return - if(dna_lock) - var/passed = FALSE - if(user.has_dna()) - var/mob/living/carbon/C = user - if(C.dna.unique_enzymes==dna_lock) - passed = TRUE - if (!passed) - to_chat(user, "Access denied. [name] is secured with a DNA lock.") - log_append_to_last("Permission denied.") - return - if(!operation_allowed(user)) - to_chat(user, "Access denied. Insufficient operation keycodes.") - log_append_to_last("Permission denied.") - return - if(user.buckled) - to_chat(user, "You are currently buckled and cannot move.") - log_append_to_last("Permission denied.") - 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!") - return - - visible_message("[user] starts to climb into [name].") - - if(do_after(user, 40, 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!") - else - moved_inside(user) - else - to_chat(user, "You stop entering the exosuit!") - return - -/obj/mecha/proc/moved_inside(mob/living/carbon/human/H) - if(H?.client && (H in range(1))) - occupant = H - H.forceMove(src) - H.update_mouse_pointer() - add_fingerprint(H) - GrantActions(H, human_occupant=1) - forceMove(loc) - log_append_to_last("[H] moved in as pilot.") - icon_state = initial(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 - -/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!") - 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!") - return FALSE - else if(dna_lock && (!mmi_as_oc.brainmob.stored_dna || (dna_lock != mmi_as_oc.brainmob.stored_dna.unique_enzymes))) - to_chat(user, "Access denied. [name] is secured with a DNA lock.") - 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) - else - to_chat(user, "Occupant 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))) - 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!") - 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]!") - return FALSE - var/mob/living/brainmob = mmi_as_oc.brainmob - mmi_as_oc.mecha = src - occupant = brainmob - brainmob.forceMove(src) //should allow relaymove - brainmob.reset_perspective(src) - brainmob.remote_control = src - brainmob.update_mobility() - brainmob.update_mouse_pointer() - icon_state = initial(icon_state) - update_icon() - setDir(dir_in) - mecha_log_message("[mmi_as_oc] moved in as pilot.") - if(!internal_damage) - SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) - GrantActions(brainmob) - return TRUE - -/obj/mecha/container_resist(mob/living/user) - go_out() - -/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) - -/obj/mecha/proc/go_out(forced, atom/newloc = loc) - if(!occupant) - return - 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) - mob_container = brain.container - else if(isAI(occupant)) - var/mob/living/silicon/ai/AI = occupant - 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 - return - else - if(!AI.linked_core) - to_chat(AI, "Inactive core destroyed. Unable to return.") - AI.linked_core = null - return - 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(). - if(mob_container.forceMove(newloc))//ejecting mob container - mecha_log_message("[mob_container] moved out.") - L << browse(null, "window=exosuit") - - if(istype(mob_container, /obj/item/mmi)) - var/obj/item/mmi/mmi = mob_container - if(mmi.brainmob) - L.forceMove(mmi) - L.reset_perspective() - mmi.mecha = null - mmi.update_icon() - L.mobility_flags = NONE - icon_state = initial(icon_state)+"-open" - setDir(dir_in) - - if(L && L.client) - L.update_mouse_pointer() - L.client.view_size.resetToDefault() - zoom_mode = 0 - -///////////////////////// -////// Access stuff ///// -///////////////////////// - -/obj/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) - 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 - -/obj/mecha/proc/mecha_log_message(message, color) - log.len++ - log[log.len] = list("time"="[STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]","date","year"="[GLOB.year_integer]","message"="[color?"":null][message][color?"":null]") - log_message(message, LOG_GAME, color) //also do the normal admin logs I guess. - return log.len - -/obj/mecha/proc/log_append_to_last(message as text,red=null) - var/list/last_entry = log[log.len] - last_entry["message"] += "
[red?"":null][message][red?"":null]" - return - -/////////////////////// -///// Power stuff ///// -/////////////////////// - -/obj/mecha/proc/has_charge(amount) - return (get_charge()>=amount) - -/obj/mecha/proc/get_charge() - for(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/R in equipment) - var/relay_charge = R.get_charge() - if(relay_charge) - return relay_charge - if(cell) - return max(0, cell.charge) - -/obj/mecha/proc/use_power(amount) - if(get_charge()) - cell.use(amount) - return 1 - return 0 - -/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 - -/////////////////////// -////// Ammo stuff ///// -/////////////////////// - -/obj/mecha/proc/ammo_resupply(var/obj/item/mecha_ammo/A, mob/user,var/fail_chat_override = FALSE) - if(!A.rounds) - if(!fail_chat_override) - to_chat(user, "This box of ammo is empty!") - return FALSE - var/ammo_needed - var/found_gun - for(var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun in equipment) - ammo_needed = 0 - - if(istype(gun, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic) && gun.ammo_type == A.ammo_type) - found_gun = TRUE - if(A.direct_load) - ammo_needed = initial(gun.projectiles) - gun.projectiles - else - ammo_needed = gun.projectiles_cache_max - gun.projectiles_cache - - if(ammo_needed) - if(ammo_needed < A.rounds) - if(A.direct_load) - gun.projectiles = gun.projectiles + ammo_needed - else - gun.projectiles_cache = gun.projectiles_cache + ammo_needed - playsound(get_turf(user),A.load_audio,50,1) - to_chat(user, "You add [ammo_needed] [A.round_term][ammo_needed > 1?"s":""] to the [gun.name]") - A.rounds = A.rounds - ammo_needed - A.update_name() - return TRUE - - else - if(A.direct_load) - gun.projectiles = gun.projectiles + A.rounds - else - gun.projectiles_cache = gun.projectiles_cache + A.rounds - playsound(get_turf(user),A.load_audio,50,1) - to_chat(user, "You add [A.rounds] [A.round_term][A.rounds > 1?"s":""] to the [gun.name]") - A.rounds = 0 - A.update_name() - return TRUE - if(!fail_chat_override) - if(found_gun) - to_chat(user, "You can't fit any more ammo of this type!") - else - to_chat(user, "None of the equipment on this exosuit can use this ammo!") - return FALSE diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm deleted file mode 100644 index ee43e3f770..0000000000 --- a/code/game/mecha/mecha_actions.dm +++ /dev/null @@ -1,285 +0,0 @@ -//////////////////////////////////////// Action Buttons /////////////////////////////////////////////// - -/obj/mecha/proc/GrantActions(mob/living/user, human_occupant = 0) - if(human_occupant) - eject_action.Grant(user, src) - 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 - -/datum/action/innate/mecha/Grant(mob/living/L, obj/mecha/M) - if(M) - chassis = M - ..() - -/datum/action/innate/mecha/Destroy() - chassis = null - return ..() - -/datum/action/innate/mecha/mech_eject - name = "Eject From Mech" - button_icon_state = "mech_eject" - -/datum/action/innate/mecha/mech_eject/Activate() - if(!owner) - return - if(!chassis || chassis.occupant != owner) - return - chassis.go_out() - - -/datum/action/innate/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) - return - chassis.use_internal_tank = !chassis.use_internal_tank - button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]" - chassis.occupant_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].") - chassis.mecha_log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].") - UpdateButtonIcon() - -/datum/action/innate/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) - return - - var/list/available_equipment = list() - for(var/obj/item/mecha_parts/mecha_equipment/M in chassis.equipment) - if(M.selectable) - available_equipment += M - - if(available_equipment.len == 0) - chassis.occupant_message("No equipment available.") - return - if(!chassis.selected) - chassis.selected = available_equipment[1] - chassis.occupant_message("You select [chassis.selected]") - send_byjax(chassis.occupant,"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) - number++ - if(A == chassis.selected) - if(available_equipment.len == number) - chassis.selected = null - chassis.occupant_message("You switch to no equipment") - button_icon_state = "mech_cycle_equip_off" - else - chassis.selected = available_equipment[number+1] - chassis.occupant_message("You switch 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 - name = "Toggle Lights" - button_icon_state = "mech_lights_off" - -/datum/action/innate/mecha/mech_toggle_lights/Activate() - if(!owner || !chassis || chassis.occupant != owner) - return - chassis.lights = !chassis.lights - if(chassis.lights) - chassis.set_light(chassis.lights_power) - button_icon_state = "mech_lights_on" - else - chassis.set_light(-chassis.lights_power) - button_icon_state = "mech_lights_off" - chassis.occupant_message("Toggled lights [chassis.lights?"on":"off"].") - chassis.mecha_log_message("Toggled lights [chassis.lights?"on":"off"].") - UpdateButtonIcon() - -/datum/action/innate/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) - return - chassis.occupant << browse(chassis.get_stats_html(), "window=exosuit") - - -/datum/action/innate/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) - return - - chassis.toggle_strafe() - -/obj/mecha/AltClick(mob/living/user) - . = ..() - if((user == occupant) && user.canUseTopic(src)) - toggle_strafe() - return TRUE - -/obj/mecha/proc/toggle_strafe() - strafe = !strafe - - occupant_message("Toggled strafing mode [strafe?"on":"off"].") - mecha_log_message("Toggled strafing mode [strafe?"on":"off"].") - strafing_action.UpdateButtonIcon() - -//////////////////////////////////////// Specific Ability Actions /////////////////////////////////////////////// -//Need to be granted by the mech type, Not default abilities. - -/datum/action/innate/mecha/mech_toggle_thrusters - name = "Toggle Thrusters" - button_icon_state = "mech_thrusters_off" - -/datum/action/innate/mecha/mech_toggle_thrusters/Activate() - if(!owner || !chassis || chassis.occupant != owner) - return - if(chassis.get_charge() > 0) - chassis.thrusters_active = !chassis.thrusters_active - button_icon_state = "mech_thrusters_[chassis.thrusters_active ? "on" : "off"]" - chassis.mecha_log_message("Toggled thrusters.") - chassis.occupant_message("Thrusters [chassis.thrusters_active ?"en":"dis"]abled.") - - -/datum/action/innate/mecha/mech_defence_mode - name = "Toggle Defence Mode" - button_icon_state = "mech_defense_mode_off" - -/datum/action/innate/mecha/mech_defence_mode/Activate(forced_state = null) - if(!owner || !chassis || chassis.occupant != owner) - return - if(!isnull(forced_state)) - chassis.defence_mode = forced_state - else - chassis.defence_mode = !chassis.defence_mode - button_icon_state = "mech_defense_mode_[chassis.defence_mode ? "on" : "off"]" - if(chassis.defence_mode) - chassis.deflect_chance = chassis.defence_mode_deflect_chance - chassis.occupant_message("You enable [chassis] defence mode.") - else - chassis.deflect_chance = initial(chassis.deflect_chance) - chassis.occupant_message("You disable [chassis] defence mode.") - chassis.mecha_log_message("Toggled defence mode.") - UpdateButtonIcon() - -/datum/action/innate/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) - return - if(!isnull(forced_state)) - chassis.leg_overload_mode = forced_state - else - chassis.leg_overload_mode = !chassis.leg_overload_mode - button_icon_state = "mech_overload_[chassis.leg_overload_mode ? "on" : "off"]" - chassis.mecha_log_message("Toggled leg actuators overload.") - if(chassis.leg_overload_mode) - chassis.leg_overload_mode = 1 - chassis.bumpsmash = 1 - chassis.step_in = min(1, round(chassis.step_in/2)) - chassis.step_energy_drain = max(chassis.overload_step_energy_drain_min,chassis.step_energy_drain*chassis.leg_overload_coeff) - chassis.occupant_message("You enable leg actuators overload.") - else - chassis.leg_overload_mode = 0 - chassis.bumpsmash = 0 - chassis.step_in = initial(chassis.step_in) - chassis.step_energy_drain = chassis.normal_step_energy_drain - chassis.occupant_message("You disable leg actuators overload.") - UpdateButtonIcon() - -/datum/action/innate/mecha/mech_smoke - name = "Smoke" - button_icon_state = "mech_smoke" - -/datum/action/innate/mecha/mech_smoke/Activate() - if(!owner || !chassis || chassis.occupant != owner) - return - if(chassis.smoke_ready && chassis.smoke>0) - chassis.smoke_system.start() - chassis.smoke-- - chassis.smoke_ready = 0 - spawn(chassis.smoke_cooldown) - chassis.smoke_ready = 1 - - -/datum/action/innate/mecha/mech_zoom - name = "Zoom" - button_icon_state = "mech_zoom_off" - -/datum/action/innate/mecha/mech_zoom/Activate() - if(!owner || !chassis || chassis.occupant != owner) - return - if(owner.client) - chassis.zoom_mode = !chassis.zoom_mode - button_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]" - chassis.mecha_log_message("Toggled zoom mode.") - chassis.occupant_message("Zoom mode [chassis.zoom_mode?"en":"dis"]abled.") - if(chassis.zoom_mode) - owner.client.view_size.setTo(4.5) - SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50)) - else - owner.client.view_size.resetToDefault() - UpdateButtonIcon() - -/datum/action/innate/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) - return - var/new_damtype - switch(chassis.damtype) - if("tox") - new_damtype = "brute" - chassis.occupant_message("Your exosuit's hands form into fists.") - if("brute") - new_damtype = "fire" - chassis.occupant_message("A torch tip extends from your exosuit's hand, glowing red.") - if("fire") - new_damtype = "tox" - chassis.occupant_message("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, 1) - UpdateButtonIcon() - -/datum/action/innate/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) - return - chassis.phasing = !chassis.phasing - button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]" - chassis.occupant_message("En":"#f00\">Dis"]abled phasing.") - UpdateButtonIcon() diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm deleted file mode 100644 index 34cb57f661..0000000000 --- a/code/game/mecha/mecha_construction_paths.dm +++ /dev/null @@ -1,2292 +0,0 @@ -//////////////////////////////// -///// Construction datums ////// -//////////////////////////////// -/datum/component/construction/mecha - var/base_icon - var/looky_helpy = TRUE - -/datum/component/construction/mecha/examine(datum/source, mob/user, list/examine_list) - . = ..() - if(looky_helpy) - switch(steps[index]["key"]) - if(TOOL_WRENCH) - examine_list += "The mech could be wrenched into place." - if(TOOL_SCREWDRIVER) - examine_list += "The mech could be screwed into place." - if(TOOL_WIRECUTTER) - examine_list += "The mech wires could be trimmed into place." - if(/obj/item/stack/cable_coil) - examine_list += "The mech could use some wiring." - if(/obj/item/circuitboard) - examine_list += "The mech could use a type ofcircuitboard." - if(/obj/item/stock_parts/scanning_module) - examine_list += "The mech could use a scanning stock part." - if(/obj/item/stock_parts/capacitor) - examine_list += "The mech could use a power based stock part." - if(/obj/item/stock_parts/cell) - examine_list += "The mech could use a power source." - if(/obj/item/stack/sheet/metal) - examine_list += "The mech could use some sheets of metal." - if(/obj/item/stack/sheet/plasteel) - examine_list += "The mech could use some sheets of strong steel." - if(/obj/item/bikehorn) - examine_list += "HONK IT!." - if(/obj/item/clothing/mask/gas/clown_hat) - examine_list += "GIVE IT CLOWN MAKEUP HONK!." - if(/obj/item/clothing/shoes/clown_shoes) - examine_list += "GIVE IT GOOFY SHOES HONK HONK!." - if(/obj/item/mecha_parts/part) - examine_list += "The mech could use a mech part." - if(/obj/item/stack/ore/bluespace_crystal) - examine_list += "The mech could use a crystal of sorts." - if(/obj/item/assembly/signaler/anomaly) - examine_list += "The mech could use a anomaly of sorts." - -/datum/component/construction/mecha/spawn_result() - if(!result) - return - // Remove default mech power cell, as we replace it with a new one. - var/obj/mecha/M = new result(drop_location()) - QDEL_NULL(M.cell) - - var/obj/item/mecha_parts/chassis/parent_chassis = parent - M.CheckParts(parent_chassis.contents) - - SSblackbox.record_feedback("tally", "mechas_created", 1, M.name) - QDEL_NULL(parent) - -/datum/component/construction/mecha/update_parent(step_index) - ..() - // By default, each step in mech construction has a single icon_state: - // "[base_icon][index - 1]" - // For example, Ripley's step 1 icon_state is "ripley0". - var/atom/parent_atom = parent - if(!steps[index]["icon_state"] && base_icon) - parent_atom.icon_state = "[base_icon][index - 1]" - -/datum/component/construction/unordered/mecha_chassis/custom_action(obj/item/I, mob/living/user, typepath) - . = user.transferItemToLoc(I, parent) - if(.) - var/atom/parent_atom = parent - user.visible_message("[user] has connected [I] to [parent].", "You connect [I] to [parent].") - parent_atom.add_overlay(I.icon_state+"+o") - qdel(I) - -/datum/component/construction/unordered/mecha_chassis/spawn_result() - var/atom/parent_atom = parent - parent_atom.icon = 'icons/mecha/mech_construction.dmi' - parent_atom.density = TRUE - parent_atom.cut_overlays() - ..() - - -/datum/component/construction/unordered/mecha_chassis/ripley - result = /datum/component/construction/mecha/ripley - steps = list( - /obj/item/mecha_parts/part/ripley_torso, - /obj/item/mecha_parts/part/ripley_left_arm, - /obj/item/mecha_parts/part/ripley_right_arm, - /obj/item/mecha_parts/part/ripley_left_leg, - /obj/item/mecha_parts/part/ripley_right_leg - ) - -/datum/component/construction/mecha/ripley - result = /obj/mecha/working/ripley - base_icon = "ripley" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/ripley/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/ripley/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed." - ), - - //9 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The scanner module is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanner module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Capacitor is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured." - ), - - //14 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed." - ), - - //15 - list( - "key" = /obj/item/stack/sheet/metal, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured." - ), - - //16 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Internal armor is installed." - ), - - //17 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Internal armor is wrenched." - ), - - //18 - list( - "key" = /obj/item/stack/sheet/plasteel, - "amount" = 5, - "back_key" = TOOL_WELDER, - "desc" = "Internal armor is welded." - ), - - //19 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed." - ), - - //20 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched." - ), - ) - -/datum/component/construction/mecha/ripley/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(11) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(12) - if(diff==FORWARD) - user.visible_message("[user] secures [I].", "You secure [I].") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(13) - if(diff==FORWARD) - user.visible_message("[user] installs [I].", "You install [I].") - else - user.visible_message("[user] unsecures the capacitor from [parent].", "You unsecure the capacitor from [parent].") - if(14) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(15) - if(diff==FORWARD) - user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(16) - if(diff==FORWARD) - user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") - else - user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") - if(17) - if(diff==FORWARD) - user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") - if(18) - if(diff==FORWARD) - user.visible_message("[user] installs the external reinforced armor layer to [parent].", "You install the external reinforced armor layer to [parent].") - else - user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") - if(19) - if(diff==FORWARD) - user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.") - else - user.visible_message("[user] pries external armor layer from [parent].", "You pry external armor layer from [parent].") - if(20) - if(diff==FORWARD) - user.visible_message("[user] welds the external armor layer to [parent].", "You weld the external armor layer to [parent].") - else - user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") - return TRUE - -/datum/component/construction/unordered/mecha_chassis/gygax - result = /datum/component/construction/mecha/gygax - steps = list( - /obj/item/mecha_parts/part/gygax_torso, - /obj/item/mecha_parts/part/gygax_left_arm, - /obj/item/mecha_parts/part/gygax_right_arm, - /obj/item/mecha_parts/part/gygax_left_leg, - /obj/item/mecha_parts/part/gygax_right_leg, - /obj/item/mecha_parts/part/gygax_head - ) - -/datum/component/construction/mecha/gygax - result = /obj/mecha/combat/gygax - base_icon = "gygax" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/gygax/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/gygax/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed." - ), - - //9 - list( - "key" = /obj/item/circuitboard/mecha/gygax/targeting, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Weapon control module is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Weapon control module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Scanner module is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanner module is secured." - ), - - //14 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Capacitor is installed." - ), - - //15 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured." - ), - - //16 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed." - ), - - //17 - list( - "key" = /obj/item/stack/sheet/metal, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured." - ), - - //18 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Internal armor is installed." - ), - - //19 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Internal armor is wrenched." - ), - - //20 - list( - "key" = /obj/item/mecha_parts/part/gygax_armor, - "action" = ITEM_DELETE, - "back_key" = TOOL_WELDER, - "desc" = "Internal armor is welded." - ), - - //21 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed." - ), - - //22 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched." - ), - - ) - -/datum/component/construction/mecha/gygax/action(datum/source, atom/used_atom, mob/user) - return check_step(used_atom,user) - -/datum/component/construction/mecha/gygax/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") - else - user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") - if(11) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") - if(12) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(13) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(14) - if(diff==FORWARD) - user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(15) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") - if(16) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(17) - if(diff==FORWARD) - user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(18) - if(diff==FORWARD) - user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") - else - user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") - if(19) - if(diff==FORWARD) - user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") - if(20) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") - if(21) - if(diff==FORWARD) - user.visible_message("[user] secures Gygax Armor Plates.", "You secure Gygax Armor Plates.") - else - user.visible_message("[user] pries Gygax Armor Plates from [parent].", "You pry Gygax Armor Plates from [parent].") - if(22) - if(diff==FORWARD) - user.visible_message("[user] welds Gygax Armor Plates to [parent].", "You weld Gygax Armor Plates to [parent].") - else - user.visible_message("[user] unfastens Gygax Armor Plates.", "You unfasten Gygax Armor Plates.") - return TRUE - -//Begin Medigax -/datum/component/construction/unordered/mecha_chassis/medigax - result = /datum/component/construction/mecha/medigax - steps = list( - /obj/item/mecha_parts/part/medigax_torso, - /obj/item/mecha_parts/part/medigax_left_arm, - /obj/item/mecha_parts/part/medigax_right_arm, - /obj/item/mecha_parts/part/medigax_left_leg, - /obj/item/mecha_parts/part/medigax_right_leg, - /obj/item/mecha_parts/part/medigax_head - ) - -/datum/component/construction/mecha/medigax - result = /obj/mecha/medical/medigax - base_icon = "medigax" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/gygax/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/gygax/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed." - ), - - //9 - list( - "key" = /obj/item/circuitboard/mecha/gygax/targeting, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Weapon control module is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Weapon control module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Scanner module is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanner module is secured." - ), - - //14 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Capacitor is installed." - ), - - //15 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured." - ), - - //16 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed." - ), - - //17 - list( - "key" = /obj/item/stack/sheet/metal, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured." - ), - - //18 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Internal armor is installed." - ), - - //19 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Internal armor is wrenched." - ), - - //20 - list( - "key" = /obj/item/mecha_parts/part/medigax_armor, - "action" = ITEM_DELETE, - "back_key" = TOOL_WELDER, - "desc" = "Internal armor is welded." - ), - - //21 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed." - ), - - //22 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched." - ), - - ) - -/datum/component/construction/mecha/medigax/action(datum/source, atom/used_atom, mob/user) - return check_step(used_atom,user) - -/datum/component/construction/mecha/medigax/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") - else - user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") - if(11) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") - if(12) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(13) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(14) - if(diff==FORWARD) - user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(15) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") - if(16) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(17) - if(diff==FORWARD) - user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(18) - if(diff==FORWARD) - user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") - else - user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") - if(19) - if(diff==FORWARD) - user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") - if(20) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") - if(21) - if(diff==FORWARD) - user.visible_message("[user] secures Gygax Armor Plates.", "You secure Medical Gygax Armor Plates.") - else - user.visible_message("[user] pries Gygax Armor Plates from [parent].", "You pry Medical Gygax Armor Plates from [parent].") - if(22) - if(diff==FORWARD) - user.visible_message("[user] welds Gygax Armor Plates to [parent].", "You weld Medical Gygax Armor Plates to [parent].") - else - user.visible_message("[user] unfastens Gygax Armor Plates.", "You unfasten Medical Gygax Armor Plates.") - return TRUE -// End Medigax - -/datum/component/construction/unordered/mecha_chassis/firefighter - result = /datum/component/construction/mecha/firefighter - steps = list( - /obj/item/mecha_parts/part/ripley_torso, - /obj/item/mecha_parts/part/ripley_left_arm, - /obj/item/mecha_parts/part/ripley_right_arm, - /obj/item/mecha_parts/part/ripley_left_leg, - /obj/item/mecha_parts/part/ripley_right_leg, - /obj/item/clothing/suit/fire - ) - -/datum/component/construction/mecha/firefighter - result = /obj/mecha/working/ripley/firefighter - base_icon = "fireripley" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/ripley/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/ripley/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed." - ), - - //9 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The scanner module is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The scanner module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The capacitor is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The capacitor is secured." - ), - - //14 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed." - ), - - //15 - list( - "key" = /obj/item/stack/sheet/plasteel, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured." - ), - - //16 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Internal armor is installed." - ), - - //17 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Internal armor is wrenched." - ), - - //18 - list( - "key" = /obj/item/stack/sheet/plasteel, - "amount" = 5, - "back_key" = TOOL_WELDER, - "desc" = "Internal armor is welded." - ), - - //19 - list( - "key" = /obj/item/stack/sheet/plasteel, - "amount" = 5, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is being installed." - ), - - //20 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed." - ), - - //21 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched." - ), - ) - -/datum/component/construction/mecha/firefighter/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - //TODO: better messages. - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I]into [parent].", "You install [I]into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(12) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(13) - if(diff==FORWARD) - user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(14) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") - if(15) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(16) - if(diff==FORWARD) - user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(17) - if(diff==FORWARD) - user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") - else - user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") - if(18) - if(diff==FORWARD) - user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") - if(19) - if(diff==FORWARD) - user.visible_message("[user] starts to install the external armor layer to [parent].", "You install the external armor layer to [parent].") - else - user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") - if(20) - if(diff==FORWARD) - user.visible_message("[user] installs the external reinforced armor layer to [parent].", "You install the external reinforced armor layer to [parent].") - else - user.visible_message("[user] removes the external armor from [parent].", "You remove the external armor from [parent].") - if(21) - if(diff==FORWARD) - user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.") - else - user.visible_message("[user] pries external armor layer from [parent].", "You pry external armor layer from [parent].") - if(22) - if(diff==FORWARD) - user.visible_message("[user] welds the external armor layer to [parent].", "You weld the external armor layer to [parent].") - else - user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") - return TRUE - -/datum/component/construction/unordered/mecha_chassis/honker - result = /datum/component/construction/mecha/honker - steps = list( - /obj/item/mecha_parts/part/honker_torso, - /obj/item/mecha_parts/part/honker_left_arm, - /obj/item/mecha_parts/part/honker_right_arm, - /obj/item/mecha_parts/part/honker_left_leg, - /obj/item/mecha_parts/part/honker_right_leg, - /obj/item/mecha_parts/part/honker_head - ) - - -/datum/component/construction/mecha/honker - result = /obj/mecha/combat/honker - steps = list( - //1 - list( - "key" = /obj/item/bikehorn - ), - - //2 - list( - "key" = /obj/item/circuitboard/mecha/honker/main, - "action" = ITEM_DELETE - ), - - //3 - list( - "key" = /obj/item/bikehorn - ), - - //4 - list( - "key" = /obj/item/circuitboard/mecha/honker/peripherals, - "action" = ITEM_DELETE - ), - - //5 - list( - "key" = /obj/item/bikehorn - ), - - //6 - list( - "key" = /obj/item/circuitboard/mecha/honker/targeting, - "action" = ITEM_DELETE - ), - - //7 - list( - "key" = /obj/item/bikehorn - ), - - //6 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE - ), - - //8 - list( - "key" = /obj/item/bikehorn - ), - - //9 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE - ), - - //10 - list( - "key" = /obj/item/bikehorn - ), - - //11 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE - ), - - //12 - list( - "key" = /obj/item/bikehorn - ), - - //13 - list( - "key" = /obj/item/clothing/mask/gas/clown_hat, - "action" = ITEM_DELETE - ), - - //14 - list( - "key" = /obj/item/bikehorn - ), - - //15 - list( - "key" = /obj/item/clothing/shoes/clown_shoes, - "action" = ITEM_DELETE - ), - - //16 - list( - "key" = /obj/item/bikehorn - ), - ) - -// HONK doesn't have any construction step icons, so we just set an icon once. -/datum/component/construction/mecha/honker/update_parent(step_index) - if(step_index == 1) - var/atom/parent_atom = parent - parent_atom.icon = 'icons/mecha/mech_construct.dmi' - parent_atom.icon_state = "honker_chassis" - ..() -// HONK doesn't have any construction step icons, so we just set an icon once. -/datum/component/construction/mecha/honker/update_parent(step_index) - if(step_index == 1) - var/atom/parent_atom = parent - parent_atom.icon = 'icons/mecha/mech_construct.dmi' - parent_atom.icon_state = "honker_chassis" - ..() - -/datum/component/construction/mecha/honker/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - if(istype(I, /obj/item/bikehorn)) - playsound(parent, 'sound/items/bikehorn.ogg', 50, 1) - user.visible_message("HONK!") - - //TODO: better messages. - switch(index) - if(2) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - if(4) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - if(6) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - if(8) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - if(10) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - if(12) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - if(14) - user.visible_message("[user] puts [I] on [parent].", "You put [I] on [parent].") - if(16) - user.visible_message("[user] puts [I] on [parent].", "You put [I] on [parent].") - return TRUE - -/datum/component/construction/unordered/mecha_chassis/durand - result = /datum/component/construction/mecha/durand - steps = list( - /obj/item/mecha_parts/part/durand_torso, - /obj/item/mecha_parts/part/durand_left_arm, - /obj/item/mecha_parts/part/durand_right_arm, - /obj/item/mecha_parts/part/durand_left_leg, - /obj/item/mecha_parts/part/durand_right_leg, - /obj/item/mecha_parts/part/durand_head - ) - -/datum/component/construction/mecha/durand - result = /obj/mecha/combat/durand - base_icon = "durand" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/durand/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/durand/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed." - ), - - //9 - list( - "key" = /obj/item/circuitboard/mecha/durand/targeting, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Weapon control module is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Weapon control module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Scanner module is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanner module is secured." - ), - - //14 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Capacitor is installed." - ), - - //15 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured." - ), - - //16 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed." - ), - - //17 - list( - "key" = /obj/item/stack/sheet/metal, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured." - ), - - //18 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Internal armor is installed." - ), - - //19 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Internal armor is wrenched." - ), - - //20 - list( - "key" = /obj/item/mecha_parts/part/durand_armor, - "action" = ITEM_DELETE, - "back_key" = TOOL_WELDER, - "desc" = "Internal armor is welded." - ), - - //21 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed." - ), - - //22 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched." - ), - ) - - -/datum/component/construction/mecha/durand/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - //TODO: better messages. - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") - else - user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") - if(11) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") - if(12) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(13) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(14) - if(diff==FORWARD) - user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(15) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") - if(16) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(17) - if(diff==FORWARD) - user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(18) - if(diff==FORWARD) - user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") - else - user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") - if(19) - if(diff==FORWARD) - user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") - if(20) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") - if(21) - if(diff==FORWARD) - user.visible_message("[user] secures Durand Armor Plates.", "You secure Durand Armor Plates.") - else - user.visible_message("[user] pries Durand Armor Plates from [parent].", "You pry Durand Armor Plates from [parent].") - if(22) - if(diff==FORWARD) - user.visible_message("[user] welds Durand Armor Plates to [parent].", "You weld Durand Armor Plates to [parent].") - else - user.visible_message("[user] unfastens Durand Armor Plates.", "You unfasten Durand Armor Plates.") - return TRUE - -//PHAZON - -/datum/component/construction/unordered/mecha_chassis/phazon - result = /datum/component/construction/mecha/phazon - steps = list( - /obj/item/mecha_parts/part/phazon_torso, - /obj/item/mecha_parts/part/phazon_left_arm, - /obj/item/mecha_parts/part/phazon_right_arm, - /obj/item/mecha_parts/part/phazon_left_leg, - /obj/item/mecha_parts/part/phazon_right_leg, - /obj/item/mecha_parts/part/phazon_head - ) - -/datum/component/construction/mecha/phazon - result = /obj/mecha/combat/phazon - base_icon = "phazon" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/phazon/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/phazon/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed" - ), - - //9 - list( - "key" = /obj/item/circuitboard/mecha/phazon/targeting, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Weapon control is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Weapon control module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Scanner module is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanner module is secured." - ), - - //14 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Capacitor is installed." - ), - - //15 - list( - "key" = /obj/item/stack/ore/bluespace_crystal, - "amount" = 1, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured." - ), - - //16 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_CROWBAR, - "desc" = "The bluespace crystal is installed." - ), - - //17 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WIRECUTTER, - "desc" = "The bluespace crystal is connected." - ), - - //18 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The bluespace crystal is engaged." - ), - - //19 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed.", - "icon_state" = "phazon17" - // This is the point where a step icon is skipped, so "icon_state" had to be set manually starting from here. - ), - - //20 - list( - "key" = /obj/item/stack/sheet/plasteel, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured.", - "icon_state" = "phazon18" - ), - - //21 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Phase armor is installed.", - "icon_state" = "phazon19" - ), - - //22 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Phase armor is wrenched.", - "icon_state" = "phazon20" - ), - - //23 - list( - "key" = /obj/item/mecha_parts/part/phazon_armor, - "action" = ITEM_DELETE, - "back_key" = TOOL_WELDER, - "desc" = "Phase armor is welded.", - "icon_state" = "phazon21" - ), - - //24 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed.", - "icon_state" = "phazon22" - ), - - //25 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched.", - "icon_state" = "phazon23" - ), - - //26 - list( - "key" = /obj/item/assembly/signaler/anomaly, - "action" = ITEM_DELETE, - "back_key" = TOOL_WELDER, - "desc" = "Anomaly core socket is open.", - "icon_state" = "phazon24" - ), - ) - - -/datum/component/construction/mecha/phazon/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - //TODO: better messages. - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") - else - user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") - if(11) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") - if(12) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(13) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(14) - if(diff==FORWARD) - user.visible_message("[user] secures [I].", "You secure [I].") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(15) - if(diff==FORWARD) - user.visible_message("[user] installs [I].", "You install [I].") - else - user.visible_message("[user] unsecures the capacitor from [parent].", "You unsecure the capacitor from [parent].") - if(16) - if(diff==FORWARD) - user.visible_message("[user] connects the bluespace crystal.", "You connect the bluespace crystal.") - else - user.visible_message("[user] removes the bluespace crystal from [parent].", "You remove the bluespace crystal from [parent].") - if(17) - if(diff==FORWARD) - user.visible_message("[user] engages the bluespace crystal.", "You engage the bluespace crystal.") - else - user.visible_message("[user] disconnects the bluespace crystal from [parent].", "You disconnect the bluespace crystal from [parent].") - if(18) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disengages the bluespace crystal.", "You disengage the bluespace crystal.") - if(19) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(20) - if(diff==FORWARD) - user.visible_message("[user] installs the phase armor layer to [parent].", "You install the phase armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(21) - if(diff==FORWARD) - user.visible_message("[user] secures the phase armor layer.", "You secure the phase armor layer.") - else - user.visible_message("[user] pries the phase armor layer from [parent].", "You pry the phase armor layer from [parent].") - if(22) - if(diff==FORWARD) - user.visible_message("[user] welds the phase armor layer to [parent].", "You weld the phase armor layer to [parent].") - else - user.visible_message("[user] unfastens the phase armor layer.", "You unfasten the phase armor layer.") - if(23) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] cuts phase armor layer from [parent].", "You cut the phase armor layer from [parent].") - if(24) - if(diff==FORWARD) - user.visible_message("[user] secures Phazon Armor Plates.", "You secure Phazon Armor Plates.") - else - user.visible_message("[user] pries Phazon Armor Plates from [parent].", "You pry Phazon Armor Plates from [parent].") - if(25) - if(diff==FORWARD) - user.visible_message("[user] welds Phazon Armor Plates to [parent].", "You weld Phazon Armor Plates to [parent].") - else - user.visible_message("[user] unfastens Phazon Armor Plates.", "You unfasten Phazon Armor Plates.") - if(26) - if(diff==FORWARD) - user.visible_message("[user] carefully inserts the anomaly core into [parent] and secures it.", - "You slowly place the anomaly core into its socket and close its chamber.") - return TRUE - -//ODYSSEUS - -/datum/component/construction/unordered/mecha_chassis/odysseus - result = /datum/component/construction/mecha/odysseus - steps = list( - /obj/item/mecha_parts/part/odysseus_torso, - /obj/item/mecha_parts/part/odysseus_head, - /obj/item/mecha_parts/part/odysseus_left_arm, - /obj/item/mecha_parts/part/odysseus_right_arm, - /obj/item/mecha_parts/part/odysseus_left_leg, - /obj/item/mecha_parts/part/odysseus_right_leg - ) - -/datum/component/construction/mecha/odysseus - result = /obj/mecha/medical/odysseus - base_icon = "odysseus" - steps = list( - //1 - list( - "key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are disconnected." - ), - - //2 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_WRENCH, - "desc" = "The hydraulic systems are connected." - ), - - //3 - list( - "key" = /obj/item/stack/cable_coil, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The hydraulic systems are active." - ), - - //4 - list( - "key" = TOOL_WIRECUTTER, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is added." - ), - - //5 - list( - "key" = /obj/item/circuitboard/mecha/odysseus/main, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The wiring is adjusted." - ), - - //6 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Central control module is installed." - ), - - //7 - list( - "key" = /obj/item/circuitboard/mecha/odysseus/peripherals, - "action" = ITEM_DELETE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Central control module is secured." - ), - - //8 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Peripherals control module is installed." - ), - //9 - list( - "key" = /obj/item/stock_parts/scanning_module, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Peripherals control module is secured." - ), - - //10 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Scanner module is installed." - ), - - //11 - list( - "key" = /obj/item/stock_parts/capacitor, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanner module is secured." - ), - - //12 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "Capacitor is installed." - ), - - //13 - list( - "key" = /obj/item/stock_parts/cell, - "action" = ITEM_MOVE_INSIDE, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured." - ), - - //11 - list( - "key" = TOOL_SCREWDRIVER, - "back_key" = TOOL_CROWBAR, - "desc" = "The power cell is installed." - ), - - //12 - list( - "key" = /obj/item/stack/sheet/metal, - "amount" = 5, - "back_key" = TOOL_SCREWDRIVER, - "desc" = "The power cell is secured." - ), - - //13 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "Internal armor is installed." - ), - - //14 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "Internal armor is wrenched." - ), - - //15 - list( - "key" = /obj/item/stack/sheet/plasteel, - "amount" = 5, - "back_key" = TOOL_WELDER, - "desc" = "Internal armor is welded." - ), - - //16 - list( - "key" = TOOL_WRENCH, - "back_key" = TOOL_CROWBAR, - "desc" = "External armor is installed." - ), - - //17 - list( - "key" = TOOL_WELDER, - "back_key" = TOOL_WRENCH, - "desc" = "External armor is wrenched." - ), - ) - -/datum/component/construction/mecha/odysseus/custom_action(obj/item/I, mob/living/user, diff) - if(!..()) - return FALSE - - //TODO: better messages. - switch(index) - if(1) - user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") - if(2) - if(diff==FORWARD) - user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") - else - user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") - if(3) - if(diff==FORWARD) - user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") - else - user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") - if(4) - if(diff==FORWARD) - user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") - else - user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") - if(5) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") - if(6) - if(diff==FORWARD) - user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") - else - user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") - if(7) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") - if(8) - if(diff==FORWARD) - user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") - else - user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") - if(9) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") - if(10) - if(diff==FORWARD) - user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") - else - user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") - if(11) - if(diff==FORWARD) - user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") - else - user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") - if(12) - if(diff==FORWARD) - user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") - else - user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") - if(13) - if(diff==FORWARD) - user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") - else - user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") - if(14) - if(diff==FORWARD) - user.visible_message("[user] secures the power cell.", "You secure the power cell.") - else - user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") - if(15) - if(diff==FORWARD) - user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") - if(16) - if(diff==FORWARD) - user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") - else - user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") - if(17) - if(diff==FORWARD) - user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") - else - user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") - if(18) - if(diff==FORWARD) - user.visible_message("[user] installs the external armor layer to [parent].", "You install the external reinforced armor layer to [parent].") - else - user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") - if(19) - if(diff==FORWARD) - user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.") - else - user.visible_message("[user] pries the external armor layer from [parent].", "You pry the external armor layer from [parent].") - if(20) - if(diff==FORWARD) - user.visible_message("[user] welds the external armor layer to [parent].", "You weld the external armor layer to [parent].") - else - user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") - return TRUE diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm deleted file mode 100644 index 1db4cc30b9..0000000000 --- a/code/game/mecha/mecha_defense.dm +++ /dev/null @@ -1,334 +0,0 @@ -/obj/mecha/proc/get_armour_facing(relative_dir) - switch(relative_dir) - if(180) // BACKSTAB! - return facing_modifiers[BACK_ARMOUR] - if(0, 45) // direct or 45 degrees off - return facing_modifiers[FRONT_ARMOUR] - return facing_modifiers[SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side - -/obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) - . = ..() - if(. && obj_integrity > 0) - spark_system.start() - switch(damage_flag) - if("fire") - check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL)) - if("melee") - check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - else - check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT)) - if(. >= 5 || prob(33)) - occupant_message("Taking damage!") - log_append_to_last("Took [damage_amount] points of damage. Damage type: \"[damage_type]\".",1) - -/obj/mecha/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) - . = ..() - if(!damage_amount) - return 0 - var/booster_deflection_modifier = 1 - var/booster_damage_modifier = 1 - if(damage_flag == "bullet" || damage_flag == "laser" || damage_flag == "energy") - for(var/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/B in equipment) - if(B.projectile_react()) - booster_deflection_modifier = B.deflect_coeff - booster_damage_modifier = B.damage_coeff - break - else if(damage_flag == "melee") - for(var/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/B in equipment) - if(B.attack_react()) - booster_deflection_modifier *= B.deflect_coeff - booster_damage_modifier *= B.damage_coeff - break - - if(attack_dir) - var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir))) - booster_damage_modifier /= facing_modifier - booster_deflection_modifier *= facing_modifier - if(prob(deflect_chance * booster_deflection_modifier)) - visible_message("[src]'s armour deflects the attack!") - log_append_to_last("Armor saved.") - return 0 - if(.) - . *= booster_damage_modifier - - -/obj/mecha/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - playsound(loc, 'sound/weapons/tap.ogg', 40, 1, -1) - user.visible_message("[user] hits [name]. Nothing happens", null, null, COMBAT_MESSAGE_RANGE) - mecha_log_message("Attack by hand/paw. Attacker - [user].", color="red") - log_append_to_last("Armor saved.") - -/obj/mecha/attack_paw(mob/user as mob) - return attack_hand(user) - - -/obj/mecha/attack_alien(mob/living/user) - mecha_log_message("Attack by alien. Attacker - [user].", color="red") - 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) - mecha_log_message("Attack by simple animal. Attacker - [user].", color="red") - if(!user.melee_damage_upper && !user.obj_damage) - user.emote("custom", message = "[user.friendly_verb_continuous] [src].") - return 0 - else - var/play_soundeffect = 1 - if(user.environment_smash) - play_soundeffect = 0 - playsound(src, 'sound/effects/bang.ogg', 50, 1) - var/animal_damage = rand(user.melee_damage_lower,user.melee_damage_upper) - if(user.obj_damage) - animal_damage = user.obj_damage - animal_damage = min(animal_damage, 20*user.environment_smash) - attack_generic(user, animal_damage, user.melee_damage_type, "melee", play_soundeffect) - log_combat(user, src, "attacked") - return 1 - - -/obj/mecha/hulk_damage() - return 15 - -/obj/mecha/attack_hulk(mob/living/carbon/human/user) - . = ..() - if(.) - mecha_log_message("Attack by hulk. Attacker - [user].", color="red") - log_combat(user, src, "punched", "hulk powers") - -/obj/mecha/blob_act(obj/structure/blob/B) - take_damage(30, BRUTE, "melee", 0, get_dir(src, B)) - -/obj/mecha/attack_tk() - return - -/obj/mecha/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) //wrapper - mecha_log_message("Hit by [AM].", color="red") - . = ..() - - -/obj/mecha/bullet_act(obj/item/projectile/Proj) //wrapper - mecha_log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).", color="red") - . = ..() - -/obj/mecha/ex_act(severity, target, origin) - mecha_log_message("Affected by explosion of severity: [severity].", color="red") - if(prob(deflect_chance)) - severity++ - log_append_to_last("Armor saved, changing severity to [severity].") - . = ..() - -/obj/mecha/contents_explosion(severity, target, origin) - severity++ - for(var/X in equipment) - var/obj/item/mecha_parts/mecha_equipment/ME = X - ME.ex_act(severity, target, origin) - for(var/Y in trackers) - var/obj/item/mecha_parts/mecha_tracking/MT = Y - MT.ex_act(severity, target, origin) - if(occupant) - occupant.ex_act(severity, target, origin) - -/obj/mecha/handle_atom_del(atom/A) - if(A == occupant) - occupant = null - icon_state = initial(icon_state)+"-open" - setDir(dir_in) - -/obj/mecha/emp_act(severity) - . = ..() - if (. & EMP_PROTECT_SELF) - return - if(get_charge()) - use_power((cell.charge/3)*(severity*0.005)) - take_damage(severity/3, BURN, "energy", 1) - mecha_log_message("EMP detected", color="red") - - if(istype(src, /obj/mecha/combat)) - mouse_pointer = 'icons/mecha/mecha_mouse-disable.dmi' - occupant?.update_mouse_pointer() - if(!equipment_disabled && occupant) //prevent spamming this message with back-to-back EMPs - to_chat(occupant, "Error -- Connection to equipment control unit has been lost.") - addtimer(CALLBACK(src, /obj/mecha/proc/restore_equipment), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) - equipment_disabled = 1 - -/obj/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(exposed_temperature>max_temperature) - mecha_log_message("Exposed to dangerous temperature.", color="red") - take_damage(5, BURN, 0, 1) - -/obj/mecha/attackby(obj/item/W as obj, mob/user as mob, params) - - if(istype(W, /obj/item/mmi)) - if(mmi_move_inside(W,user)) - to_chat(user, "[src]-[W] interface initialized successfully.") - else - to_chat(user, "[src]-[W] interface initialization failed.") - return - - if(istype(W, /obj/item/mecha_ammo)) - ammo_resupply(W, user) - return - - if(istype(W, /obj/item/mecha_parts/mecha_equipment)) - var/obj/item/mecha_parts/mecha_equipment/E = W - spawn() - if(E.can_attach(src)) - if(!user.temporarilyRemoveItemFromInventory(W)) - return - E.attach(src) - user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src].") - else - to_chat(user, "You were unable to attach [W] to [src]!") - return - if(W.GetID()) - if(add_req_access || maint_access) - if(internals_access_allowed(user)) - var/obj/item/card/id/id_card - if(istype(W, /obj/item/card/id)) - id_card = W - else - var/obj/item/pda/pda = W - id_card = pda.id - output_maintenance_dialog(id_card, user) - return - else - to_chat(user, "Invalid ID: Access denied.") - else - to_chat(user, "Maintenance protocols disabled by operator.") - else if(W.tool_behaviour == TOOL_WRENCH) - if(state==1) - state = 2 - to_chat(user, "You undo the securing bolts.") - else if(state==2) - state = 1 - to_chat(user, "You tighten the securing bolts.") - return - else if(W.tool_behaviour == TOOL_CROWBAR) - if(state==2) - state = 3 - to_chat(user, "You open the hatch to the power unit.") - else if(state==3) - state=2 - to_chat(user, "You close the hatch to the power unit.") - return - else if(istype(W, /obj/item/stack/cable_coil)) - if(state == 3 && (internal_damage & MECHA_INT_SHORT_CIRCUIT)) - if(W.use_tool(src, user, 0, 2)) - clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) - to_chat(user, "You replace the fused wires.") - else - to_chat(user, "You need two lengths of cable to fix this mech!") - return - else if(W.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != INTENT_HARM) - if(internal_damage & MECHA_INT_TEMP_CONTROL) - clearInternalDamage(MECHA_INT_TEMP_CONTROL) - to_chat(user, "You repair the damaged temperature controller.") - else if(state==3 && cell) - cell.forceMove(loc) - cell = null - state = 4 - to_chat(user, "You unscrew and pry out the powercell.") - mecha_log_message("Powercell removed") - else if(state==4 && cell) - state=3 - to_chat(user, "You screw the cell in place.") - return - - else if(istype(W, /obj/item/stock_parts/cell)) - if(state==4) - if(!cell) - if(!user.transferItemToLoc(W, src)) - return - var/obj/item/stock_parts/cell/C = W - to_chat(user, "You install the powercell.") - cell = C - mecha_log_message("Powercell installed") - else - to_chat(user, "There's already a powercell installed.") - return - - else if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) - user.DelayNextAction(CLICK_CD_MELEE) - if(obj_integrity < max_integrity) - if(W.use_tool(src, user, 0, volume=50, amount=1)) - if (internal_damage & MECHA_INT_TANK_BREACH) - clearInternalDamage(MECHA_INT_TANK_BREACH) - to_chat(user, "You repair the damaged gas tank.") - else - user.visible_message("[user] repairs some damage to [name].", "You repair some damage to [src].") - obj_integrity += min(10, max_integrity-obj_integrity) - if(obj_integrity == max_integrity) - to_chat(user, "It looks to be fully repaired now.") - return 1 - else - to_chat(user, "The [name] is at full integrity!") - return 1 - - else if(istype(W, /obj/item/mecha_parts/mecha_tracking)) - var/obj/item/mecha_parts/mecha_tracking/tracker = W - tracker.try_attach_part(user, src) - return - else - return ..() - -/obj/mecha/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1) - mecha_log_message("Attacked by [I]. Attacker - [user]") - return ..() - -/obj/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) - target.reagents.add_reagent(/datum/reagent/cryptobiolin, force/2) - if(target.reagents.get_reagent_amount(/datum/reagent/toxin) + force < force*2) - target.reagents.add_reagent(/datum/reagent/toxin, force/2.5) - - -/obj/mecha/mech_melee_attack(obj/mecha/M) - if(!has_charge(melee_energy_drain)) - return 0 - 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)])") - . = ..() - -/obj/mecha/proc/full_repair(charge_cell) - obj_integrity = max_integrity - if(cell && charge_cell) - cell.charge = cell.maxcharge - if(internal_damage & MECHA_INT_FIRE) - clearInternalDamage(MECHA_INT_FIRE) - if(internal_damage & MECHA_INT_TEMP_CONTROL) - clearInternalDamage(MECHA_INT_TEMP_CONTROL) - if(internal_damage & MECHA_INT_SHORT_CIRCUIT) - clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) - if(internal_damage & MECHA_INT_TANK_BREACH) - clearInternalDamage(MECHA_INT_TANK_BREACH) - if(internal_damage & MECHA_INT_CONTROL_LOST) - clearInternalDamage(MECHA_INT_CONTROL_LOST) - -/obj/mecha/narsie_act() - emp_act(100) - -/obj/mecha/ratvar_act() - if((GLOB.ratvar_awakens || GLOB.clockwork_gateway_activated) && occupant) - if(is_servant_of_ratvar(occupant)) //reward the minion that got a mech by repairing it - full_repair(TRUE) - else - var/mob/living/L = occupant - go_out(TRUE) - if(L) - L.ratvar_act() - -/obj/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) - if(!no_effect) - if(selected) - used_item = selected - else if(!visual_effect_icon) - visual_effect_icon = ATTACK_EFFECT_SMASH - if(damtype == BURN) - visual_effect_icon = ATTACK_EFFECT_MECHFIRE - else if(damtype == TOX) - visual_effect_icon = ATTACK_EFFECT_MECHTOXIN - ..() diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm deleted file mode 100644 index 067cffd319..0000000000 --- a/code/game/mecha/mecha_topic.dm +++ /dev/null @@ -1,360 +0,0 @@ - -//////////////////////////////////// -///// Rendering stats window /////// -//////////////////////////////////// - -/obj/mecha/proc/get_stats_html() - . = {" - - - [name] data - - - - -
- [src.get_stats_part()] -
-
- [src.get_equipment_list()] -
-
-
- [src.get_commands()] -
- - - "} - - - -/obj/mecha/proc/report_internal_damage() - . = "" - var/list/dam_reports = list( - "[MECHA_INT_FIRE]" = "INTERNAL FIRE", - "[MECHA_INT_TEMP_CONTROL]" = "LIFE SUPPORT SYSTEM MALFUNCTION", - "[MECHA_INT_TANK_BREACH]" = "GAS TANK BREACH", - "[MECHA_INT_CONTROL_LOST]" = "COORDINATION SYSTEM CALIBRATION FAILURE - Recalibrate", - "[MECHA_INT_SHORT_CIRCUIT]" = "SHORT CIRCUIT" - ) - for(var/tflag in dam_reports) - var/intdamflag = text2num(tflag) - if(internal_damage & intdamflag) - . += dam_reports[tflag] - . += "
" - if(return_pressure() > WARNING_HIGH_PRESSURE) - . += "DANGEROUSLY HIGH CABIN PRESSURE
" - - - -/obj/mecha/proc/get_stats_part() - var/integrity = obj_integrity/max_integrity*100 - var/cell_charge = get_charge() - var/datum/gas_mixture/int_tank_air = internal_tank.return_air() - var/tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None" - var/tank_temperature = internal_tank ? int_tank_air.return_temperature() : "Unknown" - var/cabin_pressure = round(return_pressure(),0.01) - . = {"[report_internal_damage()] - [integrity<30?"DAMAGE LEVEL CRITICAL
":null] - Integrity: [integrity]%
- Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
- Air source: [use_internal_tank?"Internal Airtank":"Environment"]
- Airtank pressure: [tank_pressure]kPa
- Airtank temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
- Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
- [dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":""]
- [thrusters_action.owner ? "Thrusters: [thrusters_active ? "Enabled" : "Disabled"]
" : ""] - [defense_action.owner ? "Defence Mode: [defence_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"]
" : ""] - "} - - -/obj/mecha/proc/get_commands() - . = {"
-
Electronics
- -
- -
[get_equipment_menu()]
- "} - - -/obj/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu - . = "" - if(equipment.len) - . += {"
-
Equipment
-
" - - -/obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html - if(!equipment.len) - return - . = "Equipment:
" - for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) - . += "
[MT.get_equip_info()]
" - . += "
" - - - -/obj/mecha/proc/get_log_html() - . = "[src.name] Log" - for(var/list/entry in log) - . += {"
[entry["time"]] [time2text(entry["date"],"MMM DD")] [entry["year"]]
-
[entry["message"]]
- "} - . += "" - - - -/obj/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user) - if(!id_card || !user) - return - . = {" - - - - - -

Following keycodes are present in this system:

"} - for(var/a in operation_req_access) - . += "[get_access_desc(a)] - Delete
" - . += "

Following keycodes were detected on portable device:

" - for(var/a in id_card.access) - if(a in operation_req_access) - continue - var/a_name = get_access_desc(a) - if(!a_name) - continue //there's some strange access without a name - . += "[a_name] - Add
" - . += "
Finish " - . += "(Warning! The ID upload panel will be locked. It can be unlocked only through Exosuit Interface.)" - . += "" - user << browse(., "window=exosuit_add_access") - onclose(user, "exosuit_add_access") - - -/obj/mecha/proc/output_maintenance_dialog(obj/item/card/id/id_card,mob/user) - if(!id_card || !user) - return - . = {" - - - - - - [add_req_access?"Edit operation keycodes":null] - [maint_access?"[(state>0) ? "Terminate" : "Initiate"] maintenance protocol":null] - [(state>0) ?"Set Cabin Air Pressure":null] - - "} - user << browse(., "window=exosuit_maint_console") - onclose(user, "exosuit_maint_console") - - - - -///////////////// -///// Topic ///// -///////////////// - -/obj/mecha/Topic(href, href_list) - ..() - if(href_list["close"]) - return - - if(usr.incapacitated()) - return - - if(in_range(src, usr)) - var/obj/item/card/id/id_card - if (href_list["id_card"]) - id_card = locate(href_list["id_card"]) - if (!istype(id_card)) - return - - if(href_list["req_access"] && add_req_access) - output_access_dialog(id_card, usr) - - if(href_list["maint_access"] && maint_access) - if(state==0) - state = 1 - to_chat(usr, "The securing bolts are now exposed.") - else if(state==1) - state = 0 - to_chat(usr, "The securing bolts are now hidden.") - output_maintenance_dialog(id_card, usr) - - if(href_list["set_internal_tank_valve"] && state >=1) - var/new_pressure = input(usr,"Input new output pressure","Pressure setting",internal_tank_valve) as num - if(new_pressure) - internal_tank_valve = new_pressure - to_chat(usr, "The internal pressure valve has been set to [internal_tank_valve]kPa.") - - if(href_list["add_req_access"] && add_req_access) - operation_req_access += text2num(href_list["add_req_access"]) - output_access_dialog(id_card, usr) - - if(href_list["del_req_access"] && add_req_access) - operation_req_access -= text2num(href_list["del_req_access"]) - output_access_dialog(id_card, usr) - - if(href_list["finish_req_access"]) - add_req_access = 0 - usr << browse(null,"window=exosuit_add_access") - - if(usr != occupant) - return - - if(href_list["update_content"]) - send_byjax(usr,"exosuit.browser","content",src.get_stats_part()) - - if(href_list["select_equip"]) - var/obj/item/mecha_parts/mecha_equipment/equip = locate(href_list["select_equip"]) in src - if(equip && equip.selectable) - selected = equip - occupant_message("You switch to [equip]") - visible_message("[src] raises [equip]") - send_byjax(usr, "exosuit.browser","eq_list", get_equipment_list()) - - if(href_list["rmictoggle"]) - radio.broadcasting = !radio.broadcasting - send_byjax(usr,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged")) - - if(href_list["rspktoggle"]) - radio.listening = !radio.listening - send_byjax(usr,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged")) - - if(href_list["rfreq"]) - var/new_frequency = (radio.frequency + text2num(href_list["rfreq"])) - if (!radio.freerange || (radio.frequency < MIN_FREE_FREQ || radio.frequency > MAX_FREE_FREQ)) - new_frequency = sanitize_frequency(new_frequency) - radio.set_frequency(new_frequency) - send_byjax(usr,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]") - - if (href_list["view_log"]) - src.occupant << browse(src.get_log_html(), "window=exosuit_log") - onclose(occupant, "exosuit_log") - - if (href_list["change_name"]) - var/userinput = stripped_input(occupant,"Choose new exosuit name","Rename exosuit","", MAX_NAME_LEN) - if(!userinput || usr != occupant || usr.incapacitated()) - return - name = userinput - return - - 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") - - if(href_list["toggle_maint_access"]) - if(state) - occupant_message("Maintenance protocols in effect") - return - maint_access = !maint_access - send_byjax(usr,"exosuit.browser","t_maint_access","[maint_access?"Forbid":"Permit"] maintenance protocols") - - if (href_list["toggle_port_connection"]) - if(internal_tank.connected_port) - if(internal_tank.disconnect()) - occupant_message("Disconnected from the air system port.") - mecha_log_message("Disconnected from gas port.") - else - occupant_message("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.") - mecha_log_message("Connected to gas port.") - else - occupant_message("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") - - if(href_list["dna_lock"]) - if(!occupant) - return - var/mob/living/carbon/C = occupant - if(!istype(C) || !C.dna) - to_chat(C, " You do not have any DNA!") - return - dna_lock = C.dna.unique_enzymes - occupant_message("You feel a prick as the needle takes your DNA sample.") - - if(href_list["reset_dna"]) - dna_lock = null - - if(href_list["repair_int_control_lost"]) - occupant_message("Recalibrating coordination system...") - mecha_log_message("Recalibration of coordination system started.") - var/T = loc - spawn(100) - if(T == loc) - clearInternalDamage(MECHA_INT_CONTROL_LOST) - occupant_message("Recalibration successful.") - mecha_log_message("Recalibration of coordination system finished with 0 errors.") - else - occupant_message("Recalibration failed!") - mecha_log_message("Recalibration of coordination system failed with 1 error.", color="red") - diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm deleted file mode 100644 index 36584b85ec..0000000000 --- a/code/game/mecha/mecha_wreckage.dm +++ /dev/null @@ -1,271 +0,0 @@ -/////////////////////////////////// -//////// Mecha wreckage //////// -/////////////////////////////////// - - -/obj/structure/mecha_wreckage - name = "exosuit wreckage" - desc = "Remains of some unfortunate mecha. Completely irreparable, but perhaps something can be salvaged." - icon = 'icons/mecha/mecha.dmi' - density = TRUE - anchored = FALSE - opacity = 0 - var/list/welder_salvage = list(/obj/item/stack/sheet/plasteel, /obj/item/stack/sheet/metal, /obj/item/stack/rods) - var/list/wirecutters_salvage = list(/obj/item/stack/cable_coil) - var/list/crowbar_salvage = list() - var/salvage_num = 5 - var/mob/living/silicon/ai/AI //AIs to be salvaged - -/obj/structure/mecha_wreckage/Initialize(mapload, mob/living/silicon/ai/AI_pilot) - . = ..() - if(!AI_pilot) //Type-checking for this is already done in mecha/Destroy() - return - - AI = AI_pilot - AI.apply_damage(150, BURN) //Give the AI a bit of damage from the "shock" of being suddenly shut down - AI.death() //The damage is not enough to kill the AI, but to be 'corrupted files' in need of repair. - AI.forceMove(src) //Put the dead AI inside the wreckage for recovery - add_overlay(mutable_appearance('icons/obj/projectiles.dmi', "green_laser")) //Overlay for the recovery beacon - AI.controlled_mech = null - AI.remote_control = null - -/obj/structure/mecha_wreckage/examine(mob/user) - . = ..() - if(AI) - . += "The AI recovery beacon is active." - -/obj/structure/mecha_wreckage/attackby(obj/item/I, mob/user, params) - if(I.tool_behaviour == TOOL_WELDER) - if(salvage_num <= 0 || !length(welder_salvage)) - to_chat(user, "You don't see anything that can be cut with [I]!") - return - - if(!I.use_tool(src, user, 0, volume=50)) - return - - var/type = prob(70) ? pick(welder_salvage) : null - if(type) - var/N = new type(get_turf(user)) - user.visible_message("[user] cuts [N] from [src].", "You cut [N] from [src].") - if(istype(N, /obj/item/mecha_parts/part)) - welder_salvage -= type - salvage_num-- - else - to_chat(user, "You fail to salvage anything valuable from [src]!") - return - - else if(I.tool_behaviour == TOOL_WIRECUTTER) - if(salvage_num <= 0) - to_chat(user, "You don't see anything that can be cut with [I]!") - return - else if(wirecutters_salvage && wirecutters_salvage.len) - var/type = prob(70) ? pick(wirecutters_salvage) : null - if(type) - var/N = new type(get_turf(user)) - user.visible_message("[user] cuts [N] from [src].", "You cut [N] from [src].") - salvage_num-- - else - to_chat(user, "You fail to salvage anything valuable from [src]!") - - else if(I.tool_behaviour == TOOL_CROWBAR) - if(crowbar_salvage && crowbar_salvage.len) - var/obj/S = pick(crowbar_salvage) - if(S) - S.forceMove(user.drop_location()) - crowbar_salvage -= S - user.visible_message("[user] pries [S] from [src].", "You pry [S] from [src].") - return - else - to_chat(user, "You don't see anything that can be pried with [I]!") - - -/obj/structure/mecha_wreckage/transfer_ai(interaction, mob/user, null, obj/item/aicard/card) - if(!..()) - return - - //Proc called on the wreck by the AI card. - if(interaction == AI_TRANS_TO_CARD) //AIs can only be transferred in one direction, from the wreck to the card. - if(!AI) //No AI in the wreck - to_chat(user, "No AI backups found.") - return - cut_overlays() //Remove the recovery beacon overlay - AI.forceMove(card) //Move the dead AI to the card. - card.AI = AI - if(AI.client) //AI player is still in the dead AI and is connected - to_chat(AI, "The remains of your file system have been recovered on a mobile storage device.") - else //Give the AI a heads-up that it is probably going to get fixed. - AI.notify_ghost_cloning("You have been recovered from the wreckage!", source = card) - to_chat(user, "Backup files recovered: [AI.name] ([rand(1000,9999)].exe) salvaged from [name] and stored within local memory.") - - else - return ..() - - -/obj/structure/mecha_wreckage/gygax - name = "\improper Gygax wreckage" - icon_state = "gygax-broken" - -/obj/structure/mecha_wreckage/gygax/Initialize() - . = ..() - var/list/parts = list(/obj/item/mecha_parts/part/gygax_torso, - /obj/item/mecha_parts/part/gygax_head, - /obj/item/mecha_parts/part/gygax_left_arm, - /obj/item/mecha_parts/part/gygax_right_arm, - /obj/item/mecha_parts/part/gygax_left_leg, - /obj/item/mecha_parts/part/gygax_right_leg) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part - - - -/obj/structure/mecha_wreckage/gygax/dark - name = "\improper Dark Gygax wreckage" - icon_state = "darkgygax-broken" - -/obj/structure/mecha_wreckage/medigax - name = "\improper Medical Gygax wreckage" - icon_state = "medigax-broken" - -/obj/structure/mecha_wreckage/medigax/Initialize() - . = ..() - var/list/parts = list(/obj/item/mecha_parts/part/medigax_torso, - /obj/item/mecha_parts/part/medigax_head, - /obj/item/mecha_parts/part/medigax_left_arm, - /obj/item/mecha_parts/part/medigax_right_arm, - /obj/item/mecha_parts/part/medigax_left_leg, - /obj/item/mecha_parts/part/medigax_right_leg) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part - -/obj/structure/mecha_wreckage/marauder - name = "\improper Marauder wreckage" - icon_state = "marauder-broken" - -/obj/structure/mecha_wreckage/mauler - name = "\improper Mauler wreckage" - icon_state = "mauler-broken" - desc = "The syndicate won't be very happy about this..." - -/obj/structure/mecha_wreckage/seraph - name = "\improper Seraph wreckage" - icon_state = "seraph-broken" - -/obj/structure/mecha_wreckage/reticence - name = "\improper Reticence wreckage" - icon_state = "reticence-broken" - color = "#87878715" - desc = "..." - -/obj/structure/mecha_wreckage/ripley - name = "\improper Ripley wreckage" - icon_state = "ripley-broken" - -/obj/structure/mecha_wreckage/ripley/Initialize() - . = ..() - var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso, - /obj/item/mecha_parts/part/ripley_left_arm, - /obj/item/mecha_parts/part/ripley_right_arm, - /obj/item/mecha_parts/part/ripley_left_leg, - /obj/item/mecha_parts/part/ripley_right_leg) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part - - -/obj/structure/mecha_wreckage/ripley/firefighter - name = "\improper Firefighter wreckage" - icon_state = "firefighter-broken" - -/obj/structure/mecha_wreckage/ripley/firefighter/Initialize() - . = ..() - var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso, - /obj/item/mecha_parts/part/ripley_left_arm, - /obj/item/mecha_parts/part/ripley_right_arm, - /obj/item/mecha_parts/part/ripley_left_leg, - /obj/item/mecha_parts/part/ripley_right_leg, - /obj/item/clothing/suit/fire) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part - - -/obj/structure/mecha_wreckage/ripley/deathripley - name = "\improper Death-Ripley wreckage" - icon_state = "deathripley-broken" - - -/obj/structure/mecha_wreckage/honker - name = "\improper H.O.N.K wreckage" - icon_state = "honker-broken" - desc = "All is right in the universe." - -/obj/structure/mecha_wreckage/honker/Initialize() - . = ..() - var/list/parts = list( - /obj/item/mecha_parts/chassis/honker, - /obj/item/mecha_parts/part/honker_torso, - /obj/item/mecha_parts/part/honker_head, - /obj/item/mecha_parts/part/honker_left_arm, - /obj/item/mecha_parts/part/honker_right_arm, - /obj/item/mecha_parts/part/honker_left_leg, - /obj/item/mecha_parts/part/honker_right_leg) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part - - -/obj/structure/mecha_wreckage/durand - name = "\improper Durand wreckage" - icon_state = "durand-broken" - -/obj/structure/mecha_wreckage/durand/Initialize() - . = ..() - var/list/parts = list( - /obj/item/mecha_parts/part/durand_torso, - /obj/item/mecha_parts/part/durand_head, - /obj/item/mecha_parts/part/durand_left_arm, - /obj/item/mecha_parts/part/durand_right_arm, - /obj/item/mecha_parts/part/durand_left_leg, - /obj/item/mecha_parts/part/durand_right_leg) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part - - -/obj/structure/mecha_wreckage/phazon - name = "\improper Phazon wreckage" - icon_state = "phazon-broken" - - -/obj/structure/mecha_wreckage/odysseus - name = "\improper Odysseus wreckage" - icon_state = "odysseus-broken" - -/obj/structure/mecha_wreckage/odysseus/Initialize() - . = ..() - var/list/parts = list( - /obj/item/mecha_parts/part/odysseus_torso, - /obj/item/mecha_parts/part/odysseus_head, - /obj/item/mecha_parts/part/odysseus_left_arm, - /obj/item/mecha_parts/part/odysseus_right_arm, - /obj/item/mecha_parts/part/odysseus_left_leg, - /obj/item/mecha_parts/part/odysseus_right_leg) - for(var/i = 0; i < 2; i++) - if(parts.len && prob(40)) - var/part = pick(parts) - welder_salvage += part - parts -= part diff --git a/code/game/mecha/medical/medical.dm b/code/game/mecha/medical/medical.dm deleted file mode 100644 index 8b4e48cd3e..0000000000 --- a/code/game/mecha/medical/medical.dm +++ /dev/null @@ -1,16 +0,0 @@ -/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 diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm deleted file mode 100644 index 3c2f75bd6c..0000000000 --- a/code/game/mecha/working/ripley.dm +++ /dev/null @@ -1,188 +0,0 @@ -/obj/mecha/working/ripley - desc = "Autonomous Power Loader Unit. This newer model is refitted with powerful armour against the dangers of planetary mining." - name = "\improper APLU \"Ripley\"" - icon_state = "ripley" - step_in = 3 //Move speed, lower is faster. - var/fast_pressure_step_in = 2 - var/slow_pressure_step_in = 3 - max_temperature = 20000 - max_integrity = 200 - lights_power = 8 - deflect_chance = 15 - armor = list("melee" = 30, "bullet" = 15, "laser" = 10, "energy" = 20, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - max_equip = 6 - wreckage = /obj/structure/mecha_wreckage/ripley - var/list/cargo = new - var/cargo_capacity = 15 - var/hides = 0 - -/obj/mecha/working/ripley/Move() - . = ..() - if(.) - collect_ore() - update_pressure() - -/obj/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/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() - ..() - update_icon() - -/obj/mecha/working/ripley/moved_inside(mob/living/carbon/human/H) - ..() - update_icon() - -/obj/mecha/working/ripley/Initialize() - . = ..() - AddComponent(/datum/component/armor_plate,3,/obj/item/stack/sheet/animalhide/goliath_hide,list("melee" = 10, "bullet" = 5, "laser" = 5)) - - -/obj/mecha/working/ripley/firefighter - desc = "Autonomous Power Loader Unit. This model is refitted with additional thermal protection." - name = "\improper APLU \"Firefighter\"" - icon_state = "firefighter" - step_in = 4 - fast_pressure_step_in = 2 - slow_pressure_step_in = 4 - max_temperature = 65000 - max_integrity = 250 - resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - lights_power = 7 - armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - max_equip = 5 // More armor, less tools - wreckage = /obj/structure/mecha_wreckage/ripley/firefighter - - -/obj/mecha/working/ripley/deathripley - desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE" - name = "\improper DEATH-RIPLEY" - icon_state = "deathripley" - armor = list("melee" = 40, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - slow_pressure_step_in = 3 - opacity=0 - lights_power = 7 - wreckage = /obj/structure/mecha_wreckage/ripley/deathripley - step_energy_drain = 0 - -/obj/mecha/working/ripley/deathripley/Initialize() - . = ..() - 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 - desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE. FOR REAL" - -/obj/mecha/working/ripley/deathripley/real/Initialize() - . = ..() - for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) - E.detach() - qdel(E) - equipment.Cut() - 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 - desc = "An old, dusty mining Ripley." - name = "\improper APLU \"Miner\"" - obj_integrity = 75 //Low starting health - -/obj/mecha/working/ripley/mining/Initialize() - . = ..() - 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/mecha/working/ripley/Exit(atom/movable/O) - if(O in cargo) - return 0 - return ..() - -/obj/mecha/working/ripley/Topic(href, href_list) - ..() - if(href_list["drop_from_cargo"]) - var/obj/O = locate(href_list["drop_from_cargo"]) - if(O && (O in cargo)) - occupant_message("You unload [O].") - O.forceMove(drop_location()) - cargo -= O - mecha_log_message("Unloaded [O]. Cargo compartment capacity: [cargo_capacity - src.cargo.len]") - return - - -/obj/mecha/working/ripley/contents_explosion(severity, target, origin) - for(var/X in cargo) - var/obj/O = X - if(prob(30/severity)) - cargo -= O - O.forceMove(drop_location()) - . = ..() - -/obj/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/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) - 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]!") diff --git a/code/game/mecha/working/working.dm b/code/game/mecha/working/working.dm deleted file mode 100644 index c9e7d99ac0..0000000000 --- a/code/game/mecha/working/working.dm +++ /dev/null @@ -1,3 +0,0 @@ -/obj/mecha/working - internal_damage_threshold = 60 - diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index fb245f7607..5d573c5a43 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -18,9 +18,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/effects/temporary_visuals/clockcult.dm b/code/game/objects/effects/temporary_visuals/clockcult.dm index 9a236c00c3..4d79d50301 100644 --- a/code/game/objects/effects/temporary_visuals/clockcult.dm +++ b/code/game/objects/effects/temporary_visuals/clockcult.dm @@ -132,11 +132,15 @@ L.apply_damage(damage, BURN, "chest", L.run_armor_check("chest", "laser", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 0, "Your armor was penetrated by [src]!")) log_combat(user, L, "struck with a volt blast") hit_amount++ - for(var/obj/mecha/M in T) - if(M.occupant) - if(is_servant_of_ratvar(M.occupant)) - continue - to_chat(M.occupant, "Your [M.name] is struck by a [name]!") + for(var/obj/vehicle/sealed/mecha/M in T) + if(LAZYLEN(M.occupants)) + for(var/mob/living/MB in M.occupants) + if(is_servant_of_ratvar(MB)) + continue + else + to_chat(MB, "Your [M.name] is struck by a [name]!") + continue + M.visible_message("[M] is struck by a [name]!") M.take_damage(damage, BURN, 0, 0) hit_amount++ diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 54bdeff4de..14d5d943a2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -841,9 +841,6 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb 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 e20321414d..da5bed07ce 100644 --- a/code/game/objects/items/devices/camera_bug.dm +++ b/code/game/objects/items/devices/camera_bug.dm @@ -161,7 +161,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 95a651b50e..33c683a6cc 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -171,26 +171,6 @@ #undef BLACKLISTED_OBJECTS -/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 - visible_message("[M.name] has hit [src].", null, 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() ex_act(EXPLODE_DEVASTATE) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index e8e170446b..1e7f4fd64b 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -445,11 +445,6 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) /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) if(get_dir(user,src) & dir) diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm index e4d991a082..041751d0cd 100644 --- a/code/game/turfs/simulated/wall/misc_walls.dm +++ b/code/game/turfs/simulated/wall/misc_walls.dm @@ -145,10 +145,11 @@ user.adjustFireLoss(5) playsound(src, 'sound/machines/fryer/deep_fryer_emerge.ogg', 50, TRUE) -/turf/closed/wall/clockwork/mech_melee_attack(obj/mecha/M) +/turf/closed/wall/clockwork/mech_melee_attack(obj/vehicle/sealed/mecha/M) ..() if(heated) - to_chat(M.occupant, "The wall's intense heat completely reflects your [M.name]'s attack!") + for(var/mob/living/MB in M.occupants) + to_chat(MB, "The wall's intense heat completely reflects your [M.name]'s attack!") M.take_damage(20, BURN) /turf/closed/wall/clockwork/proc/turn_up_the_heat() diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 6303b33afa..cac03b0637 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -115,23 +115,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) - visible_message("[M.name] has hit [src]!", null, 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) return attack_hand(user) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 419378acb9..aaf8364229 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -379,7 +379,7 @@ GLOBAL_LIST_EMPTY(station_turfs) continue//Will not harm U. Since null != M, can be excluded to kill everyone. M.adjustBruteLoss(damage) M.Unconscious(damage * 4) - for(var/obj/mecha/M in src) + for(var/obj/vehicle/sealed/mecha/M in src) M.take_damage(damage*2, BRUTE, "melee", 1) /turf/proc/Bless() diff --git a/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm b/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm index 76738ab1de..8d0dff0ea8 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm @@ -72,8 +72,11 @@ drain_amount: How much is drained by default; Influenced by a multiplier on most cell.use(.) spark_system.start() -/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) - if(!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) +/obj/vehicle/sealed/mecha/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) + if(!clockcult_user || LAZYLEN(occupants)) + for(var/mob/living/MB in occupants) + if(is_servant_of_ratvar(MB)) + return if(recursive) var/succ = 0 for(var/atom/movable/target in contents) //Hiding in your mech won't save you. diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm index e251fb41e9..ae524ac257 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm @@ -207,20 +207,20 @@ /datum/clockwork_scripture/create_object/summon_arbiter descname = "Powerful Assault Mech" name = "Summon Neovgre, the Anima Bulwark" - desc = "Calls forth the mighty Anima Bulwark, a mech with superior defensive and offensive capabilities. It will \ + desc = "Calls forth the mighty Anima Bulwark, a two-person mech with superior defensive and offensive capabilities. It will \ steadily regenerate HP and triple its regeneration speed while standing \ on a clockwork tile. It will automatically draw power from nearby sigils of \ transmission should the need arise. Its Arbiter laser cannon can decimate foes \ from a range and is capable of smashing through any barrier presented to it. \ - Be warned however, choosing to pilot Neovgre is a lifetime commitment, once you are \ - in you cannot leave and when it is destroyed it will explode catastrophically, with you inside." + Be warned however, choosing to pilot or man Neovgre is a lifetime commitment, once you are \ + in you cannot leave and when it is destroyed it will explode catastrophically, with everyone inside." invocations = list("By the strength of the alloy...!!", "...call forth the Arbiter!!") channel_time = 200 // This is a strong fucking weapon, 20 seconds channel time is getting off light I tell ya. power_cost = 75000 //75 KW usage_tip = "Neovgre is a powerful mech that will crush your enemies!" invokers_required = 5 multiple_invokers_used = TRUE - object_path = /obj/mecha/combat/neovgre + object_path = /obj/vehicle/sealed/mecha/combat/neovgre tier = SCRIPTURE_APPLICATION primary_component = BELLIGERENT_EYE sort_priority = 8 diff --git a/code/modules/antagonists/clockcult/clock_structure.dm b/code/modules/antagonists/clockcult/clock_structure.dm index 380e93f102..daafb2add3 100644 --- a/code/modules/antagonists/clockcult/clock_structure.dm +++ b/code/modules/antagonists/clockcult/clock_structure.dm @@ -72,11 +72,6 @@ return FALSE return ..() -/obj/structure/destructible/clockwork/mech_melee_attack(obj/mecha/M) - if(M.occupant && is_servant_of_ratvar(M.occupant) && immune_to_servant_attacks) - return FALSE - return ..() - /obj/structure/destructible/clockwork/proc/get_efficiency_mod() if(GLOB.ratvar_awakens) return 2 diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm index 00db2b0d72..44699b17ed 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm @@ -76,7 +76,7 @@ L.adjust_fire_stacks(damage_per_tick) L.IgniteMob() else if(ismecha(target)) - var/obj/mecha/M = target + var/obj/vehicle/sealed/mecha/M = target M.take_damage(damage_per_tick * get_efficiency_mod(), BURN, "melee", 1, get_dir(src, M)) new /obj/effect/temp_visual/ratvar/ocular_warden(get_turf(target)) @@ -91,8 +91,8 @@ var/mob/living/L = target to_chat(L, "\"I SEE YOU!\"\n[src]'s gaze [GLOB.ratvar_awakens ? "melts you alive" : "burns you"]!") else if(ismecha(target)) - var/obj/mecha/M = target - to_chat(M.occupant, "\"I SEE YOU!\"" ) + var/obj/vehicle/sealed/mecha/M = target + to_chat(M.occupants, "\"I SEE YOU!\"" ) else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes if(prob(50)) visible_message("[src][pick(idle_messages)]") @@ -131,8 +131,11 @@ . += L var/list/viewcache = list() for(var/N in GLOB.mechas_list) - var/obj/mecha/M = N - if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant)) + var/obj/vehicle/sealed/mecha/M = N + if(get_dist(M, src) <= sight_range && LAZYLEN(M.occupants)) + for(var/mob/living/MB in M.occupants) + if(is_servant_of_ratvar(MB)) + return if(!length(viewcache)) for (var/obj/Z in view(sight_range, src)) viewcache += Z diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm index 21735ad6d7..55143fae66 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm @@ -9,12 +9,14 @@ /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/mech/Crossed(atom/movable/AM) . = ..() - if(!istype(AM,/obj/mecha/)) + if(!istype(AM,/obj/vehicle/sealed/mecha/)) return - var/obj/mecha/M = AM - if(M.occupant && is_servant_of_ratvar(M.occupant)) - return + var/obj/vehicle/sealed/mecha/M = AM + if(LAZYLEN(M.occupants)) + for(var/mob/living/MB in M.occupants) + if(is_servant_of_ratvar(MB)) + return audible_message("*click*") playsound(src, 'sound/items/screwdriver2.ogg', 50, TRUE) activate() diff --git a/code/modules/antagonists/clockcult/clock_structures/traps/brass_skewer.dm b/code/modules/antagonists/clockcult/clock_structures/traps/brass_skewer.dm index e8ae133ede..ab4294df85 100644 --- a/code/modules/antagonists/clockcult/clock_structures/traps/brass_skewer.dm +++ b/code/modules/antagonists/clockcult/clock_structures/traps/brass_skewer.dm @@ -68,7 +68,7 @@ mouse_opacity = MOUSE_OPACITY_OPAQUE //So players can interact with the tile it's on to pull them off buckle_mob(squirrel, TRUE) else - var/obj/mecha/M = locate() in get_turf(src) + var/obj/vehicle/sealed/mecha/M = locate() in get_turf(src) if(M) M.take_damage(50,BRUTE,"melee") M.visible_message("A massive brass spike erupts from the ground, penetrating \the [M] and shattering the trap into pieces!") diff --git a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm index 158acc0071..bee2747626 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm @@ -402,7 +402,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 b7eac3499f..c1d22d9dbf 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,30 +16,30 @@ /datum/bounty/item/mech/ripley name = "APLU \"Ripley\"" reward = 13000 - wanted_types = list(/obj/mecha/working/ripley) - exclude_types = list(/obj/mecha/working/ripley/firefighter) + wanted_types = list(/obj/vehicle/sealed/mecha/working/ripley) + exclude_types = list(/obj/vehicle/sealed/mecha/working/ripley/firefighter) /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) + wanted_types = list(/obj/vehicle/sealed/mecha/combat/phazon) diff --git a/code/modules/cargo/exports.dm b/code/modules/cargo/exports.dm index b72e497a5f..e6ed245294 100644 --- a/code/modules/cargo/exports.dm +++ b/code/modules/cargo/exports.dm @@ -61,7 +61,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they if(ismob(thing)) thing.investigate_log("deleted through cargo export",INVESTIGATE_CARGO) if(ismecha(thing)) - var/obj/mecha/mech = thing + var/obj/vehicle/sealed/mecha/mech = thing mech.wreckage = null // why a mech left a wreck when sold i will never know qdel(thing) diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm index dca23c9f22..6d965e2c5a 100644 --- a/code/modules/cargo/exports/large_objects.dm +++ b/code/modules/cargo/exports/large_objects.dm @@ -278,69 +278,69 @@ /datum/export/large/mech/odysseus cost = 7500 unit_name = "working odysseus" - export_types = list(/obj/mecha/medical/odysseus) + export_types = list(/obj/vehicle/sealed/mecha/medical/odysseus) /datum/export/large/mech/ripley cost = 12000 unit_name = "working ripley" - export_types = list(/obj/mecha/working/ripley) + export_types = list(/obj/vehicle/sealed/mecha/working/ripley) /datum/export/large/mech/firefighter cost = 14000 unit_name = "working firefighter" - export_types = list(/obj/mecha/working/ripley/firefighter) + export_types = list(/obj/vehicle/sealed/mecha/working/ripley/firefighter) /datum/export/large/mech/gygax cost = 19000 unit_name = "working gygax" - export_types = list(/obj/mecha/combat/gygax) + export_types = list(/obj/vehicle/sealed/mecha/combat/gygax) /datum/export/large/mech/durand cost = 16000 unit_name = "working durand" - export_types = list(/obj/mecha/combat/durand) + export_types = list(/obj/vehicle/sealed/mecha/combat/durand) /datum/export/large/mech/phazon cost = 35000 //Little over half due to needing a core unit_name = "working phazon" - export_types = list(/obj/mecha/combat/phazon) + export_types = list(/obj/vehicle/sealed/mecha/combat/phazon) /datum/export/large/mech/marauder cost = 15000 //Still a Combat class mech - CC tech as well! 150% "normal" boundy price. unit_name = "working marauder" - export_types = list(/obj/mecha/combat/marauder) + export_types = list(/obj/vehicle/sealed/mecha/combat/marauder) /datum/export/large/mech/deathripley cost = 18500 //Still a "Combat class" mech - Illegal tech as well! 165% "normal" boundy price. unit_name = "working illegally modified" - export_types = list(/obj/mecha/working/ripley/deathripley) + export_types = list(/obj/vehicle/sealed/mecha/working/ripley/deathripley) /datum/export/large/mech/gygaxdark cost = 28500 //Still a Combat class mech - Illegal tech as well! 150% "normal" boundy price. unit_name = "working illegally modified gygax" - export_types = list(/obj/mecha/combat/gygax/dark) + export_types = list(/obj/vehicle/sealed/mecha/combat/gygax/dark) /datum/export/large/mech/oldripley cost = 6250 //old mech - Scrap metal ! 50% "normal" boundy price. unit_name = "working miner ripley" - export_types = list(/obj/mecha/working/ripley/mining) + export_types = list(/obj/vehicle/sealed/mecha/working/ripley/mining) /datum/export/large/mech/honk cost = 16000 //Still a "Combat class" mech - Comats bordem honk! unit_name = "working honker" - export_types = list(/obj/mecha/combat/honker) + export_types = list(/obj/vehicle/sealed/mecha/combat/honker) /datum/export/large/mech/reticence cost = 16000 //Still a "Combat class" mech - Has cloking and lethal weaponds. unit_name = "working reticence" - export_types = list(/obj/mecha/combat/reticence) + export_types = list(/obj/vehicle/sealed/mecha/combat/reticence) /datum/export/large/mech/seraph cost = 25500 //Still a Combat class mech - CC tech as well! 150% "normal" boundy price. unit_name = "working seraph" - export_types = list(/obj/mecha/combat/marauder/seraph) + export_types = list(/obj/vehicle/sealed/mecha/combat/marauder/seraph) /datum/export/large/mech/mauler cost = 25000 //Still a Combat class mech - CC lethal weaponds. unit_name = "working legally modified marauder" - export_types = list(/obj/mecha/combat/marauder/mauler) + export_types = list(/obj/vehicle/sealed/mecha/combat/marauder/mauler) diff --git a/code/modules/cargo/exports/organs_robotics.dm b/code/modules/cargo/exports/organs_robotics.dm index 08340e6a56..40f7edbd99 100644 --- a/code/modules/cargo/exports/organs_robotics.dm +++ b/code/modules/cargo/exports/organs_robotics.dm @@ -163,7 +163,7 @@ cost = 150 unit_name = "mech based tool" include_subtypes = TRUE - export_types = list(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp, /obj/item/mecha_parts/mecha_equipment/extinguisher, /obj/item/mecha_parts/mecha_equipment/rcd, /obj/item/mecha_parts/mecha_equipment/cable_layer, \ + export_types = list(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp, /obj/item/mecha_parts/mecha_equipment/extinguisher, /obj/item/mecha_parts/mecha_equipment/rcd, \ /obj/item/mecha_parts/mecha_equipment/drill, /obj/item/mecha_parts/mecha_equipment/mining_scanner, /obj/item/mecha_parts/mecha_equipment/medical/sleeper) /datum/export/robotics/mech_blue_space diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm index 5b131749b8..9c144ee6f3 100644 --- a/code/modules/clothing/suits/wiz_robe.dm +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -274,8 +274,8 @@ if(isliving(A)) //Gettem boys! L = A else if(ismecha(A)) - var/obj/mecha/M = A - L = M.occupant + var/obj/vehicle/sealed/mecha/M = A + L = pick(M.occupants) if(L && L.stat != DEAD && !HAS_TRAIT(L, TRAIT_DEATHCOMA)) //Taking revenge on the deads would be proposterous. addtimer(CALLBACK(src, .proc/clear_grudge, L), 2 MINUTES, TIMER_OVERRIDE|TIMER_UNIQUE) if(!book_of_grudges[L]) diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index a96a44a789..db42ad6798 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/item/projectile)) freeze_projectile(A) - else if(istype(A, /obj/mecha)) + else if(istype(A, /obj/vehicle/sealed/mecha)) freeze_mecha(A) else if((ismachinery(A) && !istype(A, /obj/machinery/light)) || isstructure(A)) //Special exception for light fixtures since recoloring causes them to change light freeze_structure(A) @@ -120,7 +120,7 @@ unfreeze_mob(A) else if(istype(A, /obj/item/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) @@ -131,10 +131,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 f38f326bc6..b7907f227b 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 91fab5f2ec..ad2daf86e2 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -41,7 +41,7 @@ return ..() /mob/living/brain/update_mobility() - return ((mobility_flags = (container?.in_contents_of(/obj/mecha)? MOBILITY_FLAGS_DEFAULT : NONE))) + return ((mobility_flags = (container?.in_contents_of(/obj/vehicle/sealed/mecha)? MOBILITY_FLAGS_DEFAULT : NONE))) /mob/living/brain/ex_act(severity, target, origin) //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up. return @@ -71,13 +71,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) @@ -98,7 +91,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 b7d9b0f61a..4ca45ceabd 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -43,10 +43,6 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) if(client && !suiciding && !(client in GLOB.dead_players_during_shift)) GLOB.dead_players_during_shift += client GLOB.deaths_during_shift++ - 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 71573abc90..9a3c9fff0c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -256,48 +256,6 @@ var/armor_block = run_armor_check(affecting, "melee") apply_damage(damage, BRUTE, affecting, armor_block, wound_bonus=wound_mod) -/mob/living/carbon/human/mech_melee_attack(obj/mecha/M) - if(M.occupant.a_intent == INTENT_HARM) - if(HAS_TRAIT(M.occupant, TRAIT_PACIFISM)) - to_chat(M.occupant, "You don't want to harm other living beings!") - return - 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) - var/atom/throw_target = get_edge_target_turf(src, M.dir) - switch(M.damtype) - if("brute") - if(M.force > 35) // durand and other heavy mechas - DefaultCombatKnockdown(50) - src.throw_at(throw_target, rand(1,5), 7) - else if(M.force >= 20 && CHECK_MOBILITY(src, MOBILITY_STAND)) // lightweight mechas like gygax - DefaultCombatKnockdown(30) - src.throw_at(throw_target, rand(1,3), 7) - 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] has hit [src]!", \ - "[M.name] has hit you!", null, COMBAT_MESSAGE_RANGE, target = M, - target_message = "You have hit [src]!") - 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(TRAIT_BOMBIMMUNE in dna.species.species_traits) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 5ce80c5575..b687986a40 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -149,39 +149,6 @@ playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) ..() - -/mob/living/mech_melee_attack(obj/mecha/M) - if(M.occupant.a_intent == INTENT_HARM) - if(HAS_TRAIT(M.occupant, TRAIT_PACIFISM)) - to_chat(M.occupant, "You don't want to harm other living beings!") - return - M.do_attack_animation(src) - if(M.damtype == "brute") - step_away(src,M,15) - switch(M.damtype) - if(BRUTE) - Unconscious(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] has hit [src]!", \ - "[M.name] has hit you!", null, COMBAT_MESSAGE_RANGE, null, - M.occupant, "You hit [src] with your [M.name]!") - 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, COMBAT_MESSAGE_RANGE, null, - M.occupant, "You push [src] out of the way with your [M.name].") - /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 b2b1d2fb5f..a822917aa4 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -39,7 +39,7 @@ var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list()) var/viewalerts = 0 var/icon/holo_icon//Female 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/pda/ai/aiPDA @@ -408,7 +408,7 @@ return if (href_list["ai_take_control"]) //Mech domination - var/obj/mecha/M = locate(href_list["ai_take_control"]) + var/obj/vehicle/sealed/mecha/M = locate(href_list["ai_take_control"]) if(controlled_mech) to_chat(src, "You are already loaded into an onboard computer!") return diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 2cbd1f35ca..f14f2edcd4 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -53,11 +53,11 @@ if(NONE) return FALSE if(POWER_REQ_ALL) - return !T || !A || ((!A.powered(EQUIP) || isspaceturf(T)) && !is_type_in_list(loc, list(/obj/item, /obj/mecha))) + return !T || !A || ((!A.powered(EQUIP) || isspaceturf(T)) && !is_type_in_list(loc, list(/obj/item, /obj/vehicle/sealed/mecha))) if(POWER_REQ_CLOCKCULT) for(var/obj/effect/clockwork/sigil/transmission/ST in range(src, SIGIL_ACCESS_RANGE)) return FALSE - return !T || !A || (!istype(T, /turf/open/floor/clockwork) && (!A.powered(EQUIP) || isspaceturf(T)) && !is_type_in_list(loc, list(/obj/item, /obj/mecha))) + return !T || !A || (!istype(T, /turf/open/floor/clockwork) && (!A.powered(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 029adbe92f..fcb5b34d0f 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -146,7 +146,7 @@ if(!search_objects) . = hearers(vision_range, targets_from) - src //Remove self, so we don't suicide - var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/destructible/clockwork/ocular_warden,/obj/item/electronic_assembly)) + var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha, /obj/structure/destructible/clockwork/ocular_warden,/obj/item/electronic_assembly)) for(var/HM in typecache_filter_list(range(vision_range, targets_from), hostile_machines)) if(can_see(targets_from, HM, vision_range)) @@ -236,9 +236,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)) @@ -604,7 +604,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, /obj/structure/destructible/clockwork/ocular_warden)) + var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha, /obj/structure/destructible/clockwork/ocular_warden)) . = 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 f2dc6abe40..e24962c8af 100644 --- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm +++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm @@ -25,14 +25,14 @@ search_objects = 0 mob_biotypes = 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 //Vars that control when the pilot uses their mecha's abilities (if the mecha has that ability) var/threat_use_mecha_smoke = 5 //5 mobs is enough to engage crowd control - var/defence_mode_chance = 35 //Chance to engage Defence mode when damaged + var/defense_mode_chance = 35 //Chance to engage Defense mode when damaged var/smoke_chance = 20 //Chance to deploy smoke for crowd control var/retreat_chance = 40 //Chance to run away @@ -42,18 +42,18 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/no_mech/Initialize() . = ..() - 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 = "Nanotrasen Mecha Pilot" + name = "\improper Nanotrasen Mecha Pilot" desc = "Death to the Syndicate. This variant comes in MECHA DEATH flavour." 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 = "Nanotrasen Mecha Pilot" + name = "\improper Nanotrasen Mecha Pilot" desc = "Death to the Syndicate. This variant comes in MECHA DEATH flavour." icon_living = "nanotrasen" icon_state = "nanotrasen" @@ -63,12 +63,12 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/Initialize() . = ..() 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) + INVOKE_ASYNC(src, .proc/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 target = null //Target was our mecha, so null it out @@ -78,7 +78,7 @@ var/do_ranged = 0 for(var/equip in mecha.equipment) var/obj/item/mecha_parts/mecha_equipment/ME = equip - if(ME.range & RANGED) + if(ME.range & MECHA_RANGED) do_ranged = 1 break if(do_ranged) @@ -89,11 +89,11 @@ ranged = 0 wanted_objects = list() search_objects = 0 - if(mecha && 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 = src //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 range(vision_range,src)) + for(var/obj/vehicle/sealed/mecha/combat/C in range(vision_range,src)) if(is_valid_mecha(C)) target = C search_aggressiveness = 3 //We can see a mech? RUN FOR IT, IGNORE MOBS! @@ -116,23 +116,23 @@ walk(M,0)//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) @@ -144,7 +144,7 @@ ME.rearm() -/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/get_mecha_equip_by_flag(flag = RANGED) +/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/get_mecha_equip_by_flag(flag = MECHA_RANGED) . = list() if(mecha) for(var/equip in mecha.equipment) @@ -160,11 +160,10 @@ if(mecha) mecha_reload() mecha_face_target(A) - var/list/possible_weapons = get_mecha_equip_by_flag(RANGED) + 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 @@ -173,20 +172,19 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/AttackingTarget() if(mecha) - var/list/possible_weapons = get_mecha_equip_by_flag(MELEE) + var/list/possible_weapons = get_mecha_equip_by_flag(MECHA_MELEE) 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,50 +197,54 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/handle_automated_action() - if(..()) - if(!mecha) - for(var/obj/mecha/combat/C in range(src,vision_range)) - if(is_valid_mecha(C)) - target = 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 range(src,vision_range)) + 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 + 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 - Defence Power or Retreat - if(mecha.obj_integrity < mecha.max_integrity*0.25) - if(prob(defence_mode_chance)) - if(mecha.defense_action && mecha.defense_action.owner && !mecha.defence_mode) - mecha.leg_overload_mode = 0 - mecha.defense_action.Activate(TRUE) - addtimer(CALLBACK(mecha.defense_action, /datum/action/innate/mecha/mech_defence_mode.proc/Activate, FALSE), 100) //10 seconds of defence, 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, /datum/action/innate/mecha/mech_defence_mode.proc/Activate, FALSE), 100) //10 seconds of speeeeed, then toggle off + else if(prob(retreat_chance)) + //Speed boost if possible + 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 - spawn(100) - retreat_distance = 0 + retreat_distance = 50 + addtimer(VARSET_CALLBACK(src, retreat_distance, 0), 10 SECONDS) @@ -261,17 +263,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 . = ..() @@ -290,6 +292,6 @@ /mob/living/simple_animal/hostile/syndicate/mecha_pilot/Goto(target, delay, minimum_distance) if(mecha) - walk_to(mecha, target, minimum_distance, mecha.step_in) + walk_to(mecha, target, minimum_distance, mecha.movedelay) else ..() 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 dc13d870c5..8ac3649604 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -195,7 +195,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) @@ -264,7 +264,7 @@ Difficulty: Medium 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 @@ -350,7 +350,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)) @@ -409,7 +409,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 @@ -538,7 +538,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 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 c1aea8db9d..ed9e4b9112 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -656,14 +656,16 @@ Difficulty: Normal if(monster_damage_boost && (ismegafauna(L) || istype(L, /mob/living/simple_animal/hostile/asteroid))) L.adjustBruteLoss(damage) 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, null, 50) + 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/hierophant name = "hierophant beacon" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm index 6bd55d06ae..463402f151 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm @@ -200,7 +200,7 @@ L.Stun(75) L.adjustBruteLoss(rand(15,20)) // Less stun more harm latched = TRUE - for(var/obj/mecha/M in loc) + for(var/obj/vehicle/sealed/mecha/M in loc) M.take_damage(20, BRUTE, null, null, null, 25) if(!latched) retract() 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 63a796a809..92eb310595 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 enemies -= 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(faction_check_mob(M) && attack_same || !faction_check_mob(M)) enemies |= M else if(ismecha(A)) - var/obj/mecha/M = A - if(M.occupant) + var/obj/vehicle/sealed/mecha/M = A + if(LAZYLEN(M.occupants)) enemies |= M - enemies |= M.occupant + enemies |= M.occupants for(var/mob/living/simple_animal/hostile/retaliate/H in around) if(faction_check_mob(H) && !attack_same && !H.attack_same) 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 800c7d29ca..1179a95135 100644 --- a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm +++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm @@ -99,7 +99,7 @@ if(!chosen_color) dragon_name() color_selection() - + /mob/living/simple_animal/hostile/space_dragon/Life() . = ..() @@ -158,8 +158,8 @@ adjustHealth(-L.maxHealth * 0.5) 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/AltClickOn(atom/A) @@ -322,7 +322,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/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 2a978bedb4..2df583ab47 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -394,8 +394,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 4b8fa75aee..950d0fc335 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -879,7 +879,7 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) 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 diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm index 4f287fc81b..48efa2452f 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -241,16 +241,18 @@ return drain_total -//MECH// -/obj/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + +/obj/vehicle/sealed/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) if(!ninja_suit || !ninja || !ninja_gloves) + return INVALID_DRAIN var/maxcapacity = FALSE //Safety check var/drain = 0 //Drain amount var/drain_total = 0 - occupant_message("Warning: Unauthorized access through sub-route 4, block H, detected.") + for(var/mob/living/MB in occupants) + to_chat(MB, "[icon2html(src, occupants)]Warning: Unauthorized access through sub-route 4, block H, detected.") if(get_charge()) while(ninja_gloves.candrain && cell.charge > 0 && !maxcapacity) drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) diff --git a/code/modules/projectiles/projectile/energy/tesla.dm b/code/modules/projectiles/projectile/energy/tesla.dm index 1afbdeae25..d88e217722 100644 --- a/code/modules/projectiles/projectile/energy/tesla.dm +++ b/code/modules/projectiles/projectile/energy/tesla.dm @@ -28,3 +28,7 @@ /obj/item/projectile/energy/tesla/cannon name = "tesla orb" power = 20000 + +/obj/item/projectile/energy/tesla/sphere + name = "tesla sphere" + power = 100000 diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm index b3737a8388..87fa7557da 100644 --- a/code/modules/projectiles/projectile/special/rocket.dm +++ b/code/modules/projectiles/projectile/special/rocket.dm @@ -23,7 +23,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 @@ -53,7 +53,7 @@ ricochets_max = 0 //it's a MISSILE var/sturdy = list( /turf/closed, - /obj/mecha, + /obj/vehicle/sealed/mecha, /obj/machinery/door/, /obj/machinery/door/poddoor/shutters ) diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 85b5cdac51..b9513a7a01 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -524,7 +524,7 @@ /obj/effect/CanEnterDisposals() return -/obj/mecha/CanEnterDisposals() +/obj/vehicle/sealed/mecha/CanEnterDisposals() return /obj/machinery/disposal/deliveryChute/newHolderDestination(obj/structure/disposalholder/H) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 4efcad97ba..12a18c7f91 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -585,15 +585,6 @@ construction_time = 100 category = list("Exosuit Equipment") -/datum/design/mech_cable_layer - name = "Exosuit Engineering Equipment (Cable Layer)" - id = "mech_cable_layer" - build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/cable_layer - materials = list(/datum/material/iron=10000) - construction_time = 100 - category = list("Exosuit Equipment") - /datum/design/mech_generator name = "Exosuit Equipment (Plasma Generator)" id = "mech_generator" diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index bfda6c453c..c4b7c8ffee 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -261,7 +261,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( matched_bounty = TRUE // ignore mech checks because the mech is ONLY for bounty continue - 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) if(ex.exported_atoms) diff --git a/code/modules/shuttle/white_ship.dm b/code/modules/shuttle/white_ship.dm index 66146edea1..4477489aaa 100644 --- a/code/modules/shuttle/white_ship.dm +++ b/code/modules/shuttle/white_ship.dm @@ -51,6 +51,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/uplink_support.dm b/code/modules/uplink/uplink_items/uplink_support.dm index efdfe1b06a..245074b2a5 100644 --- a/code/modules/uplink/uplink_items/uplink_support.dm +++ b/code/modules/uplink/uplink_items/uplink_support.dm @@ -58,13 +58,13 @@ 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 @@ -72,5 +72,5 @@ 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 diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm index d0144269b7..954b5940bc 100644 --- a/code/modules/vehicles/_vehicle.dm +++ b/code/modules/vehicles/_vehicle.dm @@ -7,6 +7,7 @@ armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 60) density = TRUE anchored = FALSE + COOLDOWN_DECLARE(cooldown_vehicle_move) var/list/mob/occupants //mob = bitflags of their control level. var/max_occupants = 1 var/max_drivers = 1 @@ -23,6 +24,7 @@ var/list/autogrant_actions_controller //assoc list "[bitflag]" = list(typepaths) var/list/mob/occupant_actions //assoc list mob = list(type = action datum assigned to mob) var/obj/vehicle/trailer + var/mouse_pointer //do we have a special mouse /obj/vehicle/Initialize(mapload) . = ..() @@ -121,9 +123,9 @@ vehicle_move(direction) /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/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm new file mode 100644 index 0000000000..ff901f2f01 --- /dev/null +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -0,0 +1,1217 @@ +/***************** 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' + resistance_flags = FIRE_PROOF | ACID_PROOF + flags_1 = HEAR_1 + max_integrity = 300 + armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) + movedelay = 1 SECONDS + anchored = TRUE + emulate_door_bumps = TRUE + COOLDOWN_DECLARE(mecha_bump_smash) + var/light_on = FALSE + ///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 + ///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 + ///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) + ///if we cant use our equipment(such as due to EMP) + var/equipment_disabled = FALSE + /// Keeps track of the mech's cell + var/obj/item/stock_parts/cell/cell + /// Keeps track of the mech's scanning module + var/obj/item/stock_parts/scanning_module/scanmod + /// Keeps track of the mech's capacitor + var/obj/item/stock_parts/capacitor/capacitor + ///Whether the mechs maintenance protocols are on or off + var/construction_state = MECHA_LOCKED + ///Contains flags for the mecha + var/mecha_flags = ADDING_ACCESS_POSSIBLE | CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS + ///Stores the DNA enzymes of a carbon so tht only they can access the mech + var/dna_lock + ///Spark effects are handled by this datum + var/datum/effect_system/spark_spread/spark_system = new + ///How powerful our lights are + var/lights_power = 6 + ///Just stop the mech from doing anything + var/completely_disabled = FALSE + ///Whether this mech is allowed to move diagonally + var/allow_diagonal_movement = TRUE + ///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 + ///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 + ///health percentage below which internal damage is possible + var/internal_damage_threshold = 50 + ///Bitflags for internal damage + var/internal_damage = NONE + + ///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_ENGINE, ACCESS_ROBOTICS) + + ///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 + ///Maximum amount of equipment we can have + var/max_equip = 3 + + ///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 + + ///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 + ///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 + ///Energy use modifier for leg overload + var/leg_overload_coeff = 100 + + //Bool for zoom on/off + var/zoom_mode = FALSE + + ///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 + ///icon_state for flick() when phazing + var/phase_state = "" + + ///Wether we are strafing + var/strafe = FALSE + + ///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/vehicle/sealed/mecha/Initialize() + . = ..() + add_radio() + add_cabin() + 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) + smoke_system.attach(src) + add_cell() + add_scanmod() + add_capacitor() + START_PROCESSING(SSobj, src) + GLOB.poi_list |= src + log_message("[src.name] created.", LOG_MECHA) + GLOB.mechas_list += src //global mech list + prepare_huds() + for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) + diag_hud.add_to_hud(src) + diag_hud_set_mechhealth() + diag_hud_set_mechcell() + diag_hud_set_mechstat() + update_icon() + +/obj/vehicle/sealed/mecha/Destroy() + if(obj_integrity > 0) //no explody if we have hp remaining! + explode_on_death = FALSE + for(var/M in occupants) + var/mob/living/occupant = M + if(isAI(occupant)) + occupant.gib() //No wreck, no AI to recover + else + 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_NULL(cell) + if(scanmod) + QDEL_NULL(scanmod) + if(capacitor) + QDEL_NULL(capacitor) + if(internal_tank) + QDEL_NULL(internal_tank) + STOP_PROCESSING(SSobj, src) + GLOB.poi_list.Remove(src) + LAZYCLEARLIST(equipment) + if(loc) + loc.assume_air(cabin_air) + air_update_turf() + else + qdel(cabin_air) + cabin_air = null + QDEL_NULL(spark_system) + QDEL_NULL(smoke_system) + + GLOB.mechas_list -= src //global mech list + return ..() + +/obj/vehicle/sealed/mecha/update_icon() + icon_state = get_mecha_occupancy_state() + return ..() + +//override this proc if you need to split up mecha control between multiple people (see savannah_ivanov.dm) +/obj/vehicle/sealed/mecha/auto_assign_occupant_flags(mob/M) + if(driver_amount() < max_drivers) + add_control_flags(M, FULL_MECHA_CONTROL) + +/obj/vehicle/sealed/mecha/proc/get_mecha_occupancy_state() + if((mecha_flags & SILICON_PILOT) && silicon_icon_state) + return silicon_icon_state + if(LAZYLEN(occupants)) + return initial(icon_state) + return "[initial(icon_state)]-open" + +/obj/vehicle/sealed/mecha/get_cell() + return cell + +/obj/vehicle/sealed/mecha/rust_heretic_act() + take_damage(500, BRUTE) + +/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/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/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 + else + normal_step_energy_drain = 500 + step_energy_drain = normal_step_energy_drain + if(capacitor) + armor = armor.modifyRating(energy = (capacitor.rating * 5)) //Each level of capacitor protects the mech against emp by 5% + else //because we can still be hit without a cap, even if we can't move + armor = armor.setRating(energy = 0) + + +//////////////////////// +////// Helpers ///////// +//////////////////////// + +/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/vehicle/sealed/mecha/proc/add_cell(obj/item/stock_parts/cell/C=null) + QDEL_NULL(cell) + if(C) + C.forceMove(src) + cell = C + return + 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/vehicle/sealed/mecha/proc/add_scanmod(obj/item/stock_parts/scanning_module/sm=null) + QDEL_NULL(scanmod) + if(sm) + sm.forceMove(src) + scanmod = sm + return + 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/vehicle/sealed/mecha/proc/add_capacitor(obj/item/stock_parts/capacitor/cap=null) + QDEL_NULL(capacitor) + if(cap) + cap.forceMove(src) + capacitor = cap + else + capacitor = new /obj/item/stock_parts/capacitor(src) + +/obj/vehicle/sealed/mecha/proc/add_cabin() + cabin_air = new(200) + cabin_air.set_temperature(T20C) + cabin_air.set_moles(GAS_O2,O2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature())) + cabin_air.set_moles(GAS_N2,N2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature())) + return cabin_air + +/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/vehicle/sealed/mecha/proc/can_use(mob/user) + if(istype(user) && is_occupant(user)) + if(!user.incapacitated()) + return TRUE + return FALSE + +//////////////////////////////////////////////////////////////////////////////// + +/obj/vehicle/sealed/mecha/examine(mob/user) + . = ..() + var/integrity = obj_integrity*100/max_integrity + switch(integrity) + if(85 to 100) + . += "It's fully intact." + if(65 to 85) + . += "It's slightly damaged." + if(45 to 65) + . += "It's badly damaged." + if(25 to 45) + . += "It's heavily damaged." + else + . += "It's falling apart." + var/hide_weapon = locate(/obj/item/mecha_parts/concealed_weapon_bay) in contents + var/hidden_weapon = hide_weapon ? (locate(/obj/item/mecha_parts/mecha_equipment/weapon) in equipment) : null + var/list/visible_equipment = equipment - hidden_weapon + if(visible_equipment.len) + . += "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 + +//processing internal damage, temperature, air regulation, alert updates, lights power use. +/obj/vehicle/sealed/mecha/process() + var/internal_temp_regulation = 1 + + if(internal_damage) + if(internal_damage & MECHA_INT_FIRE) + if(!(internal_damage & MECHA_INT_TEMP_CONTROL) && prob(5)) + clearInternalDamage(MECHA_INT_FIRE) + if(internal_tank) + var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + if(int_tank_air.return_pressure() > internal_tank.maximum_pressure && !(internal_damage & MECHA_INT_TANK_BREACH)) + setInternalDamage(MECHA_INT_TANK_BREACH) + if(int_tank_air && int_tank_air.return_volume() > 0) //heat the air_contents + int_tank_air.set_temperature(min(6000+T0C, int_tank_air.return_temperature()+rand(10,15))) + if(cabin_air && cabin_air.return_volume()>0) + cabin_air.set_temperature(min(6000+T0C, cabin_air.return_temperature()+rand(10,15))) + if(cabin_air.return_temperature() > max_temperature/2) + take_damage(4/round(max_temperature/cabin_air.return_temperature(),0.1), BURN, 0, 0) + + if(internal_damage & MECHA_INT_TEMP_CONTROL) + internal_temp_regulation = 0 + + if(internal_damage & MECHA_INT_TANK_BREACH) //remove some air from internal tank + if(internal_tank) + assume_air_ratio(internal_tank.return_air(), 0.1) + + if(internal_damage & MECHA_INT_SHORT_CIRCUIT) + if(get_charge()) + spark_system.start() + cell.charge -= min(20,cell.charge) + cell.maxcharge -= min(20,cell.maxcharge) + + if(internal_temp_regulation) + if(cabin_air && cabin_air.return_volume() > 0) + var/delta = cabin_air.return_temperature() - T20C + cabin_air.set_temperature(cabin_air.return_temperature() - max(-10, min(10, round(delta/4,0.1)))) + + if(internal_tank) + var/datum/gas_mixture/tank_air = internal_tank.return_air() + + var/release_pressure = internal_tank_valve + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.return_temperature() > 0) + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + tank_air.transfer_to(cabin_air,transfer_moles) + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = return_air() + pressure_delta = cabin_pressure - release_pressure + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + 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(occupants) + for(var/i in occupants) + var/mob/living/occupant = i + if(cell) + var/cellcharge = cell.charge/cell.maxcharge + 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.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) + + 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_try_exit(occupant, TRUE, TRUE) //bye bye + +//Diagnostic HUD updates + diag_hud_set_mechhealth() + diag_hud_set_mechcell() + diag_hud_set_mechstat() + +/obj/vehicle/sealed/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech + . = ..() + 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 in speech_bubble_recipients) + if(M.client) + speech_bubble_recipients.Add(M.client) + INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, image('icons/mob/talk.dmi', src, "machine[say_test(speech_args[SPEECH_MESSAGE])]",MOB_LAYER+1), speech_bubble_recipients, 30) + +//////////////////////////// +///// Action processing //// +//////////////////////////// + +/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 || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT)) + return + var/list/mouse_control = params2list(params) + if(isAI(user) && !mouse_control["middle"])//AIs use MMB + return + if(phasing) + to_chat(occupants, "[icon2html(src, occupants)]Unable to interact with objects while phasing.") + return + if(user.incapacitated()) + return + if(construction_state) + to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect.") + return + if(!get_charge()) + return + if(src == target) + return + var/dir_to_target = get_dir(src,target) + if(dir_to_target && !(dir_to_target & dir))//wrong direction + return + if(internal_damage & MECHA_INT_CONTROL_LOST) + target = pick(view(3,target)) + if(!target) + return + var/mob/living/L = user + if(selected) + if(!(L in return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT))) + to_chat(user, "You can't control mech equipment from here!") + return + if(!Adjacent(target) && (selected.range & MECHA_RANGED)) + if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful) + to_chat(L, "You don't want to harm other living beings!") + return + if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, L, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK) + return + 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 + if(SEND_SIGNAL(src, COMSIG_MECHA_EQUIPMENT_CLICK, L, target) & COMPONENT_CANCEL_EQUIPMENT_CLICK) + return + INVOKE_ASYNC(selected, /obj/item/mecha_parts/mecha_equipment.proc/action, user, target, params) + return + if(!(L in return_controllers_with_flag(VEHICLE_CONTROL_MELEE))) + to_chat(L, "You're in the wrong seat to interact with your hands.") + return + var/on_cooldown = TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK) + var/adjacent = Adjacent(target) + if(SEND_SIGNAL(src, COMSIG_MECHA_MELEE_CLICK, L, target, on_cooldown, adjacent) & COMPONENT_CANCEL_MELEE_CLICK) + return + if(on_cooldown || !adjacent) + 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 //////// +////////////////////////////////// + +///Plays the mech step sound effect. Split from movement procs so that other mechs (HONK) can override this one specific part. +/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/vehicle/sealed/mecha/Process_Spacemove(movement_dir = 0) + . = ..() + if(.) + return TRUE + + var/atom/movable/backup = get_spacemove_backup() + if(backup) + if(istype(backup) && movement_dir && !backup.anchored) + if(backup.newtonian_move(turn(movement_dir, 180))) + step_silent = TRUE + if(return_drivers()) + to_chat(occupants, "[icon2html(src, occupants)]The [src] push off [backup] to propel yourself.") + return TRUE + + if(movedelay <= world.time && active_thrusters && movement_dir && active_thrusters.thrust(movement_dir)) + step_silent = TRUE + return TRUE + + return FALSE + +/obj/vehicle/sealed/mecha/relaymove(mob/living/user, direction) + . = TRUE + if(!canmove || !(user in return_drivers())) + return + vehicle_move(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 FALSE + if(!direction) + return FALSE + if(internal_tank?.connected_port) + 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)) + to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect.") + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) + 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!") + return FALSE + if(!cell) + to_chat(occupants, "[icon2html(src, occupants)]Missing power cell.") + return FALSE + if(!scanmod || !capacitor) + 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 + + if(internal_damage & MECHA_INT_CONTROL_LOST) + direction = pick(GLOB.alldirs) + + //only mechs with diagonal movement may move diagonally + if(!allow_diagonal_movement && ISDIAGONALDIR(direction)) + return TRUE + + //if we're not facing the way we're going rotate us + var/no_strafe = FALSE + if(dir != direction || forcerotate) + if(strafe) + for(var/D in return_drivers()) + var/mob/driver = D + if(driver.client?.keys_held["Alt"]) + no_strafe = TRUE + setDir(direction) + if(turnsound) + playsound(src,turnsound,40,TRUE) + return TRUE + else + 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 && !no_strafe) + setDir(olddir) + + +/obj/vehicle/sealed/mecha/Bump(atom/obstacle) + if(phasing && get_charge() >= phasing_energy_drain && !throwing) + if(phase_state) + flick(phase_state, src) + forceMove(get_step(src,dir))//This is jank I hate it thanks, this should be done thrugh move not this dumb shit + use_power(phasing_energy_drain) + addtimer(VARSET_CALLBACK(src, movedelay, TRUE), movedelay*3) + 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_step(src,dir))) + step(src,dir) + if(isobj(obstacle)) + var/obj/obj_obstacle = obstacle + if(!obj_obstacle.anchored && obj_obstacle.move_resist <= move_force) + step(obstacle, dir) + else if(ismob(obstacle)) + var/mob/mob_obstacle = obstacle + if(mob_obstacle.move_resist <= move_force) + step(obstacle, dir) + + + + + +/////////////////////////////////// +//////// Internal damage //////// +/////////////////////////////////// + +/obj/vehicle/sealed/mecha/proc/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null) + if(!islist(possible_int_damage) || !length(possible_int_damage)) + return + if(prob(20)) + if(ignore_threshold || obj_integrity*100/max_integrity < internal_damage_threshold) + for(var/T in possible_int_damage) + if(internal_damage & T) + possible_int_damage -= T + if (length(possible_int_damage)) + var/int_dam_flag = pick(possible_int_damage) + if(int_dam_flag) + setInternalDamage(int_dam_flag) + if(prob(5)) + if(ignore_threshold || obj_integrity*100/max_integrity < internal_damage_threshold) + if(LAZYLEN(equipment)) + var/obj/item/mecha_parts/mecha_equipment/ME = pick(equipment) + qdel(ME) + +/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(occupants, sound('sound/machines/warning-buzzer.ogg',wait=0)) + diag_hud_set_mechstat() + +/obj/vehicle/sealed/mecha/proc/clearInternalDamage(int_dam_flag) + if(internal_damage & int_dam_flag) + switch(int_dam_flag) + if(MECHA_INT_TEMP_CONTROL) + to_chat(occupants, "[icon2html(src, occupants)]Life support system reactivated.") + if(MECHA_INT_FIRE) + to_chat(occupants, "[icon2html(src, occupants)]Internal fire extinguished.") + if(MECHA_INT_TANK_BREACH) + to_chat(occupants, "[icon2html(src, occupants)]Damaged internal tank has been sealed.") + internal_damage &= ~int_dam_flag + diag_hud_set_mechstat() + +///////////////////////////////////// +//////////// AI piloting //////////// +///////////////////////////////////// + +/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. + if(user.can_dominate_mechs) + examine(user) //Get diagnostic information! + for(var/obj/item/mecha_parts/mecha_tracking/B in trackers) + to_chat(user, "Warning: Tracking Beacon detected. Enter at your own risk. Beacon Data:") + to_chat(user, "[B.get_mecha_info()]") + break + //Nothing like a big, red link to make the player feel powerful! + to_chat(user, "ASSUME DIRECT CONTROL?
") + else + examine(user) + if(length(return_drivers()) > 0) + to_chat(user, "This exosuit has a pilot and cannot be controlled.") + return + var/can_control_mech = 0 + for(var/obj/item/mecha_parts/mecha_tracking/ai_control/A in trackers) + can_control_mech = 1 + to_chat(user, "[icon2html(src, user)] Status of [name]:\n[A.get_mecha_info()]") + break + if(!can_control_mech) + to_chat(user, "You cannot control exosuits without AI control beacons installed.") + return + 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(!..()) + return + + //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 + 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() + remove_occupant(AI) + mecha_flags &= ~SILICON_PILOT + AI.forceMove(card) + card.AI = AI + AI.controlled_mech = null + 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.") + + 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_TRANS_FROM_CARD) //Using an AI card to upload to a mech. + AI = card.AI + if(!AI) + to_chat(user, "There is no AI currently installed on this device.") + return + if(AI.deployed_shell) //Recall AI if shelled so it can be checked for a client + AI.disconnect_shell() + if(AI.stat || !AI.client) + to_chat(user, "[AI.name] is currently unresponsive, and cannot be uploaded.") + return + if((LAZYLEN(occupants) >= max_occupants) || dna_lock) //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 + 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) + +//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) + AI.ai_restore_power() + 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. + 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.") + + +///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(LAZYLEN(occupants)) + return + LAZYADD(occupants, src) + pilot_mob.mecha = src + pilot_mob.forceMove(src) + update_icon() + +///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 + pilot_mob.forceMove(get_turf(src)) + update_icon() + + +///////////////////////////////////// +//////// Atmospheric stuff //////// +///////////////////////////////////// + +/obj/vehicle/sealed/mecha/remove_air(amount) + if(use_internal_tank) + return cabin_air.remove(amount) + return ..() + +/obj/vehicle/sealed/mecha/remove_air_ratio(ratio) + if(use_internal_tank) + return cabin_air.remove_ratio(ratio) + return ..() + + +/obj/vehicle/sealed/mecha/return_air() + if(use_internal_tank) + return cabin_air + return ..() + + +/obj/vehicle/sealed/mecha/proc/return_pressure() + var/datum/gas_mixture/t_air = return_air() + if(t_air) + . = t_air.return_pressure() + return + +/obj/vehicle/sealed/mecha/return_temperature() + var/datum/gas_mixture/t_air = return_air() + if(t_air) + . = t_air.return_temperature() + return + +/obj/vehicle/sealed/mecha/mob_try_enter(mob/M) + if(!ishuman(M)) // no silicons or drones in mechas. + return + log_message("[M] tries to move into [src].", LOG_MECHA) + if(dna_lock && M.has_dna()) + var/mob/living/carbon/entering_carbon = M + if(entering_carbon.dna.unique_enzymes != dna_lock) + to_chat(M, "Access denied. [name] is secured with a DNA lock.") + log_message("Permission denied (DNA LOCK).", LOG_MECHA) + return + if(!operation_allowed(M)) + to_chat(M, "Access denied. Insufficient operation keycodes.") + log_message("Permission denied (No keycode).", LOG_MECHA) + return + if(M.buckled) + to_chat(M, "You are currently buckled and cannot move.") + log_message("Permission denied (Buckled).", LOG_MECHA) + return + 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("[M] starts to climb into [name].") + + if(do_after(M, enter_delay, target = src)) + if(obj_integrity <= 0) + 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(M) + return ..() + else + to_chat(M, "You stop entering the exosuit!") + + +/obj/vehicle/sealed/mecha/generate_actions() + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip, VEHICLE_CONTROL_EQUIPMENT) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/strafe, VEHICLE_CONTROL_DRIVE) + +/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/vehicle/sealed/mecha/proc/mmi_move_inside(obj/item/mmi/M, mob/user) + if(!M.brainmob || !M.brainmob.client) + to_chat(user, "Consciousness matrix not detected!") + return FALSE + else if(M.brainmob.stat) + to_chat(user, "Beta-rhythm below acceptable level!") + return FALSE + var/mob/living/brain/B = M.brainmob + if(LAZYLEN(occupants) >= max_occupants) + to_chat(user, "It's full!") + return FALSE + if(dna_lock && (!B.stored_dna || (dna_lock != B.stored_dna.unique_enzymes))) + to_chat(user, "Access denied. [name] is secured with a DNA lock.") + return FALSE + + visible_message("[user] starts to insert an MMI into [name].") + + if(do_after(user, 40, target = src)) + if(LAZYLEN(occupants) < max_occupants) + return mmi_moved_inside(M, user) + else + to_chat(user, "Maximum occupants detected!") + else + 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))) + return FALSE + if(!M.brainmob || !M.brainmob.client) + to_chat(user, "Consciousness matrix not detected!") + return FALSE + else if(M.brainmob.stat) + to_chat(user, "Beta-rhythm below acceptable level!") + + 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 + + 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 + B.update_mobility() + B.update_mouse_pointer() + update_icon() + setDir(dir_in) + log_message("[M] 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)]") + return TRUE + +/obj/vehicle/sealed/mecha/container_resist(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 + if(do_after(user, exit_delay , target = src)) + to_chat(user, "You exit the mech.") + mob_try_exit(user, silent = FALSE) + else + to_chat(user, "You stop exiting the mech. Weapons are enabled again.") + is_currently_ejecting = FALSE + +/obj/vehicle/sealed/mecha/proc/ejectall() + for(var/ejectee in occupants) + mob_try_exit(ejectee, TRUE, TRUE) + +/obj/vehicle/sealed/mecha/mob_try_exit(mob/M, silent, randomstep) + mob_exit(M, silent, randomstep) + +/obj/vehicle/sealed/mecha/mob_exit(mob/M, silent, forced) + var/newloc = get_turf(src) + var/atom/movable/mob_container + if(ishuman(M)) + remove_occupant(M) + ..() + return + else if(isbrain(M)) + var/mob/living/brain/brain = M + mob_container = brain.container + 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. + 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) + to_chat(AI, "Inactive core destroyed. Unable to return.") + AI.linked_core = null + return + to_chat(AI, "Returning to core...") + AI.controlled_mech = null + AI.remote_control = null + mob_container = AI + newloc = get_turf(AI.linked_core) + qdel(AI.linked_core) + else + return ..() + var/mob/living/L = M + mecha_flags &= ~SILICON_PILOT + if(mob_container.forceMove(newloc)) + log_message("[mob_container] moved out.", LOG_MECHA) + L << browse(null, "window=exosuit") + if(istype(mob_container, /obj/item/mmi)) + var/obj/item/mmi/mmi = mob_container + if(mmi.brainmob) + L.forceMove(mmi) + L.reset_perspective() + remove_occupant(L) + mmi.mecha = null + mmi.update_icon() + L.mobility_flags = NONE + update_icon() + setDir(dir_in) + return ..() + + +/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/vehicle/sealed/mecha/proc/operation_allowed(mob/M) + req_access = operation_req_access + req_one_access = list() + return allowed(M) + +/obj/vehicle/sealed/mecha/proc/internals_access_allowed(mob/M) + req_one_access = internals_req_access + req_access = list() + return allowed(M) + + +/////////////////////// +///// Power stuff ///// +/////////////////////// + +/obj/vehicle/sealed/mecha/proc/has_charge(amount) + return (get_charge()>=amount) + +/obj/vehicle/sealed/mecha/proc/get_charge() + for(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/R in equipment) + var/relay_charge = R.get_charge() + if(relay_charge) + return relay_charge + if(cell) + return max(0, cell.charge) + +/obj/vehicle/sealed/mecha/proc/use_power(amount) + if(get_charge() && cell.use(amount)) + return TRUE + return FALSE + +/obj/vehicle/sealed/mecha/proc/give_power(amount) + if(!isnull(get_charge())) + cell.give(amount) + return TRUE + return FALSE + +/////////////////////// +////// Ammo stuff ///// +/////////////////////// + +/obj/vehicle/sealed/mecha/proc/ammo_resupply(obj/item/mecha_ammo/A, mob/user,fail_chat_override = FALSE) + if(!A.rounds) + if(!fail_chat_override) + to_chat(user, "This box of ammo is empty!") + return FALSE + var/ammo_needed + var/found_gun + for(var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun in equipment) + ammo_needed = 0 + + if(istype(gun, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic) && gun.ammo_type == A.ammo_type) + found_gun = TRUE + if(A.direct_load) + ammo_needed = initial(gun.projectiles) - gun.projectiles + else + ammo_needed = gun.projectiles_cache_max - gun.projectiles_cache + + if(ammo_needed) + if(ammo_needed < A.rounds) + if(A.direct_load) + gun.projectiles = gun.projectiles + ammo_needed + else + gun.projectiles_cache = gun.projectiles_cache + ammo_needed + playsound(get_turf(user),A.load_audio,50,TRUE) + to_chat(user, "You add [ammo_needed] [A.round_term][ammo_needed > 1?"s":""] to the [gun.name]") + A.rounds = A.rounds - ammo_needed + A.update_name() + return TRUE + + else + if(A.direct_load) + gun.projectiles = gun.projectiles + A.rounds + else + gun.projectiles_cache = gun.projectiles_cache + A.rounds + playsound(get_turf(user),A.load_audio,50,TRUE) + to_chat(user, "You add [A.rounds] [A.round_term][A.rounds > 1?"s":""] to the [gun.name]") + A.rounds = 0 + A.update_name() + return TRUE + if(!fail_chat_override) + if(found_gun) + to_chat(user, "You can't fit any more ammo of this type!") + else + to_chat(user, "None of the equipment on this exosuit can use this ammo!") + return FALSE diff --git a/code/modules/vehicles/mecha/combat/combat.dm b/code/modules/vehicles/mecha/combat/combat.dm new file mode 100644 index 0000000000..ccfd92ecbc --- /dev/null +++ b/code/modules/vehicles/mecha/combat/combat.dm @@ -0,0 +1,23 @@ +/obj/vehicle/sealed/mecha/combat + force = 30 + internals_req_access = list(ACCESS_ROBOTICS, ACCESS_SECURITY) + internal_damage_threshold = 50 + armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 20, BOMB = 20, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) + mouse_pointer = 'icons/mecha/mecha_mouse.dmi' + destruction_sleep_duration = 40 + exit_delay = 40 + +/obj/vehicle/sealed/mecha/combat/restore_equipment() + mouse_pointer = 'icons/mecha/mecha_mouse.dmi' + . = ..() + +/obj/vehicle/sealed/mecha/combat/moved_inside(mob/living/carbon/human/H) + ..() + update_icon() + + +/obj/vehicle/sealed/mecha/combat/proc/max_ammo() //Max the ammo stored for Nuke Ops mechs, or anyone else that calls this + for(var/obj/item/I in equipment) + if(istype(I, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/)) + var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun = I + gun.projectiles_cache = gun.projectiles_cache_max diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm new file mode 100644 index 0000000000..70edd9df89 --- /dev/null +++ b/code/modules/vehicles/mecha/combat/durand.dm @@ -0,0 +1,241 @@ +/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" + 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) + max_temperature = 30000 + force = 40 + wreckage = /obj/structure/mecha_wreckage/durand + var/obj/durand_shield/shield + + +/obj/vehicle/sealed/mecha/combat/durand/Initialize() + . = ..() + shield = new /obj/durand_shield(loc, src, layer, dir) + RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, .proc/relay) + RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, .proc/prehit) + + +/obj/vehicle/sealed/mecha/combat/durand/Destroy() + if(shield) + QDEL_NULL(shield) + return ..() + + +/obj/vehicle/sealed/mecha/combat/durand/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_defense_mode) + +/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) + INVOKE_ASYNC(action, /datum/action.proc/Trigger) + break + +/obj/vehicle/sealed/mecha/combat/durand/Move(direction) + . = ..() + if(shield) + shield.forceMove(loc) + shield.setDir(dir) + +/obj/vehicle/sealed/mecha/combat/durand/forceMove(turf/T) + . = ..() + shield.forceMove(T) + +/obj/vehicle/sealed/mecha/combat/durand/mob_exit(mob/M, silent, randomstep, forced) + 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) + return ..() + +///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA. +/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_TRIGGER, owner, signal_args) + +//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true. +/obj/vehicle/sealed/mecha/combat/durand/proc/prehit(obj/item/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/vehicle/sealed/mecha/combat/durand/proc/defense_check(turf/aloc) + if (!defense_mode || !shield || shield.switching) + return FALSE + . = FALSE + switch(dir) + if (1) + if(abs(x - aloc.x) <= (y - aloc.y) * -2) + . = TRUE + if (2) + if(abs(x - aloc.x) <= (y - aloc.y) * 2) + . = TRUE + if (4) + if(abs(y - aloc.y) <= (x - aloc.x) * -2) + . = TRUE + if (8) + if(abs(y - aloc.y) <= (x - aloc.x) * 2) + . = TRUE + return + +/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/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") + shield.blob_act(B) + else + . = ..() + +/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/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) + else + . = ..() + +//////////////////////////// +///// Shield processing //// +//////////////////////////// + +/**An object to take the hit for us when using the Durand's defense mode. +It is spawned in during the durand's initilization, and always stays on the same tile. +Normally invisible, until defense mode is actvated. When the durand detects an attack that should be blocked, the +attack is passed to the shield. The shield takes the damage, uses it to calculate charge cost, and then sets its +own integrity back to max. Shield is automatically dropped if we run out of power or the user gets out.*/ + +/obj/durand_shield //projectiles get passed to this when defense mode is enabled + name = "defense grid" + icon = 'icons/mecha/durand_shield.dmi' + icon_state = "shield_null" + invisibility = INVISIBILITY_MAXIMUM //no showing on right-click + pixel_y = 4 + max_integrity = 10000 + obj_integrity = 10000 + anchored = TRUE + light_range = MINIMUM_USEFUL_LIGHT_RANGE + light_power = 5 + light_color = COLOR_CYAN + ///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) + . = ..() + chassis = _chassis + layer = _layer + setDir(_dir) + RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, .proc/activate) + + +/obj/durand_shield/Destroy() + if(chassis) + chassis.shield = null + 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) + * 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 + 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 + to_chat(currentuser, "[icon2html(src, currentuser)]Insufficient power; cannot activate defense mode.") + return + switching = TRUE + chassis.defense_mode = !chassis.defense_mode + if(!signal_args[1]) + to_chat(currentuser, "[icon2html(src, currentuser)]Defense mode [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) + 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(light_range, light_power, light_color) + + if(chassis.defense_mode) + 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) + return + if(!chassis.defense_mode) //if defense mode is disabled, we're taking damage that we shouldn't be taking + return + . = ..() + flick("shield_impact", src) + if(!chassis.use_power((max_integrity - obj_integrity) * 100)) + chassis.cell?.charge = 0 + 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() + playsound(src, 'sound/mecha/mech_shield_deflect.ogg', 100, TRUE) + +/obj/durand_shield/bullet_act() + play_attack_sound() + . = ..() diff --git a/code/game/mecha/combat/five_stars.dm b/code/modules/vehicles/mecha/combat/five_stars.dm similarity index 88% rename from code/game/mecha/combat/five_stars.dm rename to code/modules/vehicles/mecha/combat/five_stars.dm index 250ec7f3f6..3c14e9ad81 100644 --- a/code/game/mecha/combat/five_stars.dm +++ b/code/modules/vehicles/mecha/combat/five_stars.dm @@ -1,4 +1,4 @@ -/obj/mecha/combat/five_stars +/obj/vehicle/sealed/mecha/combat/five_stars desc = "A state of the art tank deployed by the Spinward Stellar Coalition National Guard." name = "\improper Tank" icon = 'icons/mecha/mecha_96x96.dmi' @@ -10,7 +10,7 @@ pixel_x = -32 pixel_y = -32 -/obj/mecha/combat/five_stars/Initialize() +/obj/vehicle/sealed/mecha/combat/five_stars/Initialize() . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/spacecops(src) ME.attach(src) diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm new file mode 100644 index 0000000000..a90b776374 --- /dev/null +++ b/code/modules/vehicles/mecha/combat/gygax.dm @@ -0,0 +1,59 @@ +/obj/vehicle/sealed/mecha/combat/gygax + desc = "A lightweight, security exosuit. Popular among private and corporate security." + name = "\improper Gygax" + icon_state = "gygax" + 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) + max_temperature = 25000 + leg_overload_coeff = 80 + force = 25 + wreckage = /obj/structure/mecha_wreckage/gygax + internal_damage_threshold = 35 + max_equip = 3 + step_energy_drain = 3 + +/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" + max_integrity = 300 + deflect_chance = 20 + armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 35, BOMB = 20, BIO = 0, RAD =20, FIRE = 100, ACID = 100) + max_temperature = 35000 + leg_overload_coeff = 70 + force = 30 + operation_req_access = list(ACCESS_SYNDICATE) + internals_req_access = list(ACCESS_SYNDICATE) + wreckage = /obj/structure/mecha_wreckage/gygax/dark + max_equip = 5 + destruction_sleep_duration = 20 + +/obj/vehicle/sealed/mecha/combat/gygax/dark/loaded/Initialize() + . = ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay + ME.attach(src) + max_ammo() + +/obj/vehicle/sealed/mecha/combat/gygax/dark/add_cell(obj/item/stock_parts/cell/C=null) + if(C) + C.forceMove(src) + cell = C + return + cell = new /obj/item/stock_parts/cell/bluespace(src) + + +/obj/vehicle/sealed/mecha/combat/gygax/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_overload_mode) diff --git a/code/game/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm similarity index 63% rename from code/game/mecha/combat/honker.dm rename to code/modules/vehicles/mecha/combat/honker.dm index 89b641ccc6..7373469614 100644 --- a/code/game/mecha/combat/honker.dm +++ b/code/modules/vehicles/mecha/combat/honker.dm @@ -1,22 +1,21 @@ -/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" - 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) + armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) max_temperature = 25000 - infra_luminosity = 5 operation_req_access = list(ACCESS_THEATRE) - internals_req_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS) + internals_req_access = list(ACCESS_ROBOTICS, 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 + var/squeak = TRUE -/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() @@ -29,18 +28,18 @@ [internal_damage&MECHA_INT_TANK_BREACH?"GAS TANK HONK
":null] [internal_damage&MECHA_INT_CONTROL_LOST?"HONK-A-DOODLE - Recalibrate
":null] IntegriHONK: [integrity]%
- PowerHONK charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
+ PowerHONK charge: [isnull(cell_charge)?"No power cell installed":"[cell.percent()]%"]
Air source: [use_internal_tank?"Internal Airtank":"Environment"]
AirHONK pressure: [tank_pressure]kPa
AirHONK temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
HONK pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
HONK temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
- Lights: [lights?"on":"off"]
+ Lights: [(mecha_flags & LIGHTS_ON)?"on":"off"]
[dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":null] "} return output -/obj/mecha/combat/honker/get_stats_html() +/obj/vehicle/sealed/mecha/combat/honker/get_stats_html(mob/user) var/output = {" @@ -60,19 +59,19 @@ [js_byjax] [js_dropdowns] function SSticker() { - setInterval(function(){ - window.location='byond://?src=[REF(src)]&update_content=1'; - document.body.style.color = get_rand_color_string(); - document.body.style.background = get_rand_color_string(); - }, 1000); + setInterval(function(){ + window.location='byond://?src=[REF(src)]&update_content=1'; + document.body.style.color = get_rand_color_string(); + document.body.style.background = get_rand_color_string(); + }, 1000); } function get_rand_color_string() { - var color = new Array; - for(var i=0;i<3;i++){ - color.push(Math.floor(Math.random()*255)); - } - return "rgb("+color.toString()+")"; + var color = new Array; + for(var i=0;i<3;i++){ + color.push(Math.floor(Math.random()*255)); + } + return "rgb("+color.toString()+")"; } window.onload = function() { @@ -83,7 +82,7 @@
- [src.get_stats_part()] + [src.get_stats_part(user)]
[src.get_equipment_list()] @@ -97,7 +96,7 @@ "} return output -/obj/mecha/combat/honker/get_commands() +/obj/vehicle/sealed/mecha/combat/honker/get_commands() var/output = {" "} @@ -113,8 +120,8 @@ return output -/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) @@ -122,19 +129,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"]) @@ -148,11 +148,20 @@ playsound(src, 'sound/items/carhorn.ogg', 80) //soundfile has lower than average volume if("party_horn") playsound(src, 'sound/items/party_horn.ogg', 50) + if("reee") + playsound(src, 'sound/effects/reee.ogg', 50) + if("weeoo1") + playsound(src, 'sound/items/weeoo1.ogg', 50) + if("hiss1") + playsound(src, 'sound/voice/hiss1.ogg', 50) + if("armbomb") + playsound(src, 'sound/weapons/armbomb.ogg', 50) + if("saberon") + playsound(src, 'sound/weapons/saberon.ogg', 50) + if("airlock_alien_prying") + playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50) + if("lightningbolt") + playsound(src, 'sound/magic/lightningbolt.ogg', 50) + if("explosionfar") + playsound(src, 'sound/effects/explosionfar.ogg', 50) 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/game/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm similarity index 61% rename from code/game/mecha/combat/marauder.dm rename to code/modules/vehicles/mecha/combat/marauder.dm index 5c60a97864..d595509d2e 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/modules/vehicles/mecha/combat/marauder.dm @@ -1,38 +1,32 @@ -/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" - 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" = 0, "fire" = 100, "acid" = 100) + armor = list(MELEE = 50, BULLET = 55, LASER = 40, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 60, FIRE = 100, ACID = 100) 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, ACCESS_ROBOTICS) + 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 = 4 - bumpsmash = 1 + max_equip = 5 + bumpsmash = TRUE -/obj/mecha/combat/marauder/GrantActions(mob/living/user, human_occupant = 0) - ..() - smoke_action.Grant(user, src) - thrusters_action.Grant(user, src) - zoom_action.Grant(user, src) - -/obj/mecha/combat/marauder/RemoveActions(mob/living/user, human_occupant = 0) - ..() - smoke_action.Remove(user) - thrusters_action.Remove(user) - zoom_action.Remove(user) - -/obj/mecha/combat/marauder/loaded/Initialize() +/obj/vehicle/sealed/mecha/combat/marauder/generate_actions() . = ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_smoke) + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_zoom) + +/obj/vehicle/sealed/mecha/combat/marauder/loaded/Initialize() + . = ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src) ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src) ME.attach(src) @@ -42,23 +36,24 @@ ME.attach(src) max_ammo() -/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" operation_req_access = list(ACCESS_CENT_SPECOPS) - internals_req_access = list(ACCESS_CENT_SPECOPS, ACCESS_ROBOTICS) - step_in = 3 + internals_req_access = list(ACCESS_CENT_SPECOPS) + movedelay = 3 max_integrity = 550 wreckage = /obj/structure/mecha_wreckage/seraph internal_damage_threshold = 20 force = 55 - max_equip = 5 + max_equip = 6 -/obj/mecha/combat/marauder/seraph/Initialize() +/obj/vehicle/sealed/mecha/combat/marauder/seraph/Initialize() . = ..() - var/obj/item/mecha_parts/mecha_equipment/ME - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src) + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src) ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src) ME.attach(src) @@ -70,16 +65,22 @@ ME.attach(src) max_ammo() -/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" operation_req_access = list(ACCESS_SYNDICATE) internals_req_access = list(ACCESS_SYNDICATE) wreckage = /obj/structure/mecha_wreckage/mauler - max_equip = 5 + max_equip = 6 + destruction_sleep_duration = 20 -/obj/mecha/combat/marauder/mauler/loaded/Initialize() +/obj/vehicle/sealed/mecha/combat/marauder/mauler/Initialize() + . = ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src) + ME.attach(src) + +/obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded/Initialize() . = ..() 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/game/mecha/medical/medigax.dm b/code/modules/vehicles/mecha/combat/medigax.dm similarity index 54% rename from code/game/mecha/medical/medigax.dm rename to code/modules/vehicles/mecha/combat/medigax.dm index 98b7c9455b..6b2f54a976 100644 --- a/code/game/mecha/medical/medigax.dm +++ b/code/modules/vehicles/mecha/combat/medigax.dm @@ -1,34 +1,36 @@ -/obj/mecha/medical/medigax +/obj/vehicle/sealed/mecha/medical/medigax desc = "A Gygax with it's actuator overload stripped and a slick white paint scheme, for medical use, These exosuits are developed and produced by Vey-Med. (© All rights reserved)." name = "\improper Medical Gygax" icon_state = "medigax" - step_in = 1.75 // a little faster than an odysseus - max_temperature = 25000 + allow_diagonal_movement = TRUE + movedelay = 2 + dir_in = 1 //Facing North. max_integrity = 250 - wreckage = /obj/structure/mecha_wreckage/odysseus - armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - internal_damage_threshold = 35 deflect_chance = 15 + armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) + max_temperature = 25000 + wreckage = /obj/structure/mecha_wreckage/odysseus + internal_damage_threshold = 35 step_energy_drain = 6 infra_luminosity = 6 + internals_req_access = list(ACCESS_ROBOTICS, ACCESS_MEDICAL) - -/obj/mecha/medical/medigax/moved_inside(mob/living/carbon/human/H) +/obj/vehicle/sealed/mecha/medical/medigax/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/medigax/go_out() - if(isliving(occupant)) - var/mob/living/carbon/human/L = occupant +/obj/vehicle/sealed/mecha/medical/medigax/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/medigax/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user) +/obj/vehicle/sealed/mecha/medical/medigax/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/game/mecha/combat/neovgre.dm b/code/modules/vehicles/mecha/combat/neovgre.dm similarity index 74% rename from code/game/mecha/combat/neovgre.dm rename to code/modules/vehicles/mecha/combat/neovgre.dm index 75470abe88..8decd05f96 100644 --- a/code/game/mecha/combat/neovgre.dm +++ b/code/modules/vehicles/mecha/combat/neovgre.dm @@ -1,52 +1,43 @@ -/obj/mecha/combat/neovgre +/obj/vehicle/sealed/mecha/combat/neovgre name = "Neovgre, the Anima Bulwark" - desc = "Nezbere's most powerful creation, a mighty war machine of unmatched power said to have ended wars in a single night." + desc = "Nezbere's most powerful creation, a mighty war machine of unmatched power said to have ended wars in a single night. Armed with a heavy laser and a tesla sphere generator. Requires a pilot and a gunner." icon = 'icons/mecha/neovgre.dmi' icon_state = "neovgre" max_integrity = 500 //This is THE ratvarian superweaon, its deployment is an investment armor = list("melee" = 50, "bullet" = 40, "laser" = 25, "energy" = 25, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100) //Its similar to the clockwork armour albeit with a few buffs becuase RATVARIAN SUPERWEAPON!! force = 50 //SMASHY SMASHY!! + movedelay = 3 internal_damage_threshold = 0 - step_in = 3 pixel_x = -16 layer = ABOVE_MOB_LAYER - breach_time = 100 //ten seconds till all goes to shit - recharge_rate = 100 + var/breach_time = 100 //ten seconds till all goes to shit + var/recharge_rate = 100 internals_req_access = list() - add_req_access = 0 wreckage = /obj/structure/mecha_wreckage/durand/neovgre stepsound = 'sound/mecha/neostep2.ogg' turnsound = 'sound/mecha/powerloader_step.ogg' -/obj/mecha/combat/neovgre/GrantActions(mob/living/user, human_occupant = 0) //No Eject action for you sonny jim, your life for Ratvar! - 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/combat/neovgre/RemoveActions(mob/living/user, human_occupant = 0) - internals_action.Remove(user) - cycle_action.Remove(user) - lights_action.Remove(user) - stats_action.Remove(user) - strafing_action.Remove(user) -/obj/mecha/combat/neovgre/MouseDrop_T(mob/M, mob/user) +/obj/vehicle/sealed/mecha/neovgre/mob_exit(mob/M, silent, forced) + if(forced) + ..() + +/obj/vehicle/sealed/mecha/combat/neovgre/MouseDrop_T(mob/M, mob/user) if(!is_servant_of_ratvar(user)) to_chat(user, "BEGONE HEATHEN!") return else ..() -/obj/mecha/combat/neovgre/moved_inside(mob/living/carbon/human/H) +/obj/vehicle/sealed/mecha/combat/neovgre/moved_inside(mob/living/carbon/human/H) var/list/Itemlist = H.get_contents() for(var/obj/item/clockwork/slab/W in Itemlist) to_chat(H, "You safely store [W] inside [src].") qdel(W) . = ..() -/obj/mecha/combat/neovgre/obj_destruction() +/obj/vehicle/sealed/mecha/combat/neovgre/obj_destruction() for(var/mob/M in src) to_chat(M, "You are consumed by the fires raging within Neovgre...") M.dust() @@ -54,15 +45,15 @@ src.visible_message("The reactor has gone critical, its going to blow!") addtimer(CALLBACK(src,.proc/go_critical),breach_time) -/obj/mecha/combat/neovgre/proc/go_critical() +/obj/vehicle/sealed/mecha/combat/neovgre/proc/go_critical() explosion(get_turf(loc), 3, 5, 10, 20, 30) Destroy(src) -/obj/mecha/combat/neovgre/container_resist(mob/living/user) +/obj/vehicle/sealed/mecha/combat/neovgre/container_resist(mob/living/user) to_chat(user, "Neovgre requires a lifetime commitment friend, no backing out now!") return -/obj/mecha/combat/neovgre/process() +/obj/vehicle/sealed/mecha/combat/neovgre/process() ..() if(!obj_integrity) //Integrity is zero but we would heal out of that state if we went into this before it recognises it being zero return @@ -80,7 +71,7 @@ if(obj_integrity < max_integrity && istype(loc, /turf/open/floor/clockwork)) obj_integrity += min(max_integrity - obj_integrity, max_integrity / 200) -/obj/mecha/combat/neovgre/Initialize() +/obj/vehicle/sealed/mecha/combat/neovgre/Initialize() .=..() GLOB.neovgre_exists ++ var/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/N = new @@ -97,7 +88,7 @@ desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere" fire_sound = 'sound/weapons/neovgre_laser.ogg' -/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M) +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/vehicle/sealed/mecha/combat/neovgre/M) if(istype(M)) return 1 return 0 diff --git a/code/modules/vehicles/mecha/combat/phazon.dm b/code/modules/vehicles/mecha/combat/phazon.dm new file mode 100644 index 0000000000..c964b17e36 --- /dev/null +++ b/code/modules/vehicles/mecha/combat/phazon.dm @@ -0,0 +1,21 @@ +/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" + 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) + max_temperature = 25000 + wreckage = /obj/structure/mecha_wreckage/phazon + internal_damage_threshold = 25 + force = 15 + max_equip = 3 + phase_state = "phazon-phase" + +/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/game/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm similarity index 66% rename from code/game/mecha/combat/reticence.dm rename to code/modules/vehicles/mecha/combat/reticence.dm index 7343a85483..54f13e0fa9 100644 --- a/code/game/mecha/combat/reticence.dm +++ b/code/modules/vehicles/mecha/combat/reticence.dm @@ -1,26 +1,25 @@ -/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" - step_in = 2 + movedelay = 2 dir_in = 1 //Facing North. max_integrity = 100 deflect_chance = 3 - armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) + armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) max_temperature = 15000 wreckage = /obj/structure/mecha_wreckage/reticence operation_req_access = list(ACCESS_THEATRE) - internals_req_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS) - add_req_access = 0 + internals_req_access = list(ACCESS_ROBOTICS, ACCESS_THEATRE) + mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS internal_damage_threshold = 25 max_equip = 2 step_energy_drain = 3 color = "#87878715" stepsound = null turnsound = null - opacity = 0 -/obj/mecha/combat/reticence/loaded/Initialize() +/obj/vehicle/sealed/mecha/combat/reticence/loaded/Initialize() . = ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced ME.attach(src) diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm new file mode 100644 index 0000000000..617b82603a --- /dev/null +++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm @@ -0,0 +1,157 @@ +//DO NOT ADD MECHA PARTS TO THE GAME WITH THE DEFAULT "SPRITE ME" SPRITE! +//I'm annoyed I even have to tell you this! SPRITE FIRST, then commit. + +/obj/item/mecha_parts/mecha_equipment + name = "mecha equipment" + icon = 'icons/mecha/mecha_equipment.dmi' + icon_state = "mecha_equip" + force = 5 + max_integrity = 300 + 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/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. + var/mech_flags = NONE + var/salvageable = 1 + var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed + var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates + var/harmful = FALSE //Controls if equipment can be used to attack by a pacifist. + var/destroy_sound = 'sound/mecha/critdestr.ogg' + +/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page() + if(chassis) + 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.occupants,"exosuit.browser","[REF(src)]",get_equip_info()) + return TRUE + return + +/obj/item/mecha_parts/mecha_equipment/Destroy() + if(chassis) + LAZYREMOVE(chassis.equipment, src) + if(chassis.selected == src) + chassis.selected = null + update_chassis_page() + log_message("[src] is destroyed.", LOG_MECHA) + if(chassis.occupants) + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] is destroyed!") + playsound(chassis, destroy_sound, 50) + if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in. + chassis.max_equip-- + chassis = null + return ..() + +/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) + if(can_attach(M)) + if(!user.temporarilyRemoveItemFromInventory(src)) + return FALSE + attach(M) + user.visible_message("[user] attaches [src] to [M].", "You attach [src] to [M].") + return TRUE + to_chat(user, "You are unable to attach [src] to [M]!") + return FALSE + +/obj/item/mecha_parts/mecha_equipment/proc/get_equip_info() + if(!chassis) + return + var/txt = "* " + if(chassis.selected == src) + txt += "[src.name]" + else if(selectable) + txt += "[src.name]" + else + txt += "[src.name]" + + return txt + +/obj/item/mecha_parts/mecha_equipment/proc/action_checks(atom/target) + if(!target) + return FALSE + if(!chassis) + return FALSE + if(!equip_ready) + return FALSE + if(energy_drain && !chassis.has_charge(energy_drain)) + return FALSE + if(chassis.is_currently_ejecting) + return FALSE + if(chassis.equipment_disabled) + to_chat(chassis.occupants, "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/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) + return TRUE + +/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target, mob/user) + if(!chassis) + return + var/C = chassis.loc + chassis.use_power(energy_drain) + . = do_after(user, equip_cooldown, target=target) + if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) + return FALSE + +/obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, mob/user, delay) + if(!chassis) + return + var/C = chassis.loc + . = do_after(user, delay, target=target) + if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir)) + return FALSE + +/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/vehicle/sealed/mecha/M) + if(LAZYLEN(M.equipment)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].") - mecha_log_message("[target] loaded. Life support functions engaged.") + 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.") - mecha_log_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 update_equip_info() /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 ..() @@ -105,20 +107,23 @@ if(patient) temp = "
\[Occupant: [patient] ([patient.stat > 1 ? "*DECEASED*" : "Health: [patient.health]%"])\]
View stats|Eject" return "[output] [temp]" - 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) /obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_stats() @@ -186,7 +191,7 @@ if(SG && SG.reagents && islist(SG.reagents.reagent_list)) for(var/datum/reagent/R in SG.reagents.reagent_list) if(R.volume > 0) - output += "Inject [R.name]
" + output += "Inject [R.name]
" return output @@ -195,9 +200,9 @@ 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].") - mecha_log_message("Injecting [patient] with [to_inject] units of [R.name].") - log_combat(chassis.occupant, patient, "injected", "[name] ([R] - [to_inject] units)") + 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.occupants, patient, "injected", "[name] ([R] - [to_inject] units)") SG.reagents.trans_id_to(patient,R.type,to_inject) update_equip_info() return @@ -205,9 +210,9 @@ /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 @@ -218,9 +223,8 @@ if(..()) return if(!chassis.has_charge(energy_drain)) - set_ready_state(1) - mecha_log_message("Deactivated.") - occupant_message("[src] deactivated - no power.") + log_message("Deactivated.", LOG_MECHA) + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] deactivated - no power.") STOP_PROCESSING(SSobj, src) return var/mob/living/carbon/M = patient @@ -228,7 +232,10 @@ return if(M.health > 0) M.adjustOxyLoss(-1) - M.AdjustAllImmobility(-80) + M.AdjustStun(-80) + M.AdjustKnockdown(-80) + M.AdjustParalyzed(-80) + M.AdjustImmobilized(-80) M.AdjustUnconscious(-80) if(M.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) < 5) M.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5) @@ -254,15 +261,14 @@ var/synth_speed = 5 //[num] reagent units per cycle energy_drain = 10 var/mode = 0 //0 - fire syringe, 1 - analyze reagents. - range = MELEE|RANGED + range = MECHA_MELEE|MECHA_RANGED equip_cooldown = 10 /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Initialize() . = ..() create_reagents(max_volume, NO_REACT) syringes = new - known_reagents = list(/datum/reagent/medicine/epinephrine = "Epinephrine", /datum/reagent/medicine/charcoal = "Charcoal", /datum/reagent/medicine/prussian_blue = "Prussian Blue", \ - /datum/reagent/medicine/dexalin = "Dexalin", /datum/reagent/medicine/insulin = "Insulin", /datum/reagent/medicine/kelotane = "Kelotane", /datum/reagent/medicine/bicaridine = "Bicaridine") + known_reagents = list(/datum/reagent/medicine/epinephrine="Epinephrine") processed_reagents = new /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/detach() @@ -273,39 +279,35 @@ STOP_PROCESSING(SSobj, src) return ..() -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/critfail() - ..() - if(reagents) - reagents.reagents_holder_flags &= ~(NO_REACT) - -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/mecha/medical/M) - if(..()) - if(istype(M)) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M) + . = ..() + if(!istype(M)) + return FALSE /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/get_equip_info() var/output = ..() if(output) 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] @@ -314,11 +316,9 @@ syringes -= mechsyringe mechsyringe.icon = 'icons/obj/chemical.dmi' mechsyringe.icon_state = "syringeproj" - playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1) - mecha_log_message("Launched [mechsyringe] from [src], targeting [target].") - var/mob/originaloccupant = chassis.occupant - spawn(0) - src = null //if src is deleted, still process the syringe + playsound(chassis, 'sound/items/syringeproj.ogg', 50, TRUE) + 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 @@ -326,10 +326,10 @@ var/list/mobs = new for(var/mob/living/carbon/M in mechsyringe.loc) mobs += M - var/mob/living/carbon/M = safepick(mobs) - if(M) + if(length(mobs)) + var/mob/living/carbon/M = pick(mobs) var/R - mechsyringe.visible_message(" [M] was hit by the syringe!") + mechsyringe.visible_message(" [M] is hit by the syringe!") if(M.can_inject(null, 1)) if(mechsyringe.reagents) for(var/datum/reagent/A in mechsyringe.reagents.reagent_list) @@ -337,9 +337,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) + mechsyringe.reagents.trans_to(M, mechsyringe.reagents.total_volume, log = TRUE) 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) @@ -352,7 +352,7 @@ mechsyringe.update_icon() break sleep(1) - return 1 + return ..() /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Topic(href,href_list) @@ -376,12 +376,14 @@ if(processed_reagents.len) message += " added to production" START_PROCESSING(SSobj, src) - occupant_message(message) - occupant_message("Reagent processing started.") - mecha_log_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) @@ -445,74 +447,72 @@ var/output for(var/datum/reagent/R in reagents.reagent_list) if(R.volume > 0) - output += "[R]: [round(R.volume,0.001)] - Purge Reagent
" + output += "[R]: [round(R.volume,0.001)] - Purge Reagent
" if(output) 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.len= 2) - occupant_message("The syringe is too far away.") + to_chat(user, "[icon2html(src, user)]The syringe is too far away!") return 0 for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows) if(!(D.CanPass(S,src.loc))) - occupant_message("Unable to load syringe.") + to_chat(user, "[icon2html(src, user)]Unable to load syringe!") return 0 for(var/obj/machinery/door/D in S.loc)//Checks for doors if(!(D.CanPass(S,src.loc))) - occupant_message("Unable to load syringe.") + to_chat(user, "[icon2html(src, user)]Unable to load syringe!") return 0 S.reagents.trans_to(src, S.reagents.total_volume) S.forceMove(src) syringes += S - occupant_message("Syringe loaded.") + to_chat(user, "[icon2html(src, user)]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.can_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()) - return 1 - return + send_byjax(chassis.occupants,"msyringegun.browser","reagents",get_current_reagents()) + send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form()) + return TRUE /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/on_reagent_change(changetype) ..() update_equip_info() - return /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/process() if(..()) return if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(energy_drain)) - occupant_message("Reagent processing stopped.") - mecha_log_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 var/amount = synth_speed / processed_reagents.len @@ -527,7 +527,7 @@ desc = "Equipment for medical exosuits. Generates a focused beam of medical nanites." icon_state = "mecha_medigun" energy_drain = 10 - range = MELEE|RANGED + range = MECHA_MELEE|MECHA_RANGED equip_cooldown = 0 var/obj/item/gun/medbeam/mech/medigun custom_materials = list(/datum/material/iron = 15000, /datum/material/glass = 8000, /datum/material/plasma = 3000, /datum/material/gold = 8000, /datum/material/diamond = 2000) @@ -546,7 +546,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) diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm similarity index 70% rename from code/game/mecha/equipment/tools/mining_tools.dm rename to code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index 47820d1e27..80a3c050a5 100644 --- a/code/game/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, null, null, TRUE) -/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)) @@ -34,72 +35,69 @@ return target.visible_message("[chassis] starts to drill [target].", \ "[chassis] starts to drill [target]...", \ - "You hear drilling.") + "You hear drilling.") - if(do_after_cooldown(target)) - set_ready_state(FALSE) - mecha_log_message("Started drilling [target]") + 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) - playsound(src,'sound/weapons/drill.ogg',40,1) + drill_mob(target, source) + playsound(src,'sound/weapons/drill.ogg',40,TRUE) 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) + playsound(src,'sound/weapons/drill.ogg',40,TRUE) 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)) - drill.mecha_log_message("Drilled through [src]") +/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)) - drill.mecha_log_message("Drilled through [src]") + 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) for(var/turf/closed/mineral/M in range(drill.chassis,1)) if(get_dir(drill.chassis,M)&drill.chassis.dir) M.gets_drilled() - drill.mecha_log_message("Drilled through [src]") + 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) for(var/turf/open/floor/plating/asteroid/M in range(1, drill.chassis)) if((get_dir(drill.chassis,M)&drill.chassis.dir) && !M.dug) M.getDug() - drill.mecha_log_message("Drilled through [src]") + drill.log_message("Drilled through [src]", LOG_MECHA) drill.move_ores() /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) +/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 @@ -123,7 +121,7 @@ else //drill makes a hole var/obj/item/bodypart/target_part = target.get_bodypart(ran_zone(BODY_ZONE_CHEST)) - target.apply_damage(10, BRUTE, BODY_ZONE_CHEST, target.run_armor_check(target_part, "melee")) + target.apply_damage(10, BRUTE, BODY_ZONE_CHEST, target.run_armor_check(target_part, MELEE)) //blood splatters var/splatter_dir = get_dir(chassis, target) @@ -153,7 +151,7 @@ /obj/item/mecha_parts/mecha_equipment/mining_scanner name = "exosuit mining scanner" - desc = "Equipment for engineering and combat exosuits. It will automatically check surrounding rock for useful minerals." + desc = "Equipment for working exosuits. It will automatically check surrounding rock for useful minerals." icon_state = "mecha_analyzer" selectable = 0 equip_cooldown = 15 @@ -164,13 +162,19 @@ . = ..() START_PROCESSING(SSfastprocess, src) +/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/vehicle/sealed/mecha/M as obj) + if(..()) + if(istype(M, /obj/vehicle/sealed/mecha/working)) + return TRUE + return FALSE + /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)) diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm similarity index 58% rename from code/game/mecha/equipment/tools/other_tools.dm rename to code/modules/vehicles/mecha/equipment/tools/other_tools.dm index e1861232f4..30642db926 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm @@ -10,15 +10,16 @@ icon_state = "mecha_teleport" equip_cooldown = 150 energy_drain = 1000 - range = RANGED + range = MECHA_RANGED + var/teleport_range = 7 -/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) + if(T && (loc.z == T.z) && (get_dist(loc, T) <= teleport_range)) do_teleport(chassis, T, 4, channel = TELEPORT_CHANNEL_BLUESPACE) - return 1 + return ..() @@ -30,10 +31,10 @@ icon_state = "mecha_wholegen" equip_cooldown = 50 energy_drain = 300 - range = RANGED + 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) @@ -44,10 +45,10 @@ var/turf/pos = get_turf(src) for(var/turf/T in get_area_turfs(thearea.type)) if(!T.density && pos.z == T.z) - var/clear = 1 + var/clear = TRUE for(var/obj/O in T) if(O.density) - clear = 0 + clear = FALSE break if(clear) L+=T @@ -58,11 +59,11 @@ return var/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, 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 /////////////////////////////////////////// @@ -73,36 +74,41 @@ icon_state = "mecha_teleport" equip_cooldown = 10 energy_drain = 100 - range = MELEE|RANGED + range = MECHA_MELEE|MECHA_RANGED var/atom/movable/locked 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()) + 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)) @@ -112,15 +118,21 @@ for(var/atom/movable/A in atoms) if(A.anchored || A.move_resist >= MOVE_FORCE_EXTREMELY_STRONG) continue - spawn(0) - var/iter = 5-get_dist(A,target) - for(var/i=0 to iter) - step_away(A,target) - sleep(2) - var/turf/T = get_turf(target) - log_game("[key_name(chassis.occupant)] used a Gravitational Catapult repulse wave on [AREACOORD(T)]") - return TRUE + if(ismob(A)) + var/mob/M = A + if(M.mob_negates_gravity()) + continue + INVOKE_ASYNC(src, .proc/do_scatter, A, target) + var/turf/T = get_turf(target) + log_game("[key_name(source)] used a Gravitational Catapult repulse wave on [AREACOORD(T)]") + return ..() + +/obj/item/mecha_parts/mecha_equipment/gravcatapult/proc/do_scatter(atom/movable/A, atom/movable/target) + var/iter = 5-get_dist(A,target) + for(var/i in 0 to iter) + step_away(A,target) + sleep(2) /obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info() return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" @@ -129,7 +141,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 @@ -150,9 +162,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 @@ -168,9 +181,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 ////////////////////////////////////////////////// @@ -193,7 +207,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) @@ -216,21 +230,18 @@ if(equip_ready) START_PROCESSING(SSobj, src) droid_overlay = new(src.icon, icon_state = "repair_droid_a") - mecha_log_message("Activated.") - set_ready_state(0) + log_message("Activated.", LOG_MECHA) else STOP_PROCESSING(SSobj, src) droid_overlay = new(src.icon, icon_state = "repair_droid") - mecha_log_message("Deactivated.") - set_ready_state(1) + log_message("Deactivated.", LOG_MECHA) 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 @@ -242,16 +253,14 @@ chassis.clearInternalDamage(int_dam_flag) repaired = 1 break - if(health_boost<0 || chassis.obj_integrity < chassis.max_integrity) - chassis.obj_integrity += min(health_boost, chassis.max_integrity-chassis.obj_integrity) + if(h_boost<0 || chassis.obj_integrity < chassis.max_integrity) + chassis.obj_integrity += min(h_boost, chassis.max_integrity-chassis.obj_integrity) repaired = 1 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) @@ -284,12 +293,12 @@ if(equip_ready) //disabled return var/area/A = get_area(chassis) - var/pow_chan = get_MUTATION_POWER_channel(A) + var/pow_chan = GET_MUTATION_POWER_channel(A) if(pow_chan) return 1000 //making magic -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_MUTATION_POWER_channel(var/area/A) +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/GET_MUTATION_POWER_channel(area/A) var/pow_chan if(A) for(var/c in use_channels) @@ -303,12 +312,10 @@ if(href_list["toggle_relay"]) if(equip_ready) //inactive START_PROCESSING(SSobj, src) - set_ready_state(0) - mecha_log_message("Activated.") + log_message("Activated.", LOG_MECHA) else STOP_PROCESSING(SSobj, src) - set_ready_state(1) - mecha_log_message("Deactivated.") + log_message("Deactivated.", LOG_MECHA) /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info() if(!chassis) @@ -319,19 +326,17 @@ /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 powercell detected.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]No power cell detected.") return if(cur_charge < chassis.cell.maxcharge) - var/area/A = get_base_area(chassis) + var/area/A = get_area(chassis) if(A) var/pow_chan - for(var/c in list(EQUIP,ENVIRON,LIGHT)) + for(var/c in use_channels) if(A.powered(c)) pow_chan = c break @@ -350,7 +355,7 @@ name = "exosuit plasma converter" desc = "An exosuit module that generates power using solid plasma as fuel. Pollutes the environment." icon_state = "tesla" - range = MELEE + range = MECHA_MELEE var/coeff = 100 var/obj/item/stack/sheet/fuel var/max_fuel = 150000 @@ -377,77 +382,54 @@ ..() if(href_list["toggle"]) if(equip_ready) //inactive - set_ready_state(0) START_PROCESSING(SSobj, src) - mecha_log_message("Activated.") + log_message("Activated.", LOG_MECHA) else - set_ready_state(1) STOP_PROCESSING(SSobj, src) - mecha_log_message("Deactivated.") + log_message("Deactivated.", LOG_MECHA) /obj/item/mecha_parts/mecha_equipment/generator/get_equip_info() var/output = ..() if(output) return "[output] \[[fuel]: [round(fuel.amount*MINERAL_MATERIAL_AMOUNT,0.1)] cm3\] - [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*MINERAL_MATERIAL_AMOUNT,0) if(to_load) var/units = min(max(round(to_load / MINERAL_MATERIAL_AMOUNT),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) load_fuel(weapon) -/obj/item/mecha_parts/mecha_equipment/generator/critfail() - ..() - var/turf/open/T = get_turf(src) - if(!istype(T)) - return - var/datum/gas_mixture/GM = new - if(prob(10)) - GM.adjust_moles(GAS_PLASMA,100) - GM.set_temperature(1500+T0C) //should be enough to start a fire - T.visible_message("[src] suddenly disgorges a cloud of heated plasma.") - qdel(src) - else - GM.adjust_moles(GAS_PLASMA,5) - GM.set_temperature(istype(T) ? T.air.return_temperature() : T20C) - T.visible_message("[src] suddenly disgorges a cloud of plasma.") - T.assume_air(GM) - return - /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) - mecha_log_message("Deactivated - no fuel.") - set_ready_state(1) + log_message("Deactivated - no fuel.", LOG_MECHA) return var/cur_charge = chassis.get_charge() if(isnull(cur_charge)) - set_ready_state(1) - occupant_message("No powercell detected.") - mecha_log_message("Deactivated.") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]No power cell detected.") + log_message("Deactivated.", LOG_MECHA) STOP_PROCESSING(SSobj, src) return var/use_fuel = fuel_per_cycle_idle @@ -456,7 +438,7 @@ chassis.give_power(power_per_cycle) fuel.amount -= min(use_fuel/MINERAL_MATERIAL_AMOUNT,fuel.amount) update_equip_info() - return 1 + return TRUE /obj/item/mecha_parts/mecha_equipment/generator/nuclear @@ -472,9 +454,118 @@ /obj/item/mecha_parts/mecha_equipment/generator/nuclear/generator_init() fuel = new /obj/item/stack/sheet/mineral/uranium(src, 0) -/obj/item/mecha_parts/mecha_equipment/generator/nuclear/critfail() - return - /obj/item/mecha_parts/mecha_equipment/generator/nuclear/process() if(..()) radiation_pulse(get_turf(src), rad_per_cycle) + + +/////////////////////////////////////////// THRUSTERS ///////////////////////////////////////////// + +/obj/item/mecha_parts/mecha_equipment/thrusters + name = "generic exosuit thrusters" //parent object, in-game sources will be a child object + desc = "A generic set of thrusters, from an unknown source. Uses not-understood methods to propel exosuits seemingly for free." + icon_state = "thrusters" + selectable = FALSE + var/effect_type = /obj/effect/particle_effect/sparks + +/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) + for(var/obj/item/I in M.equipment) + if(istype(I, src)) + to_chat(user, "[M] already has this thruster package!") + return FALSE + . = ..() + +/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/vehicle/sealed/mecha/M) + M.active_thrusters = src //Enable by default + . = ..() + +/obj/item/mecha_parts/mecha_equipment/thrusters/detach() + if(chassis?.active_thrusters == src) + chassis.active_thrusters = null + . = ..() + +/obj/item/mecha_parts/mecha_equipment/thrusters/Destroy() + if(chassis?.active_thrusters == src) + chassis.active_thrusters = null + . = ..() + +/obj/item/mecha_parts/mecha_equipment/thrusters/Topic(href,href_list) + ..() + if(!chassis) + return + if(href_list["mode"]) + var/mode = text2num(href_list["mode"]) + switch(mode) + if(0) + enable() + if(1) + disable() + return + +/obj/item/mecha_parts/mecha_equipment/thrusters/proc/enable() + if (chassis.active_thrusters == src) + return + chassis.active_thrusters = src + 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 + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][src] disabled.") + +/obj/item/mecha_parts/mecha_equipment/thrusters/get_equip_info() + return "[..()] \[Enable|Disable\]" + +/obj/item/mecha_parts/mecha_equipment/thrusters/proc/thrust(movement_dir) + if(!chassis) + return FALSE + generate_effect(movement_dir) + return TRUE //This parent should never exist in-game outside admeme use, so why not let it be a creative thruster? + +/obj/item/mecha_parts/mecha_equipment/thrusters/proc/generate_effect(movement_dir) + var/obj/effect/particle_effect/E = new effect_type(get_turf(chassis)) + E.dir = turn(movement_dir, 180) + step(E, turn(movement_dir, 180)) + QDEL_IN(E, 5) + + +/obj/item/mecha_parts/mecha_equipment/thrusters/gas + name = "RCS thruster package" + desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments, by expelling gas from the internal life support tank." + effect_type = /obj/effect/particle_effect/smoke + var/move_cost = 20 //moles per step + +/obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) + if(!M.internal_tank) + to_chat(user, "[M] does not have an internal tank and cannot support this upgrade!") + return FALSE + . = ..() + +/obj/item/mecha_parts/mecha_equipment/thrusters/gas/thrust(movement_dir) + if(!chassis || !chassis.internal_tank) + return FALSE + var/moles = chassis.internal_tank.air_contents.total_moles() + if(moles < move_cost) + chassis.internal_tank.air_contents.remove(moles) + return FALSE + chassis.internal_tank.air_contents.remove(move_cost) + generate_effect(movement_dir) + return TRUE + + + +/obj/item/mecha_parts/mecha_equipment/thrusters/ion //for mechs with built-in thrusters, should never really exist un-attached to a mech + name = "Ion thruster package" + desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments." + detachable = FALSE + salvageable = FALSE + effect_type = /obj/effect/particle_effect/ion_trails + +/obj/item/mecha_parts/mecha_equipment/thrusters/ion/thrust(movement_dir) + if(!chassis) + return FALSE + if(chassis.use_power(chassis.step_energy_drain)) + generate_effect(movement_dir) + return TRUE + return FALSE diff --git a/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm b/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm new file mode 100644 index 0000000000..469d430328 --- /dev/null +++ b/code/modules/vehicles/mecha/equipment/tools/weapon_bay.dm @@ -0,0 +1,14 @@ +/obj/item/mecha_parts/concealed_weapon_bay + name = "concealed weapon bay" + desc = "A compartment that allows a non-combat mecha to equip one weapon while hiding the weapon from plain sight." + icon = 'icons/mecha/mecha_equipment.dmi' + icon_state = "mecha_weapon_bay" + +/obj/item/mecha_parts/concealed_weapon_bay/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) + if(istype(M, /obj/vehicle/sealed/mecha/combat)) + to_chat(user, "[M] can already hold weapons!") + return + if(locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents) + to_chat(user, "[M] already has a concealed weapon bay!") + return + ..() diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm new file mode 100644 index 0000000000..d3d4c8addc --- /dev/null +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -0,0 +1,410 @@ + +//Hydraulic clamp, Kill clamp, Extinguisher, RCD, Cable layer. + + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp + name = "hydraulic clamp" + desc = "Equipment for engineering exosuits. Lifts objects and loads them into cargo." + icon_state = "mecha_clamp" + equip_cooldown = 15 + energy_drain = 10 + tool_behaviour = TOOL_RETRACTOR + range = MECHA_MELEE + toolspeed = 0.8 + var/dam_force = 20 + 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/vehicle/sealed/mecha/working/ripley/M) + if(..()) + if(istype(M)) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/attach(obj/vehicle/sealed/mecha/M) + ..() + cargo_holder = M + return + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/detach(atom/moveto = null) + ..() + cargo_holder = null + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(mob/source, atom/target, params) + if(!action_checks(target)) + return + if(!cargo_holder) + return + if(ismecha(target)) + var/obj/vehicle/sealed/mecha/M = target + var/have_ammo + for(var/obj/item/mecha_ammo/box in cargo_holder.cargo) + if(istype(box, /obj/item/mecha_ammo) && box.rounds) + have_ammo = TRUE + if(M.ammo_resupply(box, source, TRUE)) + return + if(have_ammo) + to_chat(source, "No further supplies can be provided to [M].") + else + to_chat(source, "No providable supplies found in cargo hold") + return + if(isobj(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) + return + if(istype(O, /obj/machinery/door/airlock/)) + var/obj/machinery/door/airlock/D = O + 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 cargo compartment.") + O.set_anchored(TRUE) + if(do_after_cooldown(target, source)) + cargo_holder.cargo += O + O.forceMove(chassis) + O.set_anchored(FALSE) + to_chat(source, "[icon2html(src, source)][target] successfully loaded.") + log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]", LOG_MECHA) + else + O.set_anchored(initial(O.anchored)) + else + to_chat(source, "[icon2html(src, source)]Not enough room in cargo compartment!") + else + to_chat(source, "[icon2html(src, source)][target] is firmly secured!") + + else if(isliving(target)) + var/mob/living/M = target + if(M.stat == DEAD) + return + if(source.a_intent == INTENT_HARM) + M.take_overall_damage(dam_force) + if(!M) + return + M.adjustOxyLoss(round(dam_force/2)) + M.updatehealth() + target.visible_message("[chassis] squeezes [target]!", \ + "[chassis] squeezes you!",\ + "You hear something crack.") + log_combat(source, M, "attacked", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + else + step_away(M,chassis) + to_chat(source, "[icon2html(src, source)]You push [target] out of the way.") + chassis.visible_message("[chassis] pushes [target] out of the way.") + return ..() + + + +//This is pretty much just for the death-ripley +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill + name = "\improper KILL CLAMP" + desc = "They won't know what clamped them!" + energy_drain = 0 + dam_force = 0 + var/real_clamp = FALSE + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/real + desc = "They won't know what clamped them! This time for real!" + energy_drain = 10 + dam_force = 20 + real_clamp = TRUE + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/action(mob/source, atom/target, params) + if(!action_checks(target)) + return + if(!cargo_holder) + return + if(isobj(target)) + var/obj/O = target + if(!O.anchored) + if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) + chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") + O.set_anchored(TRUE) + if(do_after_cooldown(target, source)) + cargo_holder.cargo += O + O.forceMove(chassis) + O.set_anchored(FALSE) + to_chat(source, "[icon2html(src, source)][target] successfully loaded.") + log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]", LOG_MECHA) + else + O.set_anchored(initial(O.anchored)) + else + to_chat(source, "[icon2html(src, source)]Not enough room in cargo compartment!") + else + to_chat(source, "[icon2html(src, source)][target] is firmly secured!") + + else if(isliving(target)) + var/mob/living/M = target + if(M.stat == DEAD) + return + if(source.a_intent == INTENT_HARM) + if(real_clamp) + M.take_overall_damage(dam_force) + if(!M) + return + M.adjustOxyLoss(round(dam_force/2)) + M.updatehealth() + target.visible_message("[chassis] destroys [target] in an unholy fury!", \ + "[chassis] destroys you in an unholy fury!") + 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(source.a_intent == INTENT_DISARM) + if(real_clamp) + var/mob/living/carbon/C = target + var/play_sound = FALSE + var/limbs_gone = "" + var/obj/item/bodypart/affected = C.get_bodypart(BODY_ZONE_L_ARM) + if(affected != null) + affected.dismember(damtype) + play_sound = TRUE + limbs_gone = ", [affected]" + affected = C.get_bodypart(BODY_ZONE_R_ARM) + if(affected != null) + affected.dismember(damtype) + play_sound = TRUE + limbs_gone = "[limbs_gone], [affected]" + if(play_sound) + playsound(src, get_dismember_sound(), 80, TRUE) + target.visible_message("[chassis] rips [target]'s arms off!", \ + "[chassis] rips your arms off!") + 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!") + else + step_away(M,chassis) + target.visible_message("[chassis] tosses [target] like a piece of paper!", \ + "[chassis] tosses you like a piece of paper!") + return ..() + + + +/obj/item/mecha_parts/mecha_equipment/extinguisher + name = "exosuit extinguisher" + desc = "Equipment for engineering exosuits. A rapid-firing high capacity fire extinguisher." + icon_state = "mecha_exting" + equip_cooldown = 5 + energy_drain = 0 + range = MECHA_MELEE|MECHA_RANGED + mech_flags = EXOSUIT_MODULE_WORKING + +/obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize() + . = ..() + create_reagents(1000) + reagents.add_reagent(/datum/reagent/water, 1000) + +/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) + to_chat(chassis.occupants,"Extinguisher refilled.") + playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) + else + if(reagents.total_volume > 0) + playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) + var/direction = get_dir(chassis,target) + var/turf/T = get_turf(target) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + + var/list/the_targets = list(T,T1,T2) + spawn(0) + for(var/a=0, a<5, a++) + var/obj/effect/particle_effect/water/W = new /obj/effect/particle_effect/water(get_turf(chassis)) + if(!W) + return + var/turf/my_target = pick(the_targets) + var/datum/reagents/R = new/datum/reagents(5) + W.reagents = R + R.my_atom = W + reagents.trans_to(W,1) + for(var/b=0, b<4, b++) + if(!W) + return + step_towards(W,my_target) + if(!W) + return + var/turf/W_turf = get_turf(W) + W.reagents.reaction(W_turf) + for(var/atom/atm in W_turf) + W.reagents.reaction(atm) + if(W.loc == my_target) + break + sleep(2) + return 1 + +/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/vehicle/sealed/mecha/working/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 + + + +/obj/item/mecha_parts/mecha_equipment/rcd + name = "mounted RCD" + desc = "An exosuit-mounted Rapid Construction Device." + icon_state = "mecha_rcd" + equip_cooldown = 10 + energy_drain = 250 + range = MECHA_MELEE|MECHA_RANGED + item_flags = NO_MAT_REDEMPTION + var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. + +/obj/item/mecha_parts/mecha_equipment/rcd/Initialize() + . = ..() + GLOB.rcd_list += src + +/obj/item/mecha_parts/mecha_equipment/rcd/Destroy() + GLOB.rcd_list -= src + return ..() + +/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 + + if(!isturf(target) && !istype(target, /obj/machinery/door/airlock)) + target = get_turf(target) + if(!action_checks(target) || get_dist(chassis, target)>3) + return + playsound(chassis, 'sound/machines/click.ogg', 50, TRUE) + + switch(mode) + if(0) + if(iswallturf(target)) + var/turf/closed/wall/W = target + 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, TRUE) + else if(isfloorturf(target)) + var/turf/open/floor/F = 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, TRUE) + else if (istype(target, /obj/machinery/door/airlock)) + 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, TRUE) + if(1) + if(isspaceturf(target)) + var/turf/open/space/S = target + 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, TRUE) + chassis.spark_system.start() + else if(isfloorturf(target)) + var/turf/open/floor/F = target + 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, TRUE) + chassis.spark_system.start() + if(2) + if(isfloorturf(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, TRUE) + playsound(target, 'sound/effects/sparks2.ogg', 50, TRUE) + return ..() + +/obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + switch(mode) + if(0) + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Switched RCD to Deconstruct.") + energy_drain = initial(energy_drain) + if(1) + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Switched RCD to Construct.") + energy_drain = 2*initial(energy_drain) + if(2) + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]Switched RCD to Construct Airlock.") + energy_drain = 2*initial(energy_drain) + return + +/obj/item/mecha_parts/mecha_equipment/rcd/get_equip_info() + return "[..()] \[D|C|A\]" + +//Dunno where else to put this so shrug +/obj/item/mecha_parts/mecha_equipment/ripleyupgrade + name = "Ripley MK-II Conversion Kit" + desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I mecha, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied." + icon_state = "tesla" + mech_flags = EXOSUIT_MODULE_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.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(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 + to_chat(loc, "The conversion process requires a cell installed.") + return FALSE + 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) + if(!N) + return + QDEL_NULL(N.cell) + if (M.cell) + N.cell = M.cell + M.cell.forceMove(N) + M.cell = null + QDEL_NULL(N.scanmod) + if (M.scanmod) + N.scanmod = M.scanmod + M.scanmod.forceMove(N) + M.scanmod = null + QDEL_NULL(N.capacitor) + if (M.capacitor) + N.capacitor = M.capacitor + M.capacitor.forceMove(N) + M.capacitor = null + N.update_part_values() + for(var/obj/item/mecha_parts/E in M.contents) + 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(M) + E.attach(N) + N.dna_lock = M.dna_lock + 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\"") + N.name = M.name + M.wreckage = 0 + qdel(M) + playsound(get_turf(N),'sound/items/ratchet.ogg',50,TRUE) + return diff --git a/code/game/mecha/equipment/weapons/mecha_ammo.dm b/code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm similarity index 94% rename from code/game/mecha/equipment/weapons/mecha_ammo.dm rename to code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm index 3253e6cbd6..edc2b4716e 100644 --- a/code/game/mecha/equipment/weapons/mecha_ammo.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm @@ -9,7 +9,7 @@ var/rounds = 0 var/round_term = "round" var/direct_load //For weapons where we re-load the weapon itself rather than adding to the ammo storage. - var/load_audio = "sound/weapons/gun_magazine_insert_empty_1.ogg" + var/load_audio = 'sound/weapons/bulletinsert.ogg' var/ammo_type /obj/item/mecha_ammo/update_name() @@ -62,7 +62,7 @@ rounds = 6 round_term = "missile" direct_load = TRUE - load_audio = "sound/weapons/bulletinsert.ogg" + load_audio = 'sound/weapons/bulletinsert.ogg' ammo_type = "missiles_br" /obj/item/mecha_ammo/missiles_he @@ -72,7 +72,7 @@ rounds = 8 round_term = "missile" direct_load = TRUE - load_audio = "sound/weapons/bulletinsert.ogg" + load_audio = 'sound/weapons/bulletinsert.ogg' ammo_type = "missiles_he" diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm similarity index 70% rename from code/game/mecha/equipment/weapons/weapons.dm rename to code/modules/vehicles/mecha/equipment/weapons/weapons.dm index a9d7853187..1f1211a3a4 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -1,76 +1,61 @@ /obj/item/mecha_parts/mecha_equipment/weapon name = "mecha weapon" - range = RANGED + range = MECHA_RANGED + destroy_sound = 'sound/mecha/weapdestr.ogg' var/projectile 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/combat/M) - if(..()) - if(istype(M)) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/vehicle/sealed/mecha/M) + if(!..()) + return FALSE + if(istype(M, /obj/vehicle/sealed/mecha/combat)) + return TRUE + if((locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents) && !(locate(/obj/item/mecha_parts/mecha_equipment/weapon) in M.equipment)) + return TRUE + return FALSE -/obj/item/mecha_parts/mecha_equipment/weapon/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/item/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/item/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)) - chassis.mecha_log_message("Fired from [src.name], targeting [target].") - return 1 - + if(kickback) + chassis.newtonian_move(newtonian_target) + chassis.log_message("Fired from [src.name], targeting [target].", LOG_MECHA) + 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/set_ready_state, 1), equip_cooldown) - /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser equip_cooldown = 8 name = "\improper CH-PS \"Immolator\" laser" @@ -81,6 +66,15 @@ fire_sound = 'sound/weapons/laser.ogg' harmful = TRUE +/obj/item/mecha_parts/mecha_equipment/weapon/energy/disabler + equip_cooldown = 8 + name = "\improper CH-DS \"Peacemaker\" disabler" + desc = "A weapon for combat exosuits. Shoots basic disablers." + icon_state = "mecha_disabler" + energy_drain = 30 + projectile = /obj/item/projectile/beam/disabler + fire_sound = 'sound/weapons/taser2.ogg' + /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy equip_cooldown = 15 name = "\improper CH-LC \"Solaris\" laser cannon" @@ -97,7 +91,7 @@ icon_state = "mecha_ion" energy_drain = 120 projectile = /obj/item/projectile/ion - fire_sound = 'sound/weapons/IonRifle.ogg' + fire_sound = 'sound/weapons/laser.ogg' /obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla equip_cooldown = 35 @@ -124,7 +118,6 @@ name = "217-D Heavy Plasma Cutter" desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles." icon_state = "mecha_plasmacutter" - item_state = "plasmacutter" lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' energy_drain = 30 @@ -132,12 +125,12 @@ fire_sound = 'sound/weapons/plasma_cutter.ogg' harmful = TRUE -/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/working/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" @@ -155,47 +148,53 @@ icon_state = "mecha_honker" energy_drain = 200 equip_cooldown = 150 - range = MELEE|RANGED + range = MECHA_MELEE|MECHA_RANGED 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") + playsound(chassis, 'sound/items/airhorn.ogg', 100, TRUE) + 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 - if(istype(H.ears, /obj/item/clothing/ears/earmuffs)) - continue + if(!M.can_hear()) + continue + var/turf/turf_check = get_turf(M) + if(isspaceturf(turf_check) && !turf_check.Adjacent(src)) //in space nobody can hear you honk. + continue to_chat(M, "HONK") M.SetSleeping(0) M.stuttering += 20 - M.adjustEarDamage(0, 30) - M.DefaultCombatKnockdown(60) + var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS) + if(ears) + ears.adjustEarDamage(0, 30) + M.Paralyze(60) if(prob(30)) M.Stun(200) M.Unconscious(80) else M.Jitter(500) - mecha_log_message("Honked from [src.name]. HONK!") + 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)]") - return 1 + 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 ..() //Base ballistic weapon type /obj/item/mecha_parts/mecha_equipment/weapon/ballistic name = "general ballistic weapon" - fire_sound = 'sound/weapons/lmgshot.ogg' + fire_sound = 'sound/weapons/shot.ogg' var/projectiles var/projectiles_cache //ammo to be loaded in, if possible. var/projectiles_cache_max @@ -203,15 +202,12 @@ var/disabledreload //For weapons with no cache (like the rockets) which are reloaded by hand var/ammo_type -/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][projectiles_cache_max &&!projectile_energy_cost?"/[projectiles_cache]":""]\][!disabledreload &&(src.projectiles < initial(src.projectiles))?" - Rearm":null]" @@ -237,7 +233,8 @@ projectiles = projectiles + projectiles_cache projectiles_cache = 0 - 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 TRUE @@ -252,11 +249,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 @@ -274,7 +271,7 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced name = "\improper S.H.H. \"Quietus\" Carbine" desc = "A weapon for combat exosuits. A mime invention, field tests have shown that targets cannot even scream before going down." - fire_sound = 'sound/weapons/gunshot_silenced.ogg' + fire_sound = 'sound/weapons/Gunshot_silenced.ogg' icon_state = "mecha_mime" equip_cooldown = 30 projectile = /obj/item/projectile/bullet/mime @@ -285,7 +282,6 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot name = "\improper LBX AC 10 \"Scattershot\"" desc = "A weapon for combat exosuits. Shoots a spread of pellets." - fire_sound = 'sound/weapons/gunshotshotgunshot.ogg' icon_state = "mecha_scatter" equip_cooldown = 20 projectile = /obj/item/projectile/bullet/scattershot @@ -347,7 +343,7 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/breaching name = "\improper BRM-6 missile rack" - desc = "A weapon for combat exosuits. Launches low-explosive breaching missiles designed to explode only when striking a sturdy target." + desc = "A weapon for combat exosuits. Launches high-explosive breaching missiles with a safety fuze designed to explode only when striking a sturdy target." icon_state = "mecha_missilerack_six" projectile = /obj/item/projectile/bullet/a84mm_br fire_sound = 'sound/weapons/rocketlaunch.ogg' @@ -365,19 +361,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) - mecha_log_message("Launched a [O.name] from [name], targeting [target].") + playsound(chassis, fire_sound, 50, TRUE) + 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(obj/O, mob/user) return @@ -395,10 +391,10 @@ var/det_time = 20 ammo_type = "flashbang" -/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, /obj/item/grenade/flashbang.proc/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 @@ -422,8 +418,9 @@ missile_speed = 1.5 projectile_energy_cost = 100 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 @@ -439,14 +436,15 @@ missile_speed = 1.5 projectile_energy_cost = 100 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 return 0 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/proj_init(var/obj/item/assembly/mousetrap/armed/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/proj_init(obj/item/assembly/mousetrap/armed/M) M.secured = 1 @@ -457,28 +455,58 @@ icon_state = "mecha_punching_glove" energy_drain = 250 equip_cooldown = 20 - range = MELEE|RANGED + range = MECHA_MELEE|MECHA_RANGED missile_range = 5 projectile = /obj/item/punching_glove fire_sound = 'sound/items/bikehorn.ogg' projectiles = 10 projectile_energy_cost = 500 + harmful = TRUE diags_first = TRUE + /// Damage done by the glove on contact. Also used to determine throw distance (damage / 5) + var/punch_damage = 35 + /// TRUE - Can toggle between lethal and non-lethal || FALSE - Cannot toggle + var/can_toggle_lethal = TRUE + mech_flags = EXOSUIT_MODULE_HONK -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/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 return 0 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(target) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/get_equip_info() + if(!chassis) + return + + if(can_toggle_lethal) + return "[..()]   [harmful?"Punch":"Pat"] mode" + else + return ..() + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/Topic(href, href_list) + ..() + if(href_list["lethalPunch"]) + harmful = !harmful + if(harmful) + to_chat(usr, "[icon2html(src, usr)]Lethal Fisting Enabled.") + else + to_chat(usr, "[icon2html(src, usr)]Lethal Fisting Disabled.") + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(mob/source, atom/target, params) . = ..() 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)) return + + if(harmful) + PG.throwforce = punch_damage + else + PG.throwforce = 0 + //has to be low sleep or it looks weird, the beam doesn't exist for very long so it's a non-issue chassis.Beam(PG, icon_state = "chain", time = missile_range * 20, maxdistance = missile_range + 2, beam_sleep_time = 1) @@ -492,5 +520,5 @@ if(!..()) if(ismovable(hit_atom)) var/atom/movable/AM = hit_atom - AM.safe_throw_at(get_edge_target_turf(AM,get_dir(src, AM)), 7, 2) + AM.safe_throw_at(get_edge_target_turf(AM,get_dir(src, AM)), clamp(round(throwforce/5), 2, 20), 2) //Throws them equal to damage/5, with a min range of 2 and max range of 20 qdel(src) diff --git a/code/game/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm similarity index 89% rename from code/game/mecha/mech_bay.dm rename to code/modules/vehicles/mecha/mech_bay.dm index e9f682e929..18149401de 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/modules/vehicles/mecha/mech_bay.dm @@ -5,7 +5,7 @@ icon_state = "recharge_floor" // Some people just want to watch the world burn i guess /turf/open/floor/mech_bay_recharge_floor/break_tile() - ScrapeAway() + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) /turf/open/floor/mech_bay_recharge_floor/airless icon_state = "recharge_floor_asteroid" @@ -19,17 +19,25 @@ 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 var/max_charge = 50 var/on = FALSE - var/repairability = 0 var/turf/recharging_turf = null /obj/machinery/mech_bay_recharge_port/Initialize() . = ..() recharging_turf = get_step(loc, dir) +/obj/machinery/mech_bay_recharge_port/Destroy() + if (recharge_console && recharge_console.recharge_port == src) + recharge_console.recharge_port = null + return ..() + +/obj/machinery/mech_bay_recharge_port/setDir(new_dir) + . = ..() + recharging_turf = get_step(loc, dir) + /obj/machinery/mech_bay_recharge_port/RefreshParts() var/MC for(var/obj/item/stock_parts/capacitor/C in component_parts) @@ -45,7 +53,7 @@ if(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() if(recharging_mech && recharging_mech.cell) @@ -78,8 +86,8 @@ icon_screen = "recharge_comp" icon_keyboard = "rd_key" circuit = /obj/item/circuitboard/computer/mech_bay_power_console - var/obj/machinery/mech_bay_recharge_port/recharge_port light_color = LIGHT_COLOR_PINK + var/obj/machinery/mech_bay_recharge_port/recharge_port /obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -136,3 +144,8 @@ /obj/machinery/computer/mech_bay_power_console/Initialize() . = ..() reconnect() + +/obj/machinery/computer/mech_bay_power_console/Destroy() + if (recharge_port && recharge_port.recharge_console == src) + recharge_port.recharge_console = null + return ..() diff --git a/code/game/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm similarity index 100% rename from code/game/mecha/mech_fabricator.dm rename to code/modules/vehicles/mecha/mech_fabricator.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 0000000000..36a6ed1251 --- /dev/null +++ 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(BURN) + 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 new file mode 100644 index 0000000000..09ccaad2c2 --- /dev/null +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -0,0 +1,275 @@ +/***************** 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/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/vehicle/sealed/mecha/mech_eject + name = "Eject From Mech" + button_icon_state = "mech_eject" + +/datum/action/vehicle/sealed/mecha/mech_eject/Trigger() + if(!owner) + return + if(!chassis || !(owner in chassis.occupants)) + return + chassis.container_resist(owner) + +/datum/action/vehicle/sealed/mecha/mech_toggle_internals + name = "Toggle Internal Airtank Usage" + button_icon_state = "mech_internals_off" + +/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"]" + to_chat(chassis.occupants, "[icon2html(chassis, owner)]Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].") + chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA) + UpdateButtonIcon() + +/datum/action/vehicle/sealed/mecha/mech_cycle_equip + name = "Cycle Equipment" + button_icon_state = "mech_cycle_equip_off" + +/datum/action/vehicle/sealed/mecha/mech_cycle_equip/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) + return + + var/list/available_equipment = list() + for(var/e in chassis.equipment) + var/obj/item/mecha_parts/mecha_equipment/equipment = e + if(equipment.selectable) + available_equipment += equipment + + if(available_equipment.len == 0) + to_chat(owner, "[icon2html(chassis, owner)]No equipment available!") + return + if(!chassis.selected) + chassis.selected = available_equipment[1] + to_chat(owner, "[icon2html(chassis, owner)]You select [chassis.selected].") + 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/equipment in available_equipment) + number++ + if(equipment != chassis.selected) + continue + if(available_equipment.len == number) + chassis.selected = null + to_chat(owner, "[icon2html(chassis, owner)]You switch to no equipment.") + button_icon_state = "mech_cycle_equip_off" + else + chassis.selected = available_equipment[number+1] + to_chat(owner, "[icon2html(chassis, owner)]You switch 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/vehicle/sealed/mecha/mech_toggle_lights/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) + return + if(!(chassis.mecha_flags & HAS_LIGHTS)) + to_chat(owner, "This mechs lights are destroyed!") + return + chassis.mecha_flags ^= LIGHTS_ON + if(chassis.mecha_flags & LIGHTS_ON) + button_icon_state = "mech_lights_on" + chassis.set_light(5, 5) + else + button_icon_state = "mech_lights_off" + chassis.set_light(0) + to_chat(owner, "[icon2html(chassis, 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/vehicle/sealed/mecha/mech_view_stats + name = "View Stats" + button_icon_state = "mech_view_stats" + +/datum/action/vehicle/sealed/mecha/mech_view_stats/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) + return + var/datum/browser/popup = new(owner , "exosuit") + popup.set_content(chassis.get_stats_html(owner)) + popup.open() + + +/datum/action/vehicle/sealed/mecha/strafe + name = "Toggle Strafing. Disabled when Alt is held." + button_icon_state = "strafe" + +/datum/action/vehicle/sealed/mecha/strafe/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) + return + chassis.toggle_strafe() + +/obj/vehicle/sealed/mecha/AltClick(mob/living/user) + if(!(user in occupants) || !user.canUseTopic(src)) + return + if(!(user in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE))) + to_chat(user, "You're in the wrong seat to control movement.") + return + + toggle_strafe() + +/obj/vehicle/sealed/mecha/proc/toggle_strafe() + strafe = !strafe + + to_chat(occupants, "[icon2html(src, occupants)]Toggled strafing mode [strafe?"on":"off"].") + log_message("Toggled strafing mode [strafe?"on":"off"].", LOG_MECHA) + + 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/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" + +/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/vehicle/sealed/mecha/mech_overload_mode + name = "Toggle leg actuators overload" + button_icon_state = "mech_overload_off" + +/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 + else + chassis.leg_overload_mode = !chassis.leg_overload_mode + chassis.log_message("Toggled leg actuators overload.", LOG_MECHA) + if(!chassis.leg_overload_mode) + button_icon_state = "mech_overload_on" + chassis.bumpsmash = TRUE + 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) + to_chat(owner, "[icon2html(chassis, owner)]You enable leg actuators overload.") + else + button_icon_state = "mech_overload_off" + chassis.bumpsmash = FALSE + chassis.movedelay = initial(chassis.movedelay) + chassis.step_energy_drain = chassis.normal_step_energy_drain + to_chat(owner, "[icon2html(chassis, owner)]You disable leg actuators overload.") + UpdateButtonIcon() + +/datum/action/vehicle/sealed/mecha/mech_smoke + name = "Smoke" + button_icon_state = "mech_smoke" + +/datum/action/vehicle/sealed/mecha/mech_smoke/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) + return + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_SMOKE) && chassis.smoke_charges>0) + chassis.smoke_system.start() + chassis.smoke_charges-- + TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_SMOKE, chassis.smoke_cooldown) + + +/datum/action/vehicle/sealed/mecha/mech_zoom + name = "Zoom" + button_icon_state = "mech_zoom_off" + +/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 + button_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]" + chassis.log_message("Toggled zoom mode.", LOG_MECHA) + to_chat(owner, "[icon2html(chassis, owner)]Zoom mode [chassis.zoom_mode?"en":"dis"]abled.") + if(chassis.zoom_mode) + owner.client.view_size.setTo(4.5) + SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50)) + else + owner.client.view_size.resetToDefault() //Let's not let this stack shall we? + UpdateButtonIcon() + +/datum/action/vehicle/sealed/mecha/mech_switch_damtype + name = "Reconfigure arm microtool arrays" + button_icon_state = "mech_damtype_brute" + +/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" + 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(chassis, 'sound/mecha/mechmove01.ogg', 50, TRUE) + UpdateButtonIcon() + +///swap seats, for two person mecha +/datum/action/vehicle/sealed/mecha/swap_seat + name = "Switch Seats" + button_icon_state = "mech_seat_swap" + +/datum/action/vehicle/sealed/mecha/swap_seat/Trigger() + if(!owner || !chassis || !(owner in chassis.occupants)) + return + + if(chassis.occupants.len == chassis.max_occupants) + to_chat(owner, "The other seat is occupied!") + return + var/list/drivers = chassis.return_drivers() + to_chat(owner, "Switching seats...") + chassis.is_currently_ejecting = TRUE + if(!do_after(owner, chassis.has_gravity() ? chassis.exit_delay : 0 , target = chassis)) + chassis.is_currently_ejecting = FALSE + return + chassis.is_currently_ejecting = FALSE + if(owner in drivers) + to_chat(owner, "You shift to the gunner seat!") + chassis.remove_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + chassis.add_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + else + to_chat(owner, "You shift to the pilot seat!") + chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + chassis.update_icon_state() + +/datum/action/vehicle/sealed/mecha/mech_toggle_phasing + name = "Toggle Phasing" + button_icon_state = "mech_phasing_off" + +/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"]" + to_chat(owner, "[icon2html(chassis, owner)]En":"#f00\">Dis"]abled phasing.") + UpdateButtonIcon() diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm new file mode 100644 index 0000000000..d0fa7aca0b --- /dev/null +++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm @@ -0,0 +1,1608 @@ +//////////////////////////////// +///// Construction datums ////// +//////////////////////////////// +/datum/component/construction/mecha + var/base_icon + + // Component typepaths. + // most must be defined unless + // get_steps is overriden. + + // Circuit board typepaths. + // circuit_control and circuit_periph must be defined + // unless get_circuit_steps is overriden. + var/circuit_control + var/circuit_periph + var/circuit_weapon + + // Armor plating typepaths. both must be defined + // unless relevant step procs are overriden. amounts + // must be defined if using /obj/item/stack/sheet types + var/inner_plating + var/inner_plating_amount + + var/outer_plating + var/outer_plating_amount + +/datum/component/construction/mecha/spawn_result() + if(!result) + return + // Remove default mech power cell, as we replace it with a new one. + var/obj/vehicle/sealed/mecha/M = new result(drop_location()) + QDEL_NULL(M.cell) + QDEL_NULL(M.scanmod) + QDEL_NULL(M.capacitor) + + var/obj/item/mecha_parts/chassis/parent_chassis = parent + M.CheckParts(parent_chassis.contents) + + SSblackbox.record_feedback("tally", "mechas_created", 1, M.name) + QDEL_NULL(parent) + +// Default proc to generate mech steps. +// Override if the mech needs an entirely custom process (See HONK mech) +// Otherwise override specific steps as needed (Ripley, Clarke, Phazon) +/datum/component/construction/mecha/proc/get_steps() + return get_frame_steps() + get_circuit_steps() + (circuit_weapon ? get_circuit_weapon_steps() : list()) + get_stockpart_steps() + get_inner_plating_steps() + get_outer_plating_steps() + +/datum/component/construction/mecha/update_parent(step_index) + steps = get_steps() + ..() + // By default, each step in mech construction has a single icon_state: + // "[base_icon][index - 1]" + // For example, Ripley's step 1 icon_state is "ripley0". + var/atom/parent_atom = parent + if(!steps[index]["icon_state"] && base_icon) + parent_atom.icon_state = "[base_icon][index - 1]" + +/datum/component/construction/unordered/mecha_chassis/custom_action(obj/item/I, mob/living/user, typepath) + . = user.transferItemToLoc(I, parent) + if(.) + var/atom/parent_atom = parent + user.visible_message("[user] connects [I] to [parent].", "You connect [I] to [parent].") + parent_atom.add_overlay(I.icon_state+"+o") + qdel(I) + +/datum/component/construction/unordered/mecha_chassis/spawn_result() + var/atom/parent_atom = parent + parent_atom.icon = 'icons/mecha/mech_construction.dmi' + parent_atom.density = TRUE + parent_atom.cut_overlays() + ..() + +// Default proc for the first steps of mech construction. +/datum/component/construction/mecha/proc/get_frame_steps() + return list( + list( + "key" = TOOL_WRENCH, + "desc" = "The hydraulic systems are disconnected." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_WRENCH, + "desc" = "The hydraulic systems are connected." + ), + list( + "key" = /obj/item/stack/cable_coil, + "amount" = 5, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The hydraulic systems are active." + ), + list( + "key" = TOOL_WIRECUTTER, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The wiring is added." + ) + ) + +// Default proc for the circuit board steps of a mech. +// Second set of steps by default. +/datum/component/construction/mecha/proc/get_circuit_steps() + return list( + list( + "key" = circuit_control, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The wiring is adjusted." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Central control module is installed." + ), + list( + "key" = circuit_periph, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Central control module is secured." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Peripherals control module is installed." + ) + ) + +// Default proc for weapon circuitboard steps +// Used by combat mechs +/datum/component/construction/mecha/proc/get_circuit_weapon_steps() + return list( + list( + "key" = circuit_weapon, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Peripherals control module is secured." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Weapons control module is installed." + ) + ) + +// Default proc for stock part installation +// Third set of steps by default +/datum/component/construction/mecha/proc/get_stockpart_steps() + var/prevstep_text = circuit_weapon ? "Weapons control module is secured." : "Peripherals control module is secured." + return list( + list( + "key" = /obj/item/stock_parts/scanning_module, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = prevstep_text + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Scanner module is installed." + ), + list( + "key" = /obj/item/stock_parts/capacitor, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Scanner module is secured." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Capacitor is installed." + ), + list( + "key" = /obj/item/stock_parts/cell, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Capacitor is secured." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "The power cell is installed." + ) + ) + +// Default proc for inner armor plating +// Fourth set of steps by default +/datum/component/construction/mecha/proc/get_inner_plating_steps() + var/list/first_step + if(ispath(inner_plating, /obj/item/stack/sheet)) + first_step = list( + list( + "key" = inner_plating, + "amount" = inner_plating_amount, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The power cell is secured." + ) + ) + else + first_step = list( + list( + "key" = inner_plating, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The power cell is secured." + ) + ) + + return first_step + list( + list( + "key" = TOOL_WRENCH, + "back_key" = TOOL_CROWBAR, + "desc" = "Inner plating is installed." + ), + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WRENCH, + "desc" = "Inner Plating is wrenched." + ) + ) + +// Default proc for outer armor plating +// Fifth set of steps by default +/datum/component/construction/mecha/proc/get_outer_plating_steps() + var/list/first_step + if(ispath(outer_plating, /obj/item/stack/sheet)) + first_step = list( + list( + "key" = outer_plating, + "amount" = outer_plating_amount, + "back_key" = TOOL_WELDER, + "desc" = "Inner plating is welded." + ) + ) + else + first_step = list( + list( + "key" = outer_plating, + "action" = ITEM_DELETE, + "back_key" = TOOL_WELDER, + "desc" = "Inner plating is welded." + ) + ) + + return first_step + list( + list( + "key" = TOOL_WRENCH, + "back_key" = TOOL_CROWBAR, + "desc" = "External armor is installed." + ), + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WRENCH, + "desc" = "External armor is wrenched." + ) + ) + + +/datum/component/construction/unordered/mecha_chassis/ripley + result = /datum/component/construction/mecha/ripley + steps = list( + /obj/item/mecha_parts/part/ripley_torso, + /obj/item/mecha_parts/part/ripley_left_arm, + /obj/item/mecha_parts/part/ripley_right_arm, + /obj/item/mecha_parts/part/ripley_left_leg, + /obj/item/mecha_parts/part/ripley_right_leg + ) + +/datum/component/construction/mecha/ripley + result = /obj/vehicle/sealed/mecha/working/ripley + base_icon = "ripley" + + circuit_control = /obj/item/circuitboard/mecha/ripley/main + circuit_periph = /obj/item/circuitboard/mecha/ripley/peripherals + + inner_plating=/obj/item/stack/sheet/metal + inner_plating_amount = 5 + + outer_plating=/obj/item/stack/rods + outer_plating_amount = 10 + +/datum/component/construction/mecha/ripley/get_outer_plating_steps() + return list( + list( + "key" = /obj/item/stack/rods, + "amount" = 10, + "back_key" = TOOL_WELDER, + "desc" = "Outer Plating is welded." + ), + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WIRECUTTER, + "desc" = "Cockpit wire screen is installed." + ), + ) + +/datum/component/construction/mecha/ripley/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems.", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems.", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures [I].", "You secure [I].") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I].", "You install [I].") + else + user.visible_message("[user] unsecures the capacitor from [parent].", "You unsecure the capacitor from [parent].") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(16) + if(diff==FORWARD) + user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(18) + if(diff==FORWARD) + user.visible_message("[user] installs the external reinforced armor layer to [parent].", "You install the external reinforced armor layer to [parent].") + else + user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") + if(19) + if(diff==FORWARD) + user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.") + else + user.visible_message("[user] pries external armor layer from [parent].", "You pry external armor layer from [parent].") + if(20) + if(diff==FORWARD) + user.visible_message("[user] welds the external armor layer to [parent].", "You weld the external armor layer to [parent].") + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + return TRUE + +/datum/component/construction/unordered/mecha_chassis/gygax + result = /datum/component/construction/mecha/gygax + steps = list( + /obj/item/mecha_parts/part/gygax_torso, + /obj/item/mecha_parts/part/gygax_left_arm, + /obj/item/mecha_parts/part/gygax_right_arm, + /obj/item/mecha_parts/part/gygax_left_leg, + /obj/item/mecha_parts/part/gygax_right_leg, + /obj/item/mecha_parts/part/gygax_head + ) + +/datum/component/construction/mecha/gygax + result = /obj/vehicle/sealed/mecha/combat/gygax + base_icon = "gygax" + + circuit_control = /obj/item/circuitboard/mecha/gygax/main + circuit_periph = /obj/item/circuitboard/mecha/gygax/peripherals + circuit_weapon = /obj/item/circuitboard/mecha/gygax/targeting + + inner_plating = /obj/item/stack/sheet/metal + inner_plating_amount = 5 + + outer_plating=/obj/item/mecha_parts/part/gygax_armor + outer_plating_amount=1 + +/datum/component/construction/mecha/gygax/action(datum/source, atom/used_atom, mob/user) + return check_step(used_atom,user) + +/datum/component/construction/mecha/gygax/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems.", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems.", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") + else + user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") + if(16) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(18) + if(diff==FORWARD) + user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") + if(19) + if(diff==FORWARD) + user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(20) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") + if(21) + if(diff==FORWARD) + user.visible_message("[user] secures Gygax Armor Plates.", "You secure Gygax Armor Plates.") + else + user.visible_message("[user] pries Gygax Armor Plates from [parent].", "You pry Gygax Armor Plates from [parent].") + if(22) + if(diff==FORWARD) + user.visible_message("[user] welds Gygax Armor Plates to [parent].", "You weld Gygax Armor Plates to [parent].") + else + user.visible_message("[user] unfastens Gygax Armor Plates.", "You unfasten Gygax Armor Plates.") + return TRUE + +//Begin Medigax +/datum/component/construction/unordered/mecha_chassis/medigax + result = /datum/component/construction/mecha/medigax + steps = list( + /obj/item/mecha_parts/part/medigax_torso, + /obj/item/mecha_parts/part/medigax_left_arm, + /obj/item/mecha_parts/part/medigax_right_arm, + /obj/item/mecha_parts/part/medigax_left_leg, + /obj/item/mecha_parts/part/medigax_right_leg, + /obj/item/mecha_parts/part/medigax_head + ) + +/datum/component/construction/mecha/medigax + result = /obj/vehicle/sealed/mecha/medical/medigax + base_icon = "medigax" + steps = list( + //1 + list( + "key" = TOOL_WRENCH, + "desc" = "The hydraulic systems are disconnected." + ), + + //2 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_WRENCH, + "desc" = "The hydraulic systems are connected." + ), + + //3 + list( + "key" = /obj/item/stack/cable_coil, + "amount" = 5, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The hydraulic systems are active." + ), + + //4 + list( + "key" = TOOL_WIRECUTTER, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The wiring is added." + ), + + //5 + list( + "key" = /obj/item/circuitboard/mecha/gygax/main, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The wiring is adjusted." + ), + + //6 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Central control module is installed." + ), + + //7 + list( + "key" = /obj/item/circuitboard/mecha/gygax/peripherals, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Central control module is secured." + ), + + //8 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Peripherals control module is installed." + ), + + //9 + list( + "key" = /obj/item/circuitboard/mecha/gygax/targeting, + "action" = ITEM_DELETE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Peripherals control module is secured." + ), + + //10 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Weapon control module is installed." + ), + + //11 + list( + "key" = /obj/item/stock_parts/scanning_module, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Weapon control module is secured." + ), + + //12 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Scanner module is installed." + ), + + //13 + list( + "key" = /obj/item/stock_parts/capacitor, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Scanner module is secured." + ), + + //14 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Capacitor is installed." + ), + + //15 + list( + "key" = /obj/item/stock_parts/cell, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Capacitor is secured." + ), + + //16 + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "The power cell is installed." + ), + + //17 + list( + "key" = /obj/item/stack/sheet/metal, + "amount" = 5, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The power cell is secured." + ), + + //18 + list( + "key" = TOOL_WRENCH, + "back_key" = TOOL_CROWBAR, + "desc" = "Internal armor is installed." + ), + + //19 + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WRENCH, + "desc" = "Internal armor is wrenched." + ), + + //20 + list( + "key" = /obj/item/mecha_parts/part/medigax_armor, + "action" = ITEM_DELETE, + "back_key" = TOOL_WELDER, + "desc" = "Internal armor is welded." + ), + + //21 + list( + "key" = TOOL_WRENCH, + "back_key" = TOOL_CROWBAR, + "desc" = "External armor is installed." + ), + + //22 + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WRENCH, + "desc" = "External armor is wrenched." + ), + + ) + +/datum/component/construction/mecha/medigax/action(datum/source, atom/used_atom, mob/user) + return check_step(used_atom,user) + +/datum/component/construction/mecha/medigax/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") + else + user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") + if(16) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(18) + if(diff==FORWARD) + user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") + if(19) + if(diff==FORWARD) + user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(20) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") + if(21) + if(diff==FORWARD) + user.visible_message("[user] secures Gygax Armor Plates.", "You secure Medical Gygax Armor Plates.") + else + user.visible_message("[user] pries Gygax Armor Plates from [parent].", "You pry Medical Gygax Armor Plates from [parent].") + if(22) + if(diff==FORWARD) + user.visible_message("[user] welds Gygax Armor Plates to [parent].", "You weld Medical Gygax Armor Plates to [parent].") + else + user.visible_message("[user] unfastens Gygax Armor Plates.", "You unfasten Medical Gygax Armor Plates.") + return TRUE +// End Medigax + +/datum/component/construction/unordered/mecha_chassis/firefighter + result = /datum/component/construction/mecha/firefighter + steps = list( + /obj/item/mecha_parts/part/ripley_torso, + /obj/item/mecha_parts/part/ripley_left_arm, + /obj/item/mecha_parts/part/ripley_right_arm, + /obj/item/mecha_parts/part/ripley_left_leg, + /obj/item/mecha_parts/part/ripley_right_leg + ) + +/datum/component/construction/mecha/firefighter + result = /obj/vehicle/sealed/mecha/working/ripley/firefighter + base_icon = "firefighter" + + circuit_control = /obj/item/circuitboard/mecha/ripley/main + circuit_periph = /obj/item/circuitboard/mecha/ripley/peripherals + + inner_plating= /obj/item/clothing/suit/fire + inner_plating_amount = 1 + + outer_plating=/obj/item/stack/sheet/plasteel + outer_plating_amount = 10 + +/datum/component/construction/mecha/firefighter/get_outer_plating_steps() + return list( + list( + "key" = /obj/item/stack/sheet/plasteel, + "amount" = 10, + "back_key" = TOOL_WELDER, + "desc" = "Outer plating is welded." + ), + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WRENCH, + "desc" = "Outer plating is complete." + ), + ) + +/datum/component/construction/mecha/firefighter/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems.", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems.", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures [I].", "You secure [I].") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I].", "You install [I].") + else + user.visible_message("[user] unsecures the capacitor from [parent].", "You unsecure the capacitor from [parent].") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(16) + if(diff==FORWARD) + user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(18) + if(diff==FORWARD) + user.visible_message("[user] installs the external reinforced armor layer to [parent].", "You install the external reinforced armor layer to [parent].") + else + user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") + if(19) + if(diff==FORWARD) + user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.") + else + user.visible_message("[user] pries external armor layer from [parent].", "You pry external armor layer from [parent].") + if(20) + if(diff==FORWARD) + user.visible_message("[user] welds the external armor layer to [parent].", "You weld the external armor layer to [parent].") + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + return TRUE + +/datum/component/construction/unordered/mecha_chassis/honker + result = /datum/component/construction/mecha/honker + steps = list( + /obj/item/mecha_parts/part/honker_torso, + /obj/item/mecha_parts/part/honker_left_arm, + /obj/item/mecha_parts/part/honker_right_arm, + /obj/item/mecha_parts/part/honker_left_leg, + /obj/item/mecha_parts/part/honker_right_leg, + /obj/item/mecha_parts/part/honker_head + ) + +/datum/component/construction/mecha/honker + result = /obj/vehicle/sealed/mecha/combat/honker + steps = list( + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/circuitboard/mecha/honker/main, + "action" = ITEM_DELETE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/circuitboard/mecha/honker/peripherals, + "action" = ITEM_DELETE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/circuitboard/mecha/honker/targeting, + "action" = ITEM_DELETE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/stock_parts/scanning_module, + "action" = ITEM_MOVE_INSIDE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/stock_parts/capacitor, + "action" = ITEM_MOVE_INSIDE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/stock_parts/cell, + "action" = ITEM_MOVE_INSIDE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/clothing/mask/gas/clown_hat, + "action" = ITEM_DELETE + ), + list( + "key" = /obj/item/bikehorn + ), + list( + "key" = /obj/item/clothing/shoes/clown_shoes, + "action" = ITEM_DELETE + ), + list( + "key" = /obj/item/bikehorn + ), + ) + +/datum/component/construction/mecha/honker/get_steps() + return steps + +// HONK doesn't have any construction step icons, so we just set an icon once. +/datum/component/construction/mecha/honker/update_parent(step_index) + if(step_index == 1) + var/atom/parent_atom = parent + parent_atom.icon = 'icons/mecha/mech_construct.dmi' + parent_atom.icon_state = "honker_chassis" + ..() + +/datum/component/construction/mecha/honker/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + if(istype(I, /obj/item/bikehorn)) + playsound(parent, 'sound/items/bikehorn.ogg', 50, TRUE) + user.visible_message("HONK!") + + //TODO: better messages. + switch(index) + if(2) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + if(4) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + if(6) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + if(8) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + if(10) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + if(12) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + if(14) + user.visible_message("[user] puts [I] on [parent].", "You put [I] on [parent].") + if(16) + user.visible_message("[user] puts [I] on [parent].", "You put [I] on [parent].") + return TRUE + +/datum/component/construction/unordered/mecha_chassis/durand + result = /datum/component/construction/mecha/durand + steps = list( + /obj/item/mecha_parts/part/durand_torso, + /obj/item/mecha_parts/part/durand_left_arm, + /obj/item/mecha_parts/part/durand_right_arm, + /obj/item/mecha_parts/part/durand_left_leg, + /obj/item/mecha_parts/part/durand_right_leg, + /obj/item/mecha_parts/part/durand_head + ) + +/datum/component/construction/mecha/durand + result = /obj/vehicle/sealed/mecha/combat/durand + base_icon = "durand" + + circuit_control = /obj/item/circuitboard/mecha/durand/main + circuit_periph = /obj/item/circuitboard/mecha/durand/peripherals + circuit_weapon = /obj/item/circuitboard/mecha/durand/targeting + + inner_plating = /obj/item/stack/sheet/metal + inner_plating_amount = 5 + + outer_plating = /obj/item/mecha_parts/part/durand_armor + outer_plating_amount = 1 + +/datum/component/construction/mecha/durand/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + //TODO: better messages. + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems.", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems.", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") + else + user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") + if(16) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(18) + if(diff==FORWARD) + user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") + if(19) + if(diff==FORWARD) + user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(20) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") + if(21) + if(diff==FORWARD) + user.visible_message("[user] secures Durand Armor Plates.", "You secure Durand Armor Plates.") + else + user.visible_message("[user] pries Durand Armor Plates from [parent].", "You pry Durand Armor Plates from [parent].") + if(22) + if(diff==FORWARD) + user.visible_message("[user] welds Durand Armor Plates to [parent].", "You weld Durand Armor Plates to [parent].") + else + user.visible_message("[user] unfastens Durand Armor Plates.", "You unfasten Durand Armor Plates.") + return TRUE + +//PHAZON + +/datum/component/construction/unordered/mecha_chassis/phazon + result = /datum/component/construction/mecha/phazon + steps = list( + /obj/item/mecha_parts/part/phazon_torso, + /obj/item/mecha_parts/part/phazon_left_arm, + /obj/item/mecha_parts/part/phazon_right_arm, + /obj/item/mecha_parts/part/phazon_left_leg, + /obj/item/mecha_parts/part/phazon_right_leg, + /obj/item/mecha_parts/part/phazon_head + ) + +/datum/component/construction/mecha/phazon + result = /obj/vehicle/sealed/mecha/combat/phazon + base_icon = "phazon" + + circuit_control = /obj/item/circuitboard/mecha/phazon/main + circuit_periph = /obj/item/circuitboard/mecha/phazon/peripherals + circuit_weapon = /obj/item/circuitboard/mecha/phazon/targeting + + inner_plating = /obj/item/stack/sheet/plasteel + inner_plating_amount = 5 + + outer_plating = /obj/item/mecha_parts/part/phazon_armor + outer_plating_amount = 1 + +/datum/component/construction/mecha/phazon/get_stockpart_steps() + return list( + list( + "key" = /obj/item/stock_parts/scanning_module, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Weapon control module is secured." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Scanner module is installed." + ), + list( + "key" = /obj/item/stock_parts/capacitor, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Scanner module is secured." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "Capacitor is installed." + ), + list( + "key" = /obj/item/stack/ore/bluespace_crystal, + "amount" = 1, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "Capacitor is secured." + ), + list( + "key" = /obj/item/stack/cable_coil, + "amount" = 5, + "back_key" = TOOL_CROWBAR, + "desc" = "The bluespace crystal is installed." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_WIRECUTTER, + "desc" = "The bluespace crystal is connected." + ), + list( + "key" = /obj/item/stock_parts/cell, + "action" = ITEM_MOVE_INSIDE, + "back_key" = TOOL_SCREWDRIVER, + "desc" = "The bluespace crystal is engaged." + ), + list( + "key" = TOOL_SCREWDRIVER, + "back_key" = TOOL_CROWBAR, + "desc" = "The power cell is installed.", + "icon_state" = "phazon17" + // This is the point where a step icon is skipped, so "icon_state" had to be set manually starting from here. + ) + ) + +/datum/component/construction/mecha/phazon/get_outer_plating_steps() + return list( + list( + "key" = outer_plating, + "amount" = 1, + "action" = ITEM_DELETE, + "back_key" = TOOL_WELDER, + "desc" = "Internal armor is welded." + ), + list( + "key" = TOOL_WRENCH, + "back_key" = TOOL_CROWBAR, + "desc" = "External armor is installed." + ), + list( + "key" = TOOL_WELDER, + "back_key" = TOOL_WRENCH, + "desc" = "External armor is wrenched." + ), + list( + "key" = /obj/item/assembly/signaler/anomaly/bluespace, + "action" = ITEM_DELETE, + "back_key" = TOOL_WELDER, + "desc" = "Bluespace anomaly core socket is open.", + "icon_state" = "phazon24" + ) + ) + +/datum/component/construction/mecha/phazon/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + //TODO: better messages. + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems.", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems.", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") + else + user.visible_message("[user] removes the weapon control module from [parent].", "You remove the weapon control module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs [I].", "You install [I].") + else + user.visible_message("[user] unsecures the capacitor from [parent].", "You unsecure the capacitor from [parent].") + if(16) + if(diff==FORWARD) + user.visible_message("[user] connects the bluespace crystal.", "You connect the bluespace crystal.") + else + user.visible_message("[user] removes the bluespace crystal from [parent].", "You remove the bluespace crystal from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] engages the bluespace crystal.", "You engage the bluespace crystal.") + else + user.visible_message("[user] disconnects the bluespace crystal from [parent].", "You disconnect the bluespace crystal from [parent].") + if(18) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disengages the bluespace crystal.", "You disengage the bluespace crystal.") + if(19) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(20) + if(diff==FORWARD) + user.visible_message("[user] installs the phase armor layer to [parent].", "You install the phase armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(21) + if(diff==FORWARD) + user.visible_message("[user] secures the phase armor layer.", "You secure the phase armor layer.") + else + user.visible_message("[user] pries the phase armor layer from [parent].", "You pry the phase armor layer from [parent].") + if(22) + if(diff==FORWARD) + user.visible_message("[user] welds the phase armor layer to [parent].", "You weld the phase armor layer to [parent].") + else + user.visible_message("[user] unfastens the phase armor layer.", "You unfasten the phase armor layer.") + if(23) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] cuts phase armor layer from [parent].", "You cut the phase armor layer from [parent].") + if(24) + if(diff==FORWARD) + user.visible_message("[user] secures Phazon Armor Plates.", "You secure Phazon Armor Plates.") + else + user.visible_message("[user] pries Phazon Armor Plates from [parent].", "You pry Phazon Armor Plates from [parent].") + if(25) + if(diff==FORWARD) + user.visible_message("[user] welds Phazon Armor Plates to [parent].", "You weld Phazon Armor Plates to [parent].") + else + user.visible_message("[user] unfastens Phazon Armor Plates.", "You unfasten Phazon Armor Plates.") + if(26) + if(diff==FORWARD) + user.visible_message("[user] carefully inserts the bluespace anomaly core into [parent] and secures it.", + "You slowly place the bluespace anomaly core into its socket and close its chamber.") + return TRUE + +//ODYSSEUS + +/datum/component/construction/unordered/mecha_chassis/odysseus + result = /datum/component/construction/mecha/odysseus + steps = list( + /obj/item/mecha_parts/part/odysseus_torso, + /obj/item/mecha_parts/part/odysseus_head, + /obj/item/mecha_parts/part/odysseus_left_arm, + /obj/item/mecha_parts/part/odysseus_right_arm, + /obj/item/mecha_parts/part/odysseus_left_leg, + /obj/item/mecha_parts/part/odysseus_right_leg + ) + +/datum/component/construction/mecha/odysseus + result = /obj/vehicle/sealed/mecha/medical/odysseus + base_icon = "odysseus" + + circuit_control = /obj/item/circuitboard/mecha/odysseus/main + circuit_periph = /obj/item/circuitboard/mecha/odysseus/peripherals + + inner_plating = /obj/item/stack/sheet/metal + inner_plating_amount = 5 + + outer_plating = /obj/item/stack/sheet/plasteel + outer_plating_amount = 5 + +/datum/component/construction/mecha/odysseus/custom_action(obj/item/I, mob/living/user, diff) + if(!..()) + return FALSE + + //TODO: better messages. + switch(index) + if(1) + user.visible_message("[user] connects [parent] hydraulic systems.", "You connect [parent] hydraulic systems.") + if(2) + if(diff==FORWARD) + user.visible_message("[user] activates [parent] hydraulic systems.", "You activate [parent] hydraulic systems.") + else + user.visible_message("[user] disconnects [parent] hydraulic systems.", "You disconnect [parent] hydraulic systems.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [parent].", "You add the wiring to [parent].") + else + user.visible_message("[user] deactivates [parent] hydraulic systems.", "You deactivate [parent] hydraulic systems.") + if(4) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [parent].", "You adjust the wiring of [parent].") + else + user.visible_message("[user] removes the wiring from [parent].", "You remove the wiring from [parent].") + if(5) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] disconnects the wiring of [parent].", "You disconnect the wiring of [parent].") + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [parent].", "You remove the central computer mainboard from [parent].") + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [parent].", "You remove the peripherals control module from [parent].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the scanner module.", "You secure the scanner module.") + else + user.visible_message("[user] removes the scanner module from [parent].", "You remove the scanner module from [parent].") + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs [I] to [parent].", "You install [I] to [parent].") + else + user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] secures the capacitor.", "You secure the capacitor.") + else + user.visible_message("[user] removes the capacitor from [parent].", "You remove the capacitor from [parent].") + if(13) + if(diff==FORWARD) + user.visible_message("[user] installs [I] into [parent].", "You install [I] into [parent].") + else + user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.") + if(14) + if(diff==FORWARD) + user.visible_message("[user] secures the power cell.", "You secure the power cell.") + else + user.visible_message("[user] pries the power cell from [parent].", "You pry the power cell from [parent].") + if(15) + if(diff==FORWARD) + user.visible_message("[user] installs the internal armor layer to [parent].", "You install the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.") + if(16) + if(diff==FORWARD) + user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [parent].", "You pry internal armor layer from [parent].") + if(17) + if(diff==FORWARD) + user.visible_message("[user] welds the internal armor layer to [parent].", "You weld the internal armor layer to [parent].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(18) + if(diff==FORWARD) + user.visible_message("[user] installs the external armor layer to [parent].", "You install the external reinforced armor layer to [parent].") + else + user.visible_message("[user] cuts the internal armor layer from [parent].", "You cut the internal armor layer from [parent].") + if(19) + if(diff==FORWARD) + user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.") + else + user.visible_message("[user] pries the external armor layer from [parent].", "You pry the external armor layer from [parent].") + if(20) + if(diff==FORWARD) + user.visible_message("[user] welds the external armor layer to [parent].", "You weld the external armor layer to [parent].") + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + return TRUE diff --git a/code/game/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm similarity index 77% rename from code/game/mecha/mecha_control_console.dm rename to code/modules/vehicles/mecha/mecha_control_console.dm index ab547f4ccd..38224fbbdd 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/modules/vehicles/mecha/mecha_control_console.dm @@ -16,29 +16,29 @@ 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 = list(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((LAZYLEN(RM.cargo) / RM.cargo_capacity) * 100) + cargo_space = round((RM.cargo.len / RM.cargo_capacity) * 100) ) data["mechs"] += list(mech_data) @@ -46,8 +46,7 @@ return data /obj/machinery/computer/mecha/ui_act(action, params) - . = ..() - if(.) + if(..()) return switch(action) @@ -56,20 +55,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) - to_chat(M.occupant, 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 [M.occupant ? "has the occupants [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 ? "occupied by [M.occupant][ADMIN_FLW(M)]." : "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 @@ -83,11 +82,11 @@ /// 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 - */ + * Returns a html formatted string describing attached mech status + */ /obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info() if(!chassis) return FALSE @@ -97,12 +96,12 @@ 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 - answer += "
Used Cargo Space: [round((LAZYLEN(RM.cargo) / RM.cargo_capacity * 100), 0.01)]%" + 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 @@ -118,7 +117,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(!..()) return M.trackers += src @@ -126,8 +125,8 @@ chassis = M /** - * Attempts to EMP mech that the tracker is attached to, if there is one and tracker is not on cooldown - */ + * Attempts to EMP mech that the tracker is attached to, if there is one and tracker is not on cooldown + */ /obj/item/mecha_parts/mecha_tracking/proc/shock() if(recharging) return @@ -137,8 +136,8 @@ recharging = TRUE /** - * Resets recharge variable, allowing tracker to be EMP pulsed again - */ + * Resets recharge variable, allowing tracker to be EMP pulsed again + */ /obj/item/mecha_parts/mecha_tracking/proc/recharge() recharging = FALSE diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm new file mode 100644 index 0000000000..39a1b74709 --- /dev/null +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -0,0 +1,390 @@ +/obj/vehicle/sealed/mecha/proc/get_armour_facing(relative_dir) + switch(relative_dir) + if(180) // BACKSTAB! + return facing_modifiers[MECHA_BACK_ARMOUR] + if(0, 45) // direct or 45 degrees off + return facing_modifiers[MECHA_FRONT_ARMOUR] + return facing_modifiers[MECHA_SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side + +/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() + switch(damage_flag) + if(FIRE) + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL)) + if(MELEE) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + else + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT)) + if(. >= 5 || prob(33)) + to_chat(occupants, "[icon2html(src, occupants)]Taking damage!") + log_message("Took [damage_amount] points of damage. Damage type: [damage_type]", LOG_MECHA) + +/obj/vehicle/sealed/mecha/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) + . = ..() + if(!damage_amount) + return 0 + var/booster_deflection_modifier = 1 + var/booster_damage_modifier = 1 + if(damage_flag == BULLET || damage_flag == LASER || damage_flag == ENERGY) + for(var/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/B in equipment) + if(B.projectile_react()) + booster_deflection_modifier = B.deflect_coeff + booster_damage_modifier = B.damage_coeff + break + else if(damage_flag == MELEE) + for(var/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/B in equipment) + if(B.attack_react()) + booster_deflection_modifier *= B.deflect_coeff + booster_damage_modifier *= B.damage_coeff + break + + if(attack_dir) + var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir))) + booster_damage_modifier /= facing_modifier + booster_deflection_modifier *= facing_modifier + if(prob(deflect_chance * booster_deflection_modifier)) + visible_message("[src]'s armour deflects the attack!") + log_message("Armor saved.", LOG_MECHA) + return 0 + if(.) + . *= booster_damage_modifier + +/obj/vehicle/sealed/mecha/attack_hand(mob/living/user) + . = ..() + if(.) + return + user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) + playsound(loc, 'sound/weapons/tap.ogg', 40, TRUE, -1) + 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/vehicle/sealed/mecha/attack_paw(mob/user as mob) + return attack_hand(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, TRUE) + attack_generic(user, 15, BRUTE, MELEE, 0) + +/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_upper && !user.obj_damage) + user.emote("custom", message = "[user.friendly_verb_continuous] [src].") + return 0 + else + var/play_soundeffect = 1 + if(user.environment_smash) + play_soundeffect = 0 + playsound(src, 'sound/effects/bang.ogg', 50, TRUE) + var/animal_damage = rand(user.melee_damage_lower,user.melee_damage_upper) + if(user.obj_damage) + animal_damage = user.obj_damage + animal_damage = min(animal_damage, 20*user.environment_smash) + log_combat(user, src, "attacked") + attack_generic(user, animal_damage, user.melee_damage_type, MELEE, play_soundeffect) + return 1 + + +/obj/vehicle/sealed/mecha/hulk_damage() + return 15 + +/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/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/vehicle/sealed/mecha/attack_tk() + return + +/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/vehicle/sealed/mecha/bullet_act(obj/item/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.flag]).", LOG_MECHA, color="red") + . = ..() + +/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/vehicle/sealed/mecha/contents_explosion(severity, target, origin) + severity++ + for(var/X in equipment) + var/obj/item/mecha_parts/mecha_equipment/ME = X + ME.ex_act(severity, target, origin) + for(var/Y in trackers) + var/obj/item/mecha_parts/mecha_tracking/MT = Y + MT.ex_act(severity, target, origin) + for(var/Z in occupants) + var/mob/living/occupant = Z + occupant.ex_act(severity, target, origin) + +/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/vehicle/sealed/mecha/emp_act(severity) + . = ..() + if (. & EMP_PROTECT_SELF) + return + if(get_charge()) + use_power((cell.charge/3)/(severity*2)) + take_damage(30 / severity, BURN, ENERGY, 1) + log_message("EMP detected", LOG_MECHA, color="red") + + if(istype(src, /obj/vehicle/sealed/mecha/combat)) + mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse-disable.dmi' + for(var/occus in occupants) + var/mob/living/occupant = occus + occupant.update_mouse_pointer() + if(!equipment_disabled && 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, /obj/vehicle/sealed/mecha/proc/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) + if(exposed_temperature>max_temperature) + log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red") + take_damage(5, BURN, 0, 1) + +/obj/vehicle/sealed/mecha/attackby(obj/item/W, mob/user, params) + + if(istype(W, /obj/item/mmi)) + if(mmi_move_inside(W,user)) + to_chat(user, "[src]-[W] interface initialized successfully.") + else + to_chat(user, "[src]-[W] interface initialization failed.") + return + + if(istype(W, /obj/item/mecha_ammo)) + ammo_resupply(W, user) + return + + if(W.GetID()) + if((mecha_flags & ADDING_ACCESS_POSSIBLE) || (mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)) + if(internals_access_allowed(user)) + var/obj/item/card/id/id_card + if(istype(W, /obj/item/card/id)) + id_card = W + else + var/obj/item/pda/pda = W + id_card = pda.id + output_maintenance_dialog(id_card, user) + return + to_chat(user, "Invalid ID: Access denied.") + return + to_chat(user, "Maintenance protocols disabled by operator.") + return + + if(istype(W, /obj/item/stock_parts/cell)) + if(construction_state == MECHA_OPEN_HATCH) + if(!cell) + if(!user.transferItemToLoc(W, src, silent = FALSE)) + return + var/obj/item/stock_parts/cell/C = W + to_chat(user, "You install the power cell.") + playsound(src, 'sound/items/screwdriver2.ogg', 50, FALSE) + cell = C + log_message("Power cell installed", LOG_MECHA) + else + to_chat(user, "There's already a power cell installed!") + return + + if(istype(W, /obj/item/stock_parts/scanning_module)) + if(construction_state == MECHA_OPEN_HATCH) + if(!scanmod) + if(!user.transferItemToLoc(W, src)) + return + to_chat(user, "You install the scanning module.") + playsound(src, 'sound/items/screwdriver2.ogg', 50, FALSE) + scanmod = W + log_message("[W] installed", LOG_MECHA) + update_part_values() + else + to_chat(user, "There's already a scanning module installed!") + return + + if(istype(W, /obj/item/stock_parts/capacitor)) + if(construction_state == MECHA_OPEN_HATCH) + if(!capacitor) + if(!user.transferItemToLoc(W, src)) + return + to_chat(user, "You install the capacitor.") + playsound(src, 'sound/items/screwdriver2.ogg', 50, FALSE) + capacitor = W + log_message("[W] installed", LOG_MECHA) + update_part_values() + else + to_chat(user, "There's already a capacitor installed!") + return + + if(istype(W, /obj/item/stack/cable_coil)) + if(construction_state == MECHA_OPEN_HATCH && (internal_damage & MECHA_INT_SHORT_CIRCUIT)) + var/obj/item/stack/cable_coil/CC = W + if(CC.use(2)) + clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) + to_chat(user, "You replace the fused wires.") + else + to_chat(user, "You need two lengths of cable to fix this mech!") + return + + if(istype(W, /obj/item/mecha_parts)) + var/obj/item/mecha_parts/P = W + P.try_attach_part(user, src) + return + if(istype(W, /obj/item/analyzer)) + if(construction_state) + var/datum/gas_mixture/GasNux = internal_tank.return_air() + atmosanalyzer_scan(GasNux,user,src,TRUE) + else + atmosanalyzer_scan(cabin_air,user,src,TRUE) + return + log_message("Attacked by [W]. Attacker - [user]", LOG_MECHA) + return ..() + +/obj/vehicle/sealed/mecha/wrench_act(mob/living/user, obj/item/I) + ..() + . = TRUE + if(construction_state == MECHA_SECURE_BOLTS) + construction_state = MECHA_LOOSE_BOLTS + to_chat(user, "You undo the securing bolts.") + return + if(construction_state == MECHA_LOOSE_BOLTS) + construction_state = MECHA_SECURE_BOLTS + to_chat(user, "You tighten the securing bolts.") + +/obj/vehicle/sealed/mecha/crowbar_act(mob/living/user, obj/item/I) + ..() + . = TRUE + if(construction_state == MECHA_LOOSE_BOLTS) + construction_state = MECHA_OPEN_HATCH + to_chat(user, "You open the hatch to the power unit.") + return + if(construction_state == MECHA_OPEN_HATCH) + construction_state = MECHA_LOOSE_BOLTS + to_chat(user, "You close the hatch to the power unit.") + +/obj/vehicle/sealed/mecha/screwdriver_act(mob/living/user, obj/item/I) + ..() + . = TRUE + if(internal_damage & MECHA_INT_TEMP_CONTROL) + clearInternalDamage(MECHA_INT_TEMP_CONTROL) + to_chat(user, "You repair the damaged temperature controller.") + return + +/obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W) + . = ..() + if(user.a_intent == INTENT_HARM) + return + . = TRUE + if(internal_damage & MECHA_INT_TANK_BREACH) + if(!W.use_tool(src, user, 0, volume=50, amount=1)) + return + clearInternalDamage(MECHA_INT_TANK_BREACH) + to_chat(user, "You repair the damaged gas tank.") + return + if(obj_integrity < max_integrity) + if(!W.use_tool(src, user, 0, volume=50, amount=1)) + return + user.visible_message("[user] repairs some damage to [name].", "You repair some damage to [src].") + obj_integrity += min(10, max_integrity-obj_integrity) + if(obj_integrity == max_integrity) + to_chat(user, "It looks to be fully repaired now.") + return + to_chat(user, "The [name] is at full integrity!") + +/obj/vehicle/sealed/mecha/proc/mech_toxin_damage(mob/living/target) + playsound(src, 'sound/effects/spray2.ogg', 50, TRUE) + if(target.reagents) + if(target.reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + force < force*2) + target.reagents.add_reagent(/datum/reagent/cryptobiolin, force/2) + if(target.reagents.get_reagent_amount(/datum/reagent/toxin) + force < force*2) + target.reagents.add_reagent(/datum/reagent/toxin, force/2.5) + + +/obj/vehicle/sealed/mecha/mech_melee_attack(obj/vehicle/sealed/mecha/M, mob/user) + if(!has_charge(melee_energy_drain)) + return NONE + use_power(melee_energy_drain) + if(M.damtype == BRUTE || M.damtype == BURN) + log_combat(user, src, "attacked", M, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + . = ..() + +/obj/vehicle/sealed/mecha/proc/full_repair(charge_cell) + obj_integrity = max_integrity + if(cell && charge_cell) + cell.charge = cell.maxcharge + if(internal_damage & MECHA_INT_FIRE) + clearInternalDamage(MECHA_INT_FIRE) + if(internal_damage & MECHA_INT_TEMP_CONTROL) + clearInternalDamage(MECHA_INT_TEMP_CONTROL) + if(internal_damage & MECHA_INT_SHORT_CIRCUIT) + clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) + if(internal_damage & MECHA_INT_TANK_BREACH) + clearInternalDamage(MECHA_INT_TANK_BREACH) + if(internal_damage & MECHA_INT_CONTROL_LOST) + clearInternalDamage(MECHA_INT_CONTROL_LOST) + +/obj/vehicle/sealed/mecha/narsie_act() + emp_act(80) + +/obj/vehicle/sealed/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) + if(!no_effect) + if(selected) + used_item = selected + else if(!visual_effect_icon) + visual_effect_icon = ATTACK_EFFECT_SMASH + if(damtype == BURN) + visual_effect_icon = ATTACK_EFFECT_MECHFIRE + else if(damtype == TOX) + visual_effect_icon = ATTACK_EFFECT_MECHTOXIN + ..() + +/obj/vehicle/sealed/mecha/obj_destruction() + if(wreckage) + var/mob/living/silicon/ai/AI + 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)) + WR.crowbar_salvage += E + E.detach(WR) //detaches from src into WR + E.equip_ready = 1 + else + E.detach(loc) + qdel(E) + if(cell) + WR.crowbar_salvage += cell + cell.forceMove(WR) + cell.charge = rand(0, cell.charge) + cell = null + if(internal_tank) + WR.crowbar_salvage += internal_tank + internal_tank.forceMove(WR) + cell = null + . = ..() diff --git a/code/game/mecha/mecha_parts.dm b/code/modules/vehicles/mecha/mecha_parts.dm similarity index 95% rename from code/game/mecha/mecha_parts.dm rename to code/modules/vehicles/mecha/mecha_parts.dm index 8a9e4e641f..31c4c72a2b 100644 --- a/code/game/mecha/mecha_parts.dm +++ b/code/modules/vehicles/mecha/mecha_parts.dm @@ -9,13 +9,16 @@ w_class = WEIGHT_CLASS_GIGANTIC flags_1 = CONDUCT_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/vehicle/sealed/mecha/M) + return + /obj/item/mecha_parts/chassis name = "Mecha Chassis" icon_state = "backbone" @@ -58,6 +61,12 @@ desc = "A Ripley APLU right leg. Contains somewhat complex servodrives and balance maintaining systems." icon_state = "ripley_r_leg" + +//Firefighter +/obj/item/mecha_parts/chassis/firefighter + name = "\improper Firefighter chassis" + construct_type = /datum/component/construction/unordered/mecha_chassis/firefighter + ///////// Odysseus /obj/item/mecha_parts/chassis/odysseus @@ -220,12 +229,6 @@ desc = "A set of armor plates for the Durand. Built heavy to resist an incredible amount of brute force." icon_state = "durand_armor" -////////// Firefighter - -/obj/item/mecha_parts/chassis/firefighter - name = "\improper Firefighter chassis" - construct_type = /datum/component/construction/unordered/mecha_chassis/firefighter - ////////// HONK @@ -270,6 +273,11 @@ name = "\improper Phazon chassis" construct_type = /datum/component/construction/unordered/mecha_chassis/phazon +/obj/item/mecha_parts/chassis/phazon/attackby(obj/item/I, mob/user, params) + . = ..() + if(istype(I, /obj/item/assembly/signaler/anomaly) && !istype(I, /obj/item/assembly/signaler/anomaly/bluespace)) + to_chat(user, "The anomaly core socket only accepts bluespace anomaly cores!") + /obj/item/mecha_parts/part/phazon_torso name="\improper Phazon torso" desc="A Phazon torso part. The socket for the bluespace core that powers the exosuit's unique phase drives is located in the middle." @@ -312,7 +320,6 @@ name = "exosuit circuit board" icon = 'icons/obj/module.dmi' icon_state = "std_mod" - item_state = "electronic" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' flags_1 = CONDUCT_1 @@ -385,3 +392,11 @@ /obj/item/circuitboard/mecha/phazon/main name = "Phazon Central Control module (Exosuit Board)" + +/obj/item/circuitboard/mecha/clarke/peripherals + name = "Clarke Peripherals Control module (Exosuit Board)" + icon_state = "mcontroller" + +/obj/item/circuitboard/mecha/clarke/main + name = "Clarke Central Control module (Exosuit Board)" + icon_state = "mainboard" diff --git a/code/modules/vehicles/mecha/mecha_topic.dm b/code/modules/vehicles/mecha/mecha_topic.dm new file mode 100644 index 0000000000..eb7dcd01db --- /dev/null +++ b/code/modules/vehicles/mecha/mecha_topic.dm @@ -0,0 +1,421 @@ + +//////////////////////////////////// +///// Rendering stats window /////// +//////////////////////////////////// + +/obj/vehicle/sealed/mecha/proc/get_stats_html(mob/user) + . = {" + + + [name] data + + + + +
+ [get_stats_part(user)] +
+
+ [get_equipment_list()] +
+
+
+ [get_commands()] +
+
+ [get_equipment_menu()] +
+ + "} + +///Returns the status of the mech. +/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 + var/tank_pressure = 0 + var/tank_temperature = 0 + var/cabin_pressure = 0 + if (internal_tank) + int_tank_air = internal_tank.return_air() + tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None" + tank_temperature = internal_tank ? int_tank_air.return_temperature() : "Unknown" + cabin_pressure = round(return_pressure(),0.01) + . = {"[report_internal_damage()] + [integrity<30?"DAMAGE LEVEL CRITICAL
":null] + Integrity: [integrity]%
+ Power cell charge: [isnull(cell_charge)?"No power cell installed":"[cell.percent()]%"]
+ Air source: [internal_tank?"[use_internal_tank?"Internal Airtank":"Environment"]":"Environment"]
+ Airtank pressure: [internal_tank?"[tank_pressure]kPa":"N/A"]
+ Airtank temperature: [internal_tank?"[tank_temperature]°K|[tank_temperature - T0C]°C":"N/A"]
+ Cabin pressure: [internal_tank?"[cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa":"N/A"]
+ Cabin temperature: [internal_tank?"[return_temperature()]°K|[return_temperature() - T0C]°C":"N/A"]
+ [dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":""]
"} + . += "[get_actions(user)]
" + +///Returns HTML for mech actions. Ideally, this proc would be empty for the base mecha. Segmented for easy refactoring. +/obj/vehicle/sealed/mecha/proc/get_actions(mob/user) + . = "" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_defense_mode) ? "Defense Mode: [defense_mode ? "Enabled" : "Disabled"]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_overload_mode) ? "Leg Actuators Overload: [leg_overload_mode ? "Enabled" : "Disabled"]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_smoke) ? "Smoke Charges remaining: [smoke_charges]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_zoom) ? "Zoom: [zoom_mode ? "Enabled" : "Disabled"]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_switch_damtype) ? "Damtype: [damtype]
" : ""]" + . += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_toggle_phasing) ? "Phase Modulator: [phasing ? "Enabled" : "Disabled"]
" : ""]" + +///HTML for internal damage. +/obj/vehicle/sealed/mecha/proc/report_internal_damage() + . = "" + var/list/dam_reports = list( + "[MECHA_INT_FIRE]" = "INTERNAL FIRE", + "[MECHA_INT_TEMP_CONTROL]" = "LIFE SUPPORT SYSTEM MALFUNCTION", + "[MECHA_INT_TANK_BREACH]" = "GAS TANK BREACH", + "[MECHA_INT_CONTROL_LOST]" = "COORDINATION SYSTEM CALIBRATION FAILURE - Recalibrate", + "[MECHA_INT_SHORT_CIRCUIT]" = "SHORT CIRCUIT" + ) + for(var/tflag in dam_reports) + var/intdamflag = text2num(tflag) + if(internal_damage & intdamflag) + . += dam_reports[tflag] + . += "
" + if(return_pressure() > WARNING_HIGH_PRESSURE) + . += "DANGEROUSLY HIGH CABIN PRESSURE
" + +///HTML for list of equipment. +/obj/vehicle/sealed/mecha/proc/get_equipment_list() //outputs mecha equipment list in html + if(!LAZYLEN(equipment)) + return + . = "Equipment:
" + for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) + . += "
[MT.get_equip_info()]
" + . += "
" + +///HTML for commands. +/obj/vehicle/sealed/mecha/proc/get_commands() + . = {" +
+
Electronics
+ +
+ "} + + +/obj/vehicle/sealed/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu + . = {" +
+
Equipment
+ +
"} + +/obj/vehicle/sealed/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user) + if(!id_card || !user) + return + . = {" + + + + + +

Following keycodes are present in this system:

"} + for(var/a in operation_req_access) + . += "[get_access_desc(a)] - Delete
" + . += "

Following keycodes were detected on portable device:

" + for(var/a in id_card.access) + if(a in operation_req_access) + continue + var/a_name = get_access_desc(a) + if(!a_name) + continue //there's some strange access without a name + . += "[a_name] - Add
" + . +={"
Lock ID panel
+ (Warning! The ID upload panel can be unlocked only through Exosuit Interface.) + + "} + user << browse(., "window=exosuit_add_access") + onclose(user, "exosuit_add_access") + + +/obj/vehicle/sealed/mecha/proc/output_maintenance_dialog(obj/item/card/id/id_card,mob/user) + if(!id_card || !user) + return + . = {" + + + + + + [(mecha_flags & ADDING_ACCESS_POSSIBLE)?"Edit operation keycodes":null] + [(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"[(construction_state > MECHA_LOCKED) ? "Terminate" : "Initiate"] maintenance protocol":null] + [(construction_state == MECHA_OPEN_HATCH) ?"--------------------
":null] + [(construction_state == MECHA_OPEN_HATCH) ?"[cell?"Drop power cell":"No cell installed
"]":null] + [(construction_state == MECHA_OPEN_HATCH) ?"[scanmod?"Drop scanning module":"No scanning module installed
"]":null] + [(construction_state == MECHA_OPEN_HATCH) ?"[capacitor?"Drop capacitor":"No capacitor installed
"]":null] + [(construction_state == MECHA_OPEN_HATCH) ?"--------------------
":null] + [(construction_state > MECHA_LOCKED) ?"Set Cabin Air Pressure":null] + + "} + user << browse(., "window=exosuit_maint_console") + onclose(user, "exosuit_maint_console") + + + + +///////////////// +///// Topic ///// +///////////////// + +/obj/vehicle/sealed/mecha/Topic(href, href_list) + ..() + + if(!usr) + return + + if(href_list["close"]) + return + + if(usr.incapacitated()) + return + + if(in_range(src, usr)) + //Start of ID requirements. + if(href_list["id_card"]) + var/obj/item/card/id/id_card + id_card = locate(href_list["id_card"]) + if(!istype(id_card)) + return + + if(href_list["req_access"]) + if(!(mecha_flags & ADDING_ACCESS_POSSIBLE)) + return + output_access_dialog(id_card,usr) + return + + if(href_list["maint_access"]) + if(!(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)) + return + if(construction_state == MECHA_LOCKED) + construction_state = MECHA_SECURE_BOLTS + to_chat(usr, "The securing bolts are now exposed.") + else if(construction_state == MECHA_SECURE_BOLTS) + construction_state = MECHA_LOCKED + to_chat(usr, "The securing bolts are now hidden.") + output_maintenance_dialog(id_card,usr) + return + if(href_list["drop_cell"]) + if(construction_state == MECHA_OPEN_HATCH) + cell.forceMove(get_turf(src)) + cell = null + output_maintenance_dialog(id_card,usr) + return + if(href_list["drop_scanmod"]) + if(construction_state == MECHA_OPEN_HATCH) + scanmod.forceMove(get_turf(src)) + scanmod = null + output_maintenance_dialog(id_card,usr) + return + if(href_list["drop_cap"]) + if(construction_state == MECHA_OPEN_HATCH) + capacitor.forceMove(get_turf(src)) + capacitor = null + output_maintenance_dialog(id_card,usr) + return + + if(href_list["add_req_access"]) + if(!(mecha_flags & ADDING_ACCESS_POSSIBLE)) + return + operation_req_access += text2num(href_list["add_req_access"]) + output_access_dialog(id_card,usr) + return + + if(href_list["del_req_access"]) + if(!(mecha_flags & ADDING_ACCESS_POSSIBLE)) + return + operation_req_access -= text2num(href_list["del_req_access"]) + output_access_dialog(id_card, usr) + return + return //Here end everything requiring an ID. + + //Here ID access stuff goes to die. + if(href_list["finish_req_access"]) + mecha_flags &= ~ADDING_ACCESS_POSSIBLE + usr << browse(null,"window=exosuit_add_access") + return + + //Set pressure. + if(href_list["set_internal_tank_valve"] && construction_state) + var/new_pressure = input(usr,"Input new output pressure","Pressure setting",internal_tank_valve) as num|null + if(isnull(new_pressure) || usr.incapacitated() || !construction_state) + return + internal_tank_valve = new_pressure + to_chat(usr, "The internal pressure valve has been set to [internal_tank_valve]kPa.") + return + + //Start of all internal topic stuff. + if(!locate(usr) in occupants) + return + + if(href_list["update_content"]) + send_byjax(usr,"exosuit.browser","content", get_stats_part()) + return + + //Selects the mech equipment/weapon. + if(href_list["select_equip"]) + var/obj/item/mecha_parts/mecha_equipment/equip = locate(href_list["select_equip"]) in src + if(!equip || !equip.selectable) + return + selected = equip + to_chat(occupants, "[icon2html(src, occupants)]You switch to [equip].") + visible_message("[src] raises [equip].") + send_byjax(usr, "exosuit.browser", "eq_list", get_equipment_list()) + return + + //Toggles radio broadcasting + if(href_list["rmictoggle"]) + radio.broadcasting = !radio.broadcasting + send_byjax(usr,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged")) + return + + //Toggles radio listening + if(href_list["rspktoggle"]) + radio.listening = !radio.listening + send_byjax(usr,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged")) + return + + //Changes radio freqency. + if(href_list["rfreq"]) + var/new_frequency = radio.frequency + text2num(href_list["rfreq"]) + radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange)) + send_byjax(usr,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]") + return + + //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 || !locate(usr) in occupants || usr.incapacitated()) + return + name = userinput + return + + //Toggles ID upload. + if (href_list["toggle_id_upload"]) + mecha_flags ^= ADDING_ACCESS_POSSIBLE + send_byjax(usr,"exosuit.browser","t_id_upload","[(mecha_flags & ADDING_ACCESS_POSSIBLE)?"L":"Unl"]ock ID upload panel") + return + + //Toggles main access. + if(href_list["toggle_maint_access"]) + if(construction_state) + to_chat(occupants, "[icon2html(src, occupants)]Maintenance protocols in effect") + return + mecha_flags ^= ADDING_MAINT_ACCESS_POSSIBLE + send_byjax(usr,"exosuit.browser","t_maint_access","[(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"Forbid":"Permit"] maintenance protocols") + return + + //Toggles connection port. + if (href_list["toggle_port_connection"]) + if(internal_tank.connected_port) + if(internal_tank.disconnect()) + to_chat(occupants, "[icon2html(src, occupants)]Disconnected from the air system port.") + log_message("Disconnected from gas port.", LOG_MECHA) + else + 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)) + to_chat(occupants, "[icon2html(src, occupants)]Connected to the air system port.") + log_message("Connected to gas port.", LOG_MECHA) + else + to_chat(occupants, "[icon2html(src, occupants)]Unable to connect with air system port!") + return + send_byjax(occupants,"exosuit.browser","t_port_connection","[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port") + return + + //Turns on the DNA lock + if(href_list["dna_lock"]) + var/mob/living/carbon/user = usr + if(!istype(user) || !user.dna) + to_chat(user, "[icon2html(src, occupants)]You can't create a DNA lock with no DNA!.") + return + dna_lock = user.dna.unique_enzymes + to_chat(user, "[icon2html(src, occupants)]You feel a prick as the needle takes your DNA sample.") + return + + //Resets the DNA lock + if(href_list["reset_dna"]) + dna_lock = null + return + + //Repairs internal damage + if(href_list["repair_int_control_lost"]) + to_chat(occupants, "[icon2html(src, occupants)]Recalibrating coordination system...") + log_message("Recalibration of coordination system started.", LOG_MECHA) + addtimer(CALLBACK(src, .proc/stationary_repair, loc), 100, TIMER_UNIQUE) + +///Repairs internal damage if the mech hasn't moved. +/obj/vehicle/sealed/mecha/proc/stationary_repair(location) + if(location == loc) + clearInternalDamage(MECHA_INT_CONTROL_LOST) + to_chat(occupants, "[icon2html(src, occupants)]Recalibration successful.") + log_message("Recalibration of coordination system finished with 0 errors.", LOG_MECHA) + else + to_chat(occupants, "[icon2html(src, occupants)]Recalibration failed!") + log_message("Recalibration of coordination system failed with 1 error.", LOG_MECHA, color="red") diff --git a/code/modules/vehicles/mecha/mecha_wreckage.dm b/code/modules/vehicles/mecha/mecha_wreckage.dm new file mode 100644 index 0000000000..b9f299731a --- /dev/null +++ b/code/modules/vehicles/mecha/mecha_wreckage.dm @@ -0,0 +1,222 @@ +/////////////////////////////////// +//////// Mecha wreckage //////// +/////////////////////////////////// + + +/obj/structure/mecha_wreckage + name = "exosuit wreckage" + desc = "Remains of some unfortunate mecha. Completely irreparable, but perhaps something can be salvaged." + icon = 'icons/mecha/mecha.dmi' + density = TRUE + anchored = FALSE + opacity = FALSE + var/list/welder_salvage = list(/obj/item/stack/sheet/plasteel, /obj/item/stack/sheet/metal, /obj/item/stack/rods) + var/salvage_num = 5 + var/list/crowbar_salvage = list() + var/wires_removed = FALSE + var/mob/living/silicon/ai/AI //AIs to be salvaged + var/list/parts + +/obj/structure/mecha_wreckage/Initialize(mapload, mob/living/silicon/ai/AI_pilot) + . = ..() + if(parts) + for(var/i in 1 to 2) + if(!parts.len) + break + if(prob(60)) + continue + var/part = pick(parts) + welder_salvage += part + parts = null + if(!AI_pilot) //Type-checking for this is already done in mecha/Destroy() + return + AI = AI_pilot + AI.apply_damage(150, BURN) //Give the AI a bit of damage from the "shock" of being suddenly shut down + AI.death() //The damage is not enough to kill the AI, but to be 'corrupted files' in need of repair. + AI.forceMove(src) //Put the dead AI inside the wreckage for recovery + add_overlay(mutable_appearance('icons/obj/projectiles.dmi', "green_laser")) //Overlay for the recovery beacon + AI.controlled_mech = null + AI.remote_control = null + +/obj/structure/mecha_wreckage/Destroy() + if(AI) + QDEL_NULL(AI) + QDEL_LIST(crowbar_salvage) + return ..() + +/obj/structure/mecha_wreckage/examine(mob/user) + . = ..() + if(!AI) + return + . += "The AI recovery beacon is active." + +/obj/structure/mecha_wreckage/welder_act(mob/living/user, obj/item/I) + ..() + . = TRUE + if(salvage_num <= 0 || !length(welder_salvage)) + to_chat(user, "You don't see anything that can be cut with [I]!") + return + if(!I.use_tool(src, user, 0, volume=50)) + return + if(prob(30)) + to_chat(user, "You fail to salvage anything valuable from [src]!") + return + var/type = pick(welder_salvage) + var/N = new type(get_turf(user)) + user.visible_message("[user] cuts [N] from [src].", "You cut [N] from [src].") + if(!istype(N, /obj/item/stack)) + welder_salvage -= type + salvage_num-- + +/obj/structure/mecha_wreckage/wirecutter_act(mob/living/user, obj/item/I) + ..() + . = TRUE + if(wires_removed) + to_chat(user, "You don't see anything that can be cut with [I]!") + return + var/N = new /obj/item/stack/cable_coil(get_turf(user), rand(1,3)) + user.visible_message("[user] cuts [N] from [src].", "You cut [N] from [src].") + wires_removed = TRUE + +/obj/structure/mecha_wreckage/crowbar_act(mob/living/user, obj/item/I) + ..() + . = TRUE + if(crowbar_salvage.len) + var/obj/S = pick(crowbar_salvage) + S.forceMove(user.drop_location()) + user.visible_message("[user] pries [S] from [src].", "You pry [S] from [src].") + crowbar_salvage -= S + return + to_chat(user, "You don't see anything that can be cut with [I]!") + +/obj/structure/mecha_wreckage/transfer_ai(interaction, mob/user, null, obj/item/aicard/card) + if(!..()) + return + + //Proc called on the wreck by the AI card. + if(interaction != AI_TRANS_TO_CARD) //AIs can only be transferred in one direction, from the wreck to the card. + return + if(!AI) //No AI in the wreck + to_chat(user, "No AI backups found.") + return + cut_overlays() //Remove the recovery beacon overlay + AI.forceMove(card) //Move the dead AI to the card. + card.AI = AI + if(AI.client) //AI player is still in the dead AI and is connected + to_chat(AI, "The remains of your file system have been recovered on a mobile storage device.") + else //Give the AI a heads-up that it is probably going to get fixed. + AI.notify_ghost_cloning("You have been recovered from the wreckage!", source = card) + to_chat(user, "Backup files recovered: [AI.name] ([rand(1000,9999)].exe) salvaged from [name] and stored within local memory.") + AI = null + +/obj/structure/mecha_wreckage/gygax + name = "\improper Gygax wreckage" + icon_state = "gygax-broken" + parts = list( + /obj/item/mecha_parts/part/gygax_torso, + /obj/item/mecha_parts/part/gygax_head, + /obj/item/mecha_parts/part/gygax_left_arm, + /obj/item/mecha_parts/part/gygax_right_arm, + /obj/item/mecha_parts/part/gygax_left_leg, + /obj/item/mecha_parts/part/gygax_right_leg + ) + +/obj/structure/mecha_wreckage/gygax/dark + name = "\improper Dark Gygax wreckage" + icon_state = "darkgygax-broken" + +/obj/structure/mecha_wreckage/marauder + name = "\improper Marauder wreckage" + icon_state = "marauder-broken" + +/obj/structure/mecha_wreckage/mauler + name = "\improper Mauler wreckage" + icon_state = "mauler-broken" + desc = "The syndicate won't be very happy about this..." + +/obj/structure/mecha_wreckage/seraph + name = "\improper Seraph wreckage" + icon_state = "seraph-broken" + +/obj/structure/mecha_wreckage/reticence + name = "\improper Reticence wreckage" + icon_state = "reticence-broken" + color = "#87878715" + desc = "..." + +/obj/structure/mecha_wreckage/ripley + name = "\improper Ripley wreckage" + icon_state = "ripley-broken" + parts = list( + /obj/item/mecha_parts/part/ripley_torso, + /obj/item/mecha_parts/part/ripley_left_arm, + /obj/item/mecha_parts/part/ripley_right_arm, + /obj/item/mecha_parts/part/ripley_left_leg, + /obj/item/mecha_parts/part/ripley_right_leg) + +/obj/structure/mecha_wreckage/ripley/mkii + name = "\improper Ripley MK-II wreckage" + icon_state = "ripleymkii-broken" + +/obj/structure/mecha_wreckage/ripley/deathripley + name = "\improper Death-Ripley wreckage" + icon_state = "deathripley-broken" + parts = null + +/obj/structure/mecha_wreckage/ripley/firefighter + name = "\improper Firefighter wreckage" + icon_state = "firefighter-broken" + parts = list( + /obj/item/mecha_parts/part/ripley_torso, + /obj/item/mecha_parts/part/ripley_left_arm, + /obj/item/mecha_parts/part/ripley_right_arm, + /obj/item/mecha_parts/part/ripley_left_leg, + /obj/item/mecha_parts/part/ripley_right_leg) + + +/obj/structure/mecha_wreckage/honker + name = "\improper H.O.N.K wreckage" + icon_state = "honker-broken" + desc = "All is right in the universe." + parts = list( + /obj/item/mecha_parts/part/honker_torso, + /obj/item/mecha_parts/part/honker_head, + /obj/item/mecha_parts/part/honker_left_arm, + /obj/item/mecha_parts/part/honker_right_arm, + /obj/item/mecha_parts/part/honker_left_leg, + /obj/item/mecha_parts/part/honker_right_leg) + +/obj/structure/mecha_wreckage/durand + name = "\improper Durand wreckage" + icon_state = "durand-broken" + parts = list( + /obj/item/mecha_parts/part/durand_torso, + /obj/item/mecha_parts/part/durand_head, + /obj/item/mecha_parts/part/durand_left_arm, + /obj/item/mecha_parts/part/durand_right_arm, + /obj/item/mecha_parts/part/durand_left_leg, + /obj/item/mecha_parts/part/durand_right_leg) + +/obj/structure/mecha_wreckage/phazon + name = "\improper Phazon wreckage" + icon_state = "phazon-broken" + parts = list( + /obj/item/mecha_parts/part/phazon_torso, + /obj/item/mecha_parts/part/phazon_head, + /obj/item/mecha_parts/part/phazon_left_arm, + /obj/item/mecha_parts/part/phazon_right_arm, + /obj/item/mecha_parts/part/phazon_left_leg, + /obj/item/mecha_parts/part/phazon_right_leg) + + + +/obj/structure/mecha_wreckage/odysseus + name = "\improper Odysseus wreckage" + icon_state = "odysseus-broken" + parts = list( + /obj/item/mecha_parts/part/odysseus_torso, + /obj/item/mecha_parts/part/odysseus_head, + /obj/item/mecha_parts/part/odysseus_left_arm, + /obj/item/mecha_parts/part/odysseus_right_arm, + /obj/item/mecha_parts/part/odysseus_left_leg, + /obj/item/mecha_parts/part/odysseus_right_leg) diff --git a/code/game/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm similarity index 56% rename from code/game/mecha/medical/odysseus.dm rename to code/modules/vehicles/mecha/medical/odysseus.dm index 6ed207a4c4..bd415cd64f 100644 --- a/code/game/mecha/medical/odysseus.dm +++ b/code/modules/vehicles/mecha/medical/odysseus.dm @@ -1,31 +1,33 @@ -/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" - 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_ROBOTICS, ACCESS_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/carbon/human/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 new file mode 100644 index 0000000000..e8fae6d985 --- /dev/null +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -0,0 +1,219 @@ +/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" + silicon_icon_state = "ripley-empty" + movedelay = 1.5 //Move speed, lower is faster. + /// How fast the mech is in low pressure + var/fast_pressure_step_in = 1.5 + /// How fast the mech is in normal pressure + var/slow_pressure_step_in = 2 + max_temperature = 20000 + max_integrity = 200 + 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) + max_equip = 6 + wreckage = /obj/structure/mecha_wreckage/ripley + internals_req_access = list(ACCESS_ENGINE, ACCESS_ROBOTICS, ACCESS_MINING) + enclosed = FALSE //Normal ripley has an open cockpit design + enter_delay = 10 //can enter in a quarter of the time of other mechs + exit_delay = 10 + /// Amount of Goliath hides attached to the mech + var/hides = 0 + /// List of all things in Ripley's Cargo Compartment + var/list/cargo = new + /// How much things Ripley can carry in their Cargo Compartment + var/cargo_capacity = 15 + +/obj/vehicle/sealed/mecha/working/ripley/Move() + . = ..() + update_pressure() + +/obj/vehicle/sealed/mecha/working/ripley/moved_inside(mob/living/carbon/human/H) + ..() + update_icon() + +/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() + . = ..() + 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/generate_actions() + if(enclosed) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip, VEHICLE_CONTROL_EQUIPMENT) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/strafe, VEHICLE_CONTROL_DRIVE) + +/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/mkii + desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection and armor." + name = "\improper APLU MK-II \"Ripley\"" + icon_state = "ripleymkii" + 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 + max_temperature = 30000 + max_integrity = 250 + armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100) + wreckage = /obj/structure/mecha_wreckage/ripley/mkii + enclosed = TRUE + enter_delay = 40 + silicon_icon_state = null + +/obj/vehicle/sealed/mecha/working/ripley/firefighter + desc = "Autonomous Power Loader Unit MK-II-F. This model is refitted with additional thermal protection." + name = "\improper APLU \"Firefighter\"" + icon_state = "firefighter" + movedelay = 4 + fast_pressure_step_in = 2 + slow_pressure_step_in = 4 + max_temperature = 65000 + max_integrity = 250 + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100) + max_equip = 5 // More armor, less tools + enclosed = TRUE + enter_delay = 40 + +/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" + fast_pressure_step_in = 2 //step_in while in low pressure conditions + slow_pressure_step_in = 3 //step_in while in normal pressure conditions + movedelay = 4 + 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() + . = ..() + 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() + . = ..() + 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() + . = ..() + 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, origin) + 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) * 0.5 + + 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 new file mode 100644 index 0000000000..c765e0f0e5 --- /dev/null +++ b/code/modules/vehicles/mecha/working/working.dm @@ -0,0 +1,28 @@ +/obj/vehicle/sealed/mecha/working + internal_damage_threshold = 60 + +/obj/vehicle/sealed/mecha/working/Move() + . = ..() + if(.) + collect_ore() + +/** + * Handles collecting ore. + * + * Checks for a hydraulic clamp or ore box manager and if it finds an ore box inside them puts ore in the ore box. + */ +/obj/vehicle/sealed/mecha/working/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 contents + 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/Bump(atom/obstacle) + if(istype(selected, /obj/item/mecha_parts/mecha_equipment/drill) && istype(obstacle, /turf/closed/mineral)) + var/obj/item/mecha_parts/mecha_equipment/drill/thedrill = selected + for(var/mob/M in occupants) + thedrill.action(M, obstacle) + break + ..() diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index 63c7c9f858..1a1858522a 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -47,10 +47,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) diff --git a/icons/mecha/durand_shield.dmi b/icons/mecha/durand_shield.dmi new file mode 100644 index 0000000000..0600e352b3 Binary files /dev/null and b/icons/mecha/durand_shield.dmi differ diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi index d75ae09c97..17e62c2d9e 100644 Binary files a/icons/mecha/mecha.dmi and b/icons/mecha/mecha.dmi differ diff --git a/icons/mob/actions/actions_mecha.dmi b/icons/mob/actions/actions_mecha.dmi index 81c706b22c..071305150e 100644 Binary files a/icons/mob/actions/actions_mecha.dmi and b/icons/mob/actions/actions_mecha.dmi differ diff --git a/sound/mecha/mech_shield_deflect.ogg b/sound/mecha/mech_shield_deflect.ogg new file mode 100644 index 0000000000..5c1970d872 Binary files /dev/null and b/sound/mecha/mech_shield_deflect.ogg differ diff --git a/sound/mecha/mech_shield_drop.ogg b/sound/mecha/mech_shield_drop.ogg new file mode 100644 index 0000000000..21c6cb5edb Binary files /dev/null and b/sound/mecha/mech_shield_drop.ogg differ diff --git a/sound/mecha/mech_shield_raise.ogg b/sound/mecha/mech_shield_raise.ogg new file mode 100644 index 0000000000..65ad70ad14 Binary files /dev/null and b/sound/mecha/mech_shield_raise.ogg differ diff --git a/tgstation.dme b/tgstation.dme index de8e9ccddc..e338be74df 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -73,6 +73,7 @@ #include "code\__DEFINES\materials.dm" #include "code\__DEFINES\maths.dm" #include "code\__DEFINES\MC.dm" +#include "code\__DEFINES\mecha.dm" #include "code\__DEFINES\melee.dm" #include "code\__DEFINES\menu.dm" #include "code\__DEFINES\misc.dm" @@ -998,37 +999,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\mech_fabricator.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\five_stars.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\neovgre.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\work_tools.dm" -#include "code\game\mecha\equipment\weapons\mecha_ammo.dm" -#include "code\game\mecha\equipment\weapons\weapons.dm" -#include "code\game\mecha\medical\medical.dm" -#include "code\game\mecha\medical\medigax.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" @@ -3705,6 +3675,37 @@ #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\medigax.dm" +#include "code\modules\vehicles\mecha\combat\neovgre.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"