/mob/living/MouseDrop(atom/over) if(usr == src && usr != over) if(istype(over, /mob/living/heavy_vehicle)) if(usr.mob_size >= MOB_SMALL && usr.mob_size <= 14) var/mob/living/heavy_vehicle/M = over if(M.enter(src)) return else to_chat(usr, "You cannot pilot a mech of this size.") return return ..() /mob/living/heavy_vehicle/MouseDrop_T(atom/dropping, mob/user) var/obj/machinery/portable_atmospherics/canister/C = dropping if(istype(C)) body.MouseDrop_T(dropping, user) else . = ..() /mob/living/heavy_vehicle/MouseDrop_T(src_object, over_object, src_location, over_location, src_control, over_control, params, var/mob/user) if(!user || incapacitated() || user.incapacitated() || lockdown) return FALSE if(!(user in pilots) && user != src) return FALSE //This is handled at active module level really, it is the one who has to know if it's supposed to act if(selected_system) return selected_system.MouseDragInteraction(src_object, over_object, src_location, over_location, src_control, over_control, params, user) /mob/living/heavy_vehicle/ClickOn(var/atom/A, params, var/mob/user) if(!user || incapacitated() || user.incapacitated() || lockdown) return if(!loc) return var/adj = A.Adjacent(src) // Why in the fuck isn't Adjacent() commutative. var/modifiers = params2list(params) if(modifiers["shift"]) A.examine(user) return if(modifiers["alt"]) if(selected_system) if(selected_system == A) selected_system.attack_self(user) setClickCooldown(5) return if(modifiers["ctrl"]) if(selected_system) if(selected_system == A) selected_system.CtrlClick(user) setClickCooldown(5) return if(!(user in pilots) && user != src) return // Are we facing the target? if(!(get_dir(src, A) & dir)) return if(!canClick()) return if(!arms) to_chat(user, "\The [src] has no manipulators!") setClickCooldown(3) return if(!arms.motivator || !arms.motivator.is_functional()) to_chat(user, "Your motivators are damaged! You can't use your manipulators!") setClickCooldown(15) return if(!(get_cell()?.checked_use(arms.power_use * CELLRATE))) to_chat(user, "Error: Power levels insufficient.") if(user != src) set_intent(user.a_intent) if(user.zone_sel) zone_sel.set_selected_zone(user.zone_sel.selecting) else zone_sel.set_selected_zone("chest") // You may attack the target with your exosuit FIST if you're malfunctioning. var/failed = FALSE if(emp_damage > EMP_ATTACK_DISRUPT && prob(emp_damage*2)) to_chat(user, "The wiring sparks as you attempt to control the exosuit!") failed = TRUE if(!failed) if(selected_system) if(selected_system == A) selected_system.attack_self(user) setClickCooldown(5) return // Mounted non-exosuit systems have some hacky loc juggling // to make sure that they work. var/system_moved = FALSE var/obj/item/temp_system var/obj/item/mecha_equipment/ME if(istype(selected_system, /obj/item/mecha_equipment)) ME = selected_system temp_system = ME.get_effective_obj() if(temp_system in ME) system_moved = 1 temp_system.forceMove(src) else temp_system = selected_system // Slip up and attack yourself maybe. failed = FALSE if(emp_damage>EMP_MOVE_DISRUPT && prob(10)) failed = TRUE if(failed) var/list/other_atoms = orange(1, A) A = null while(LAZYLEN(other_atoms)) var/atom/picked = pick_n_take(other_atoms) if(istype(picked) && picked.simulated) A = picked break if(!A) A = src adj = A.Adjacent(src) var/resolved if(adj) resolved = temp_system.resolve_attackby(A, src, params) if(!resolved && A && temp_system) var/mob/ruser = src if(!system_moved) //It's more useful to pass along clicker pilot when logic is fully mechside ruser = user temp_system.afterattack(A,ruser,adj,params) if(system_moved) //We are using a proxy system that may not have logging like mech equipment does log_and_message_admins("used [temp_system] targetting [A]", user, src.loc) //Mech equipment subtypes can add further click delays var/extra_delay = 0 if(ME != null) ME = selected_system extra_delay = ME.equipment_delay setClickCooldown(arms ? arms.action_delay + extra_delay : 15 + extra_delay) if(system_moved) temp_system.forceMove(selected_system) return if(A == src) setClickCooldown(5) return attack_self(user) else if(adj) setClickCooldown(arms ? arms.action_delay : 15) playsound(src.loc, arms.punch_sound, 45 + 25 * (arms.melee_damage / 50), -1 ) if(ismob(A)) var/mob/target = A user.attack_log += "\[[time_stamp()]\] Attacked [target.name] ([target.ckey]) with [arms] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(arms.damagetype)])" src.attack_log += "\[[time_stamp()]\] [user] ([user.ckey]) attacked [target.name] ([target.ckey]) with [arms] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(arms.damagetype)])" target.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [arms] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(arms.damagetype)])" msg_admin_attack("[key_name(user, highlight_special = 1)] attacked [key_name(target, highlight_special = 1)] with [arms] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(arms.damagetype)]) (JMP)",ckey=key_name(user),ckey_target=key_name(target) ) return A.attack_generic(src, arms.melee_damage, "attacked") return /mob/living/heavy_vehicle/setClickCooldown(var/timeout) next_move = max(world.time + timeout, next_move) for(var/hardpoint in hardpoint_hud_elements) var/obj/screen/mecha/hardpoint/H = hardpoint_hud_elements[hardpoint] if(H) H.color = "#FF0000" addtimer(CALLBACK(src, .proc/reset_hardpoint_color), timeout) /mob/living/heavy_vehicle/proc/reset_hardpoint_color() for(var/hardpoint in hardpoint_hud_elements) var/obj/screen/mecha/hardpoint/H = hardpoint_hud_elements[hardpoint] if(H) H.color = null /mob/living/heavy_vehicle/proc/set_hardpoint(var/hardpoint_tag) clear_selected_hardpoint() if(hardpoints[hardpoint_tag]) // Set the new system. selected_system = hardpoints[hardpoint_tag] selected_hardpoint = hardpoint_tag return 1 // The element calling this proc will set its own icon. return 0 /mob/living/heavy_vehicle/proc/clear_selected_hardpoint() if(selected_hardpoint) for(var/hardpoint in hardpoints) if(hardpoint != selected_hardpoint) continue var/obj/screen/mecha/hardpoint/H = hardpoint_hud_elements[hardpoint] if(istype(H)) H.icon_state = "hardpoint" break selected_system = null selected_hardpoint = null /mob/living/heavy_vehicle/proc/enter(var/mob/user, var/instant = FALSE) if(!user || user.incapacitated()) return if(!user.Adjacent(src)) return if(hatch_locked) to_chat(user, "The [body.hatch_descriptor] is locked.") return if(hatch_closed) to_chat(user, "The [body.hatch_descriptor] is closed.") return if(LAZYLEN(pilots) >= LAZYLEN(body.pilot_positions)) to_chat(user, "\The [src] is occupied.") return if(!instant) to_chat(user, "You start climbing into \the [src]...") if(!do_after(user, entry_speed)) return if(!user || user.incapacitated()) return if(hatch_locked) to_chat(user, "The [body.hatch_descriptor] is locked.") return if(hatch_closed) to_chat(user, "The [body.hatch_descriptor] is closed.") return if(LAZYLEN(pilots) >= LAZYLEN(body.pilot_positions)) to_chat(user, "\The [src] is occupied.") return to_chat(user, "You climb into \the [src].") user.forceMove(src) LAZYDISTINCTADD(pilots, user) sync_access() playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) user << sound('sound/mecha/nominal.ogg',volume=50) if(user.client) user.client.screen |= hud_elements LAZYDISTINCTADD(user.additional_vision_handlers, src) update_icon() return 1 /mob/living/heavy_vehicle/proc/sync_access() access_card.access = saved_access.Copy() if(sync_access) for(var/mob/pilot in pilots) var/obj/item/card/id/pilot_id = pilot.GetIdCard() if(pilot_id && pilot_id.access) access_card.access |= pilot_id.access to_chat(pilot, "Security access permissions synchronized.") /mob/living/heavy_vehicle/proc/eject(var/mob/user, var/silent) if(!user || !(user in src.contents)) return if(hatch_closed) if(hatch_locked) if(!silent) to_chat(user, "The [body.hatch_descriptor] is locked.") return hatch_closed = 0 hud_open.update_icon() update_icon() if(!silent) to_chat(user, "You open the hatch and climb out of \the [src].") else if(!silent) to_chat(user, "You climb out of \the [src].") user.forceMove(get_turf(src)) LAZYREMOVE(user.additional_vision_handlers, src) if(user.client) user.client.screen -= hud_elements user.client.eye = user if(user in pilots) set_intent(I_HURT) LAZYREMOVE(pilots, user) UNSETEMPTY(pilots) /mob/living/heavy_vehicle/relaymove(var/mob/living/user, var/direction) if(world.time < next_mecha_move) return 0 if(!user || incapacitated() || user.incapacitated() || lockdown) return if(!legs) to_chat(user, "\The [src] has no means of propulsion!") next_mecha_move = world.time + 3 // Just to stop them from getting spammed with messages. return if(!legs.motivator || legs.total_damage > 45) to_chat(user, "Your motivators are damaged! You can't move!") next_mecha_move = world.time + 15 return next_mecha_move = world.time + legs.move_delay if(maintenance_protocols) to_chat(user, "Maintenance protocols are in effect.") return var/obj/item/cell/C = get_cell() if(!C || !C.check_charge(legs.power_use * CELLRATE)) to_chat(user, "The power indicator flashes briefly.") return if(hallucination >= EMP_MOVE_DISRUPT && prob(30)) direction = pick(cardinal) if(dir == direction) var/turf/target_loc = get_step(src, direction) if(!legs.can_move_on(loc, target_loc)) return Move(target_loc, direction) else get_cell()?.use(legs.power_use * CELLRATE) if(legs && legs.mech_turn_sound) playsound(src.loc,legs.mech_turn_sound,40,1) next_mecha_move = world.time + legs.turn_delay set_dir(direction) if(istype(hardpoints[HARDPOINT_BACK], /obj/item/mecha_equipment/shield)) var/obj/item/mecha_equipment/shield/S = hardpoints[HARDPOINT_BACK] if(S.aura) S.aura.dir = direction if(S.aura.dir == NORTH) S.aura.layer = MECH_UNDER_LAYER else S.aura.layer = ABOVE_MOB_LAYER update_icon() /mob/living/heavy_vehicle/Move() if(..() && !istype(loc, /turf/space)) if(legs && legs.mech_step_sound) playsound(src.loc,legs.mech_step_sound,40,1) get_cell()?.use(legs.power_use * CELLRATE) update_icon() /mob/living/heavy_vehicle/attackby(var/obj/item/thing, var/mob/user) if(user.a_intent != I_HURT && istype(thing, /obj/item/mecha_equipment)) if(hardpoints_locked) to_chat(user, "Hardpoint system access is disabled.") return var/obj/item/mecha_equipment/realThing = thing if(realThing.owner) return var/free_hardpoints = list() for(var/hardpoint in hardpoints) if(hardpoints[hardpoint] == null) free_hardpoints += hardpoint var/to_place = input("Where would you like to install it?") as null|anything in (realThing.restricted_hardpoints & free_hardpoints) if(install_system(thing, to_place, user)) return to_chat(user, "\The [thing] could not be installed in that hardpoint.") return else if(user.a_intent != I_HURT) if(istype(thing, /obj/item/remote_mecha)) if(length(pilots)) to_chat(user, SPAN_WARNING("You can't apply this upgrade while \the [src] has occupants!")) return if(!maintenance_protocols) to_chat(user, SPAN_WARNING("You are unable to apply this upgrade while \the [src]'s maintenance protocols are not active.")) return user.visible_message(SPAN_NOTICE("\The [user] begins installing \the [thing] into \the [src]..."), SPAN_NOTICE("You begin installing the [thing] into \the [src]...")) if(do_after(user, 30, TRUE, src)) if(length(pilots)) to_chat(user, SPAN_WARNING("You can't apply this upgrade while \the [src] has occupants!")) return if(!maintenance_protocols) to_chat(user, SPAN_WARNING("You are unable to apply this upgrade while \the [src]'s maintenance protocols are not active.")) return var/obj/item/remote_mecha/RM = thing user.visible_message(SPAN_NOTICE("\The [user] installs \the [thing] into \the [src]."), SPAN_NOTICE("You install the [thing] into \the [src].")) remote_network = RM.mech_remote_network does_hardpoint_lock = RM.hardpoint_lock dummy_type = RM.dummy_path become_remote() qdel(thing) else if(thing.ismultitool()) if(hardpoints_locked) to_chat(user, "Hardpoint system access is disabled.") return var/list/parts = list() for(var/hardpoint in hardpoints) if(hardpoints[hardpoint]) parts += hardpoint var/to_remove = input("Which component would you like to remove") as null|anything in parts if(remove_system(to_remove, user)) return to_chat(user, "\The [src] has no hardpoint systems to remove.") return else if(thing.iswrench()) if(length(pilots)) to_chat(user, SPAN_WARNING("You can't disassemble \the [src] while it has a pilot!")) return if(!maintenance_protocols) to_chat(user, SPAN_WARNING("The securing bolts are not visible while maintenance protocols are disabled.")) return user.visible_message(SPAN_NOTICE("\The [user] starts dismantling \the [src]..."), SPAN_NOTICE("You start disassembling \the [src]...")) if(do_after(user, 30, TRUE, src)) if(length(pilots)) to_chat(user, SPAN_WARNING("You can't disassemble \the [src] while it has a pilot!")) return if(!maintenance_protocols) to_chat(user, SPAN_WARNING("The securing bolts are not visible while maintenance protocols are disabled.")) return user.visible_message(SPAN_NOTICE("\The [user] dismantles \the [src]."), SPAN_NOTICE("You disassemble \the [src].")) dismantle() return else if(thing.iswelder()) if(!getBruteLoss()) return var/list/damaged_parts = list() for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) if(MC && MC.brute_damage) damaged_parts += MC var/obj/item/mech_component/to_fix = input(user,"Which component would you like to fix?") as null|anything in damaged_parts if(CanInteract(user, physical_state) && !QDELETED(to_fix) && (to_fix in src) && to_fix.brute_damage) to_fix.repair_brute_generic(thing, user) return else if(thing.iscoil()) if(!getFireLoss()) return var/list/damaged_parts = list() for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) if(MC && MC.burn_damage) damaged_parts += MC var/obj/item/mech_component/to_fix = input(user,"Which component would you like to fix?") as null|anything in damaged_parts if(CanInteract(user, physical_state) && !QDELETED(to_fix) && (to_fix in src) && to_fix.burn_damage) to_fix.repair_burn_generic(thing, user) return else if(thing.iscrowbar()) if(!maintenance_protocols) to_chat(user, "The cell compartment remains locked while maintenance protocols are disabled.") return if(!body || !body.cell) to_chat(user, "There is no cell here for you to remove!") return var/delay = 10 if(!do_after(user, delay) || !maintenance_protocols || !body || !body.cell) return user.put_in_hands(body.cell) to_chat(user, "You remove \the [body.cell] from \the [src].") playsound(user.loc, thing.usesound, 50, 1) visible_message("\The [user] pries out \the [body.cell] using the \the [thing].") body.cell = null return else if(istype(thing, /obj/item/cell)) if(!maintenance_protocols) to_chat(user, "The cell compartment remains locked while maintenance protocols are disabled.") return if(!body || body.cell) to_chat(user, "There is already a cell in there!") return if(user.unEquip(thing)) thing.forceMove(body) body.cell = thing to_chat(user, "You install \the [body.cell] into \the [src].") playsound(user.loc, 'sound/items/screwdriver.ogg', 50, 1) visible_message("\The [user] installs \the [body.cell] into \the [src].") return else if(istype(thing, /obj/item/device/robotanalyzer)) to_chat(user, SPAN_NOTICE("Diagnostic Report for \the [src]:")) for(var/obj/item/mech_component/limb in list (head, body, arms, legs)) if(limb) limb.return_diagnostics(user) return return ..() /mob/living/heavy_vehicle/attack_hand(var/mob/user) // Drag the pilot out if possible. if(user.a_intent == I_HURT || user.a_intent == I_GRAB) if(!LAZYLEN(pilots)) to_chat(user, "There is nobody inside \the [src].") else if(!hatch_closed) var/mob/pilot = pick(pilots) user.visible_message("\The [user] is trying to pull \the [pilot] out of \the [src]!") if(do_after(user, 30) && user.Adjacent(src) && (pilot in pilots) && !hatch_closed) user.visible_message("\The [user] drags \the [pilot] out of \the [src]!") eject(pilot, silent=1) return // Otherwise toggle the hatch. if(hatch_locked) to_chat(user, "The [body.hatch_descriptor] is locked.") return hatch_closed = !hatch_closed to_chat(user, "You [hatch_closed ? "close" : "open"] the [body.hatch_descriptor].") hud_open.update_icon() update_icon() return /mob/living/heavy_vehicle/proc/attack_self(var/mob/user) return visible_message("\The [src] pokes itself.") /mob/living/heavy_vehicle/get_inventory_slot(obj/item/I) for(var/h in hardpoints) if(hardpoints[h] == I) return h return 0 /var/global/datum/topic_state/default/mech_state = new() /datum/topic_state/default/mech/can_use_topic(var/mob/living/heavy_vehicle/src_object, var/mob/user) if(istype(src_object)) if(user in src_object.pilots) return ..() else return STATUS_CLOSE return ..() /mob/living/heavy_vehicle/get_inventory_slot(obj/item/I) for(var/h in hardpoints) if(hardpoints[h] == I) return h return 0 /mob/living/heavy_vehicle/proc/rename(var/mob/user) if(user != src && !(user in pilots)) return var/new_name = sanitize(input("Enter a new exosuit designation.", "Exosuit Name") as text|null, max_length = MAX_NAME_LEN) if(!new_name || new_name == name || (user != src && !(user in pilots))) return name = new_name to_chat(user, "You have redesignated this exosuit as \the [name].") /mob/living/heavy_vehicle/proc/trample(var/mob/living/H) if(!LAZYLEN(pilots)) return if(!isliving(H)) return if(legs?.trample_damage) if(ishuman(H)) var/mob/living/carbon/human/D = H if(D.lying) D.attack_log += "\[[time_stamp()]\] Was trampled by [src]" attack_log += text("\[[time_stamp()]\] trampled [D.name] ([D.ckey]) with \the [src].") msg_admin_attack("[src] trampled [key_name(D)] at (JMP)" ) src.visible_message("\The [src] runs over \the [D]!") D.apply_damage(legs.trample_damage, BRUTE) return TRUE else var/mob/living/L = H src.visible_message("\The [src] runs over \the [L]!") if(isanimal(L)) if(issmall(L) && (L.stat == DEAD)) L.gib() return TRUE L.apply_damage(legs.trample_damage, BRUTE) return TRUE /mob/living/heavy_vehicle/proc/ToggleLockdown() lockdown = !lockdown if(lockdown) src.visible_message("\The [src] beeps loudly as its servos sieze up, and it enters lockdown mode!") else src.visible_message("\The [src] hums with life as it is released from its lockdown mode!")