mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 08:37:43 +01:00
Cleans up mech code, refactors Durand (#96942)
## About The Pull Request Mechs store almost all of their behaviors on base /mecha type, such as Maradeur's smoke charges and zoom or Phazon's phasing. I've moved all mech type specific variables and interactions onto their own types, cleaned up general code and refactored how Durand's shield is handled (it is now displayed in vis_contents and no longer an object present on the turf) ## Changelog 🆑 code: Cleaned up generic mech code and moved subtype specific behaviors to said subtypes refactor: Refactored how Durand's shield works /🆑
This commit is contained in:
@@ -37,15 +37,15 @@
|
||||
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi'
|
||||
/// Significantly heavier than humans
|
||||
inertia_force_weight = 5
|
||||
///How much energy the mech will consume each time it moves. this is the current active energy consumed
|
||||
/// How much energy the mech will consume each time it moves. this is the current active energy consumed
|
||||
var/step_energy_drain = 0.008 * STANDARD_CELL_CHARGE
|
||||
///How much energy we drain each time we mechpunch someone
|
||||
/// How much energy we drain each time we mechpunch someone
|
||||
var/melee_energy_drain = 0.015 * STANDARD_CELL_CHARGE
|
||||
///Power we use to have the lights on
|
||||
/// Power we use to have the lights on
|
||||
var/light_power_drain = 0.002 * STANDARD_CELL_RATE
|
||||
///Modifiers for directional damage reduction
|
||||
/// Modifiers for directional damage reduction
|
||||
var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 0.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 1.5)
|
||||
///if we cant use our equipment(such as due to EMP)
|
||||
/// 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/power_store/cell
|
||||
@@ -55,59 +55,59 @@
|
||||
var/obj/item/stock_parts/capacitor/capacitor
|
||||
/// Keeps track of the mech's servo motor
|
||||
var/obj/item/stock_parts/servo/servo
|
||||
///Contains flags for the mecha
|
||||
/// Contains flags for the mecha
|
||||
var/mecha_flags = CAN_STRAFE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE | BEACON_TRACKABLE | AI_COMPATIBLE | BEACON_CONTROLLABLE
|
||||
|
||||
///Spark effects are handled by this datum
|
||||
/// Spark effects are handled by this datum
|
||||
var/datum/effect_system/basic/spark_spread/spark_system
|
||||
///How powerful our lights are
|
||||
/// How powerful our lights are
|
||||
var/lights_power = 6
|
||||
///Just stop the mech from doing anything
|
||||
/// Just stop the mech from doing anything
|
||||
var/completely_disabled = FALSE
|
||||
///Whether this mech is allowed to move diagonally
|
||||
/// Whether this mech is allowed to move diagonally
|
||||
var/allow_diagonal_movement = TRUE
|
||||
///Whether this mech moves into a direct as soon as it goes to move. Basically, turn and step in the same key press.
|
||||
/// Whether this mech moves into a direct as soon as it goes to move. Basically, turn and step in the same key press.
|
||||
var/pivot_step = FALSE
|
||||
///Whether or not the mech destroys walls by running into it.
|
||||
/// Whether or not the mech destroys walls by running into it.
|
||||
var/bumpsmash = FALSE
|
||||
|
||||
///////////ATMOS
|
||||
///Whether the cabin exchanges gases with the environment
|
||||
// Atmos stuff
|
||||
/// Whether the cabin exchanges gases with the environment
|
||||
var/cabin_sealed = FALSE
|
||||
///Internal air mix datum
|
||||
/// Internal air mix datum
|
||||
var/datum/gas_mixture/cabin_air
|
||||
///Volume of the cabin
|
||||
/// Volume of the cabin
|
||||
var/cabin_volume = TANK_STANDARD_VOLUME * 3
|
||||
|
||||
///List of installed remote tracking beacons, including AI control beacons
|
||||
/// List of installed remote tracking beacons, including AI control beacons
|
||||
var/list/trackers = list()
|
||||
///Camera installed into the mech
|
||||
/// Camera installed into the mech
|
||||
var/obj/machinery/camera/exosuit/chassis_camera
|
||||
|
||||
var/max_temperature = 25000
|
||||
|
||||
///Bitflags for internal damage
|
||||
/// Bitflags for internal damage
|
||||
var/internal_damage = NONE
|
||||
/// % chance for internal damage to occur
|
||||
var/internal_damage_probability = 20
|
||||
/// list of possibly dealt internal damage for this mech type
|
||||
/// List of possibly dealt internal damage for this mech type
|
||||
var/possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_CABIN_AIR_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT
|
||||
/// damage threshold above which we take component damage
|
||||
/// Damage threshold above which we take component damage
|
||||
var/component_damage_threshold = 10
|
||||
|
||||
///Stores the DNA enzymes of a carbon so tht only they can access the mech
|
||||
/// Stores the DNA enzymes of a carbon so tht only they can access the mech
|
||||
var/dna_lock
|
||||
/// A list of all granted accesses
|
||||
var/list/accesses = list()
|
||||
/// If the mech should require ALL or only ONE of the listed accesses
|
||||
var/one_access = TRUE
|
||||
|
||||
///Typepath for the wreckage it spawns when destroyed
|
||||
/// Typepath for the wreckage it spawns when destroyed
|
||||
var/wreckage
|
||||
///single flag for the type of this mech, determines what kind of equipment can be attached to it
|
||||
/// Single flag for the type of this mech, determines what kind of equipment can be attached to it
|
||||
var/mech_type
|
||||
|
||||
///assoc list: key-typepathlist before init, key-equipmentlist after
|
||||
/// Assoc list: key-typepathlist before init, key-equipmentlist after
|
||||
var/list/equip_by_category = list(
|
||||
MECHA_L_ARM = null,
|
||||
MECHA_R_ARM = null,
|
||||
@@ -115,7 +115,7 @@
|
||||
MECHA_POWER = list(),
|
||||
MECHA_ARMOR = list(),
|
||||
)
|
||||
///assoc list: max equips for modules key-count
|
||||
/// Assoc list: max equips for modules key-count
|
||||
var/list/max_equip_by_category = list(
|
||||
MECHA_L_ARM = 1,
|
||||
MECHA_R_ARM = 1,
|
||||
@@ -123,94 +123,71 @@
|
||||
MECHA_POWER = 1,
|
||||
MECHA_ARMOR = 0,
|
||||
)
|
||||
///flat equipment for iteration
|
||||
/// Flat equipment for iteration
|
||||
var/list/flat_equipment
|
||||
|
||||
///Handles an internal ore box for mining mechs
|
||||
/// Internal ore box for mining mechs, or one picked up by a hydraulic clamp
|
||||
var/obj/structure/ore_box/ore_box
|
||||
|
||||
///Whether our steps are silent due to no gravity
|
||||
var/step_silent = FALSE
|
||||
///Sound played when the mech moves
|
||||
/// Sound played when the mech moves
|
||||
var/stepsound = 'sound/vehicles/mecha/mechstep.ogg'
|
||||
///Sound played when the mech walks
|
||||
/// Sound played when the mech walks
|
||||
var/turnsound = 'sound/vehicles/mecha/mechturn.ogg'
|
||||
///Sounds for types of melee attack
|
||||
/// Sounds for types of melee attack
|
||||
var/brute_attack_sound = 'sound/items/weapons/punch4.ogg'
|
||||
var/burn_attack_sound = 'sound/items/tools/welder.ogg'
|
||||
var/tox_attack_sound = 'sound/effects/spray2.ogg'
|
||||
///Sound on wall destroying
|
||||
/// Sound on wall destroying
|
||||
var/destroy_wall_sound = 'sound/effects/meteorimpact.ogg'
|
||||
|
||||
///Melee attack verb
|
||||
/// Melee attack verb
|
||||
var/list/attack_verbs = list("hit", "hits", "hitting")
|
||||
|
||||
///Cooldown duration between melee punches
|
||||
/// Cooldown duration between melee punches
|
||||
var/melee_cooldown = CLICK_CD_SLOW
|
||||
|
||||
///TIme taken to leave the mech
|
||||
/// 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
|
||||
/// Time you get slept for if you get forcible ejected by the mech exploding
|
||||
var/destruction_sleep_duration = 2 SECONDS
|
||||
///In case theres a different iconstate for AI/MMI pilot(currently only used for ripley)
|
||||
/// 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
|
||||
/// Currently ejecting, and unable to do things
|
||||
var/is_currently_ejecting = FALSE
|
||||
///Safety for weapons. Won't fire if enabled, and toggled by middle click.
|
||||
/// Safety for weapons. Won't fire if enabled, and toggled by middle click.
|
||||
var/weapons_safety = FALSE
|
||||
///Don't play standard sound when set safety if TRUE.
|
||||
/// Don't play standard sound when set safety if TRUE.
|
||||
var/safety_sound_custom = FALSE
|
||||
|
||||
var/datum/effect_system/fluid_spread/smoke/smoke_system
|
||||
|
||||
////Action vars
|
||||
///Ref to any active thrusters we might have
|
||||
// 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
|
||||
/// Bool for leg overload on/off
|
||||
VAR_FINAL/overclock_mode = FALSE
|
||||
///Whether it is possible to toggle overclocking from the cabin
|
||||
/// Whether it is possible to toggle overclocking from the cabin
|
||||
var/can_use_overclock = FALSE
|
||||
///Speed and energy usage modifier for leg overload
|
||||
/// Speed and energy usage modifier for leg overload
|
||||
var/overclock_coeff = 1.5
|
||||
///Current leg actuator temperature. Increases when overloaded, decreases when not.
|
||||
/// Current leg actuator temperature. Increases when overloaded, decreases when not.
|
||||
var/overclock_temp = 0
|
||||
///Temperature threshold at which actuators may start causing internal damage
|
||||
/// Temperature threshold at which actuators may start causing internal damage
|
||||
var/overclock_temp_danger = 15
|
||||
///Whether the mech has an option to enable safe overclocking
|
||||
/// Whether the mech has an option to enable safe overclocking
|
||||
var/overclock_safety_available = FALSE
|
||||
///Whether the overclocking turns off automatically when overheated
|
||||
/// Whether the overclocking turns off automatically when overheated
|
||||
var/overclock_safety = FALSE
|
||||
/// Action type for overclocking, if null - no action
|
||||
var/overclock_action_type = /datum/action/vehicle/sealed/mecha/mech_overclock
|
||||
/// Name of the overclock action
|
||||
var/overclock_name = "overclock"
|
||||
|
||||
//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
|
||||
|
||||
///check for phasing, if it is set to text (to describe how it is phasing: "flying", "phasing") it will let the mech walk through walls.
|
||||
var/phasing = ""
|
||||
///Power we use every time we phaze through something
|
||||
var/phasing_energy_drain = 0.2 * STANDARD_CELL_CHARGE
|
||||
///icon_state for flick() when phazing
|
||||
var/phase_state = ""
|
||||
|
||||
///Wether we are strafing
|
||||
/// Whether we are strafing
|
||||
var/strafe = FALSE
|
||||
|
||||
///Bool for whether this mech can only be used on lavaland
|
||||
var/lavaland_only = FALSE
|
||||
|
||||
/// ref to screen object that displays in the middle of the UI
|
||||
/// Ref to screen object that displays in the middle of the UI
|
||||
var/atom/movable/screen/map_view/ui_view
|
||||
|
||||
/// Theme of the mech TGUI
|
||||
@@ -234,7 +211,6 @@
|
||||
|
||||
spark_system = new(src, 2, FALSE)
|
||||
spark_system.attach(src)
|
||||
smoke_system = new(src, 3, holder = src)
|
||||
|
||||
cabin_air = new(cabin_volume)
|
||||
|
||||
@@ -274,9 +250,9 @@
|
||||
AddElement(/datum/element/hostile_machine)
|
||||
|
||||
/obj/vehicle/sealed/mecha/Destroy()
|
||||
/// If the former occupants get polymorphed, mutated, chestburstered,
|
||||
/// or otherwise replaced by another mob, that mob is no longer in .occupants
|
||||
/// and gets deleted with the mech. However, they do remain in .contents
|
||||
// If the former occupants get polymorphed, mutated, chestburstered,
|
||||
// or otherwise replaced by another mob, that mob is no longer in .occupants
|
||||
// and gets deleted with the mech. However, they do remain in .contents
|
||||
var/list/potential_occupants = contents | occupants
|
||||
for(var/mob/buggy_ejectee in potential_occupants)
|
||||
mob_exit(buggy_ejectee, silent = TRUE, forced = TRUE)
|
||||
@@ -297,7 +273,6 @@
|
||||
QDEL_NULL(servo)
|
||||
QDEL_NULL(cabin_air)
|
||||
QDEL_NULL(spark_system)
|
||||
QDEL_NULL(smoke_system)
|
||||
QDEL_NULL(ui_view)
|
||||
QDEL_LIST(trackers)
|
||||
QDEL_NULL(chassis_camera)
|
||||
@@ -307,7 +282,7 @@
|
||||
diag_hud.remove_atom_from_hud(src) //YEET
|
||||
return ..()
|
||||
|
||||
///Add parts on mech spawning. Skipped in manual construction.
|
||||
/// Add parts on mech spawning. Skipped in manual construction.
|
||||
/obj/vehicle/sealed/mecha/proc/populate_parts()
|
||||
cell = new /obj/item/stock_parts/power_store/cell/high(src)
|
||||
scanmod = new /obj/item/stock_parts/scanning_module(src)
|
||||
@@ -329,37 +304,42 @@
|
||||
|
||||
var/mob/living/silicon/ai/unlucky_ai
|
||||
for(var/mob/living/occupant as anything in occupants)
|
||||
if(isAI(occupant))
|
||||
//FIXME: Nothiing about this block works
|
||||
var/mob/living/silicon/ai/ai = occupant
|
||||
if(!ai.linked_core && !ai.can_shunt) // we probably shouldnt gib AIs with a core or shunting abilities
|
||||
unlucky_ai = occupant
|
||||
ai.investigate_log("has been gibbed by having their mech destroyed.", INVESTIGATE_DEATHS)
|
||||
ai.gib(DROP_ALL_REMAINS) //No wreck, no AI to recover
|
||||
else
|
||||
mob_exit(ai, silent = TRUE, forced = TRUE) // so we dont ghost the AI
|
||||
continue
|
||||
else
|
||||
if(!isAI(occupant))
|
||||
mob_exit(occupant, forced = TRUE)
|
||||
if(!isbrain(occupant)) // who would win.. 1 brain vs 1 sleep proc..
|
||||
occupant.SetSleeping(destruction_sleep_duration)
|
||||
continue
|
||||
|
||||
if(wreckage)
|
||||
var/obj/structure/mecha_wreckage/WR = new wreckage(loc, unlucky_ai)
|
||||
for(var/obj/item/mecha_parts/mecha_equipment/E in flat_equipment)
|
||||
if(E.detachable && prob(30))
|
||||
WR.crowbar_salvage += E
|
||||
E.detach(WR) //detaches from src into WR
|
||||
E.active = TRUE
|
||||
else
|
||||
E.detach(loc)
|
||||
qdel(E)
|
||||
if(cell)
|
||||
WR.crowbar_salvage += cell
|
||||
cell.forceMove(WR)
|
||||
cell.use(rand(0, cell.charge), TRUE)
|
||||
cell = null
|
||||
return ..()
|
||||
var/mob/living/silicon/ai/ai = occupant
|
||||
if(ai.linked_core || ai.can_shunt) // we probably shouldnt gib AIs with a core or shunting abilities
|
||||
mob_exit(ai, silent = TRUE, forced = TRUE) // so we dont ghost the AI
|
||||
continue
|
||||
|
||||
unlucky_ai = occupant
|
||||
ai.investigate_log("has been gibbed by having their mech destroyed.", INVESTIGATE_DEATHS)
|
||||
ai.gib(DROP_ALL_REMAINS) //No wreck, no AI to recover
|
||||
|
||||
if(ore_box)
|
||||
INVOKE_ASYNC(ore_box, TYPE_PROC_REF(/obj/structure/ore_box, dump_box_contents))
|
||||
|
||||
if(!wreckage)
|
||||
return ..()
|
||||
|
||||
var/obj/structure/mecha_wreckage/wreck = new wreckage(loc, unlucky_ai)
|
||||
for(var/obj/item/mecha_parts/mecha_equipment/equipment in flat_equipment)
|
||||
if(equipment.detachable && prob(30))
|
||||
wreck.crowbar_salvage += equipment
|
||||
equipment.detach(wreck) //detaches from src into wreck
|
||||
equipment.active = TRUE
|
||||
else
|
||||
equipment.detach(loc)
|
||||
qdel(equipment)
|
||||
|
||||
if(cell)
|
||||
wreck.crowbar_salvage += cell
|
||||
cell.forceMove(wreck)
|
||||
cell.use(rand(0, cell.charge), TRUE)
|
||||
cell = null
|
||||
|
||||
|
||||
/obj/vehicle/sealed/mecha/update_icon_state()
|
||||
@@ -400,9 +380,9 @@
|
||||
mob_occupant.update_mouse_pointer()
|
||||
|
||||
//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)
|
||||
/obj/vehicle/sealed/mecha/auto_assign_occupant_flags(mob/occupant)
|
||||
if(driver_amount() < max_drivers)
|
||||
add_control_flags(M, FULL_MECHA_CONTROL)
|
||||
add_control_flags(occupant, FULL_MECHA_CONTROL)
|
||||
|
||||
/obj/vehicle/sealed/mecha/generate_actions()
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_eject)
|
||||
@@ -416,14 +396,15 @@
|
||||
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/strafe, VEHICLE_CONTROL_DRIVE)
|
||||
|
||||
/obj/vehicle/sealed/mecha/add_occupant(mob/M, control_flags, forced)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
generate_equipment_actions(M)
|
||||
|
||||
/obj/vehicle/sealed/mecha/remove_occupant(mob/M)
|
||||
remove_all_equipment_actions(M)
|
||||
return ..()
|
||||
|
||||
///Generates action buttons for all eligible equipment and grants them to the occupant with VEHICLE_CONTROL_SETTINGS flag.
|
||||
/// Generates action buttons for all eligible equipment and grants them to the occupant with VEHICLE_CONTROL_SETTINGS flag.
|
||||
/obj/vehicle/sealed/mecha/proc/generate_equipment_actions(mob/occupant)
|
||||
if(!(occupant in occupants) || !(occupants[occupant] & VEHICLE_CONTROL_SETTINGS))
|
||||
return
|
||||
@@ -433,7 +414,7 @@
|
||||
|
||||
grant_equipment_action(occupant, equipment)
|
||||
|
||||
///Removes all equipment actions from a specific occupant.
|
||||
/// Removes all equipment actions from a specific occupant.
|
||||
/obj/vehicle/sealed/mecha/proc/remove_all_equipment_actions(mob/occupant)
|
||||
var/list/actions = LAZYACCESS(occupant_actions, occupant)
|
||||
if(!actions)
|
||||
@@ -442,7 +423,6 @@
|
||||
for(var/equipment_type in actions)
|
||||
if(!ispath(equipment_type, /obj/item/mecha_parts/mecha_equipment))
|
||||
continue
|
||||
|
||||
remove_action_type_from_mob(equipment_type, occupant)
|
||||
|
||||
/**
|
||||
@@ -497,16 +477,6 @@
|
||||
return base_icon_state
|
||||
return "[base_icon_state]-open"
|
||||
|
||||
/obj/vehicle/sealed/mecha/CanPassThrough(atom/blocker, movement_dir, blocker_opinion)
|
||||
if(!phasing || get_charge() <= phasing_energy_drain || throwing)
|
||||
return ..()
|
||||
if(phase_state)
|
||||
flick(phase_state, src)
|
||||
var/turf/destination_turf = get_step(loc, movement_dir)
|
||||
if(!check_teleport_valid(src, destination_turf) || SSmapping.level_trait(destination_turf.z, ZTRAIT_NOPHASE))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/vehicle/sealed/mecha/get_cell()
|
||||
return cell
|
||||
|
||||
@@ -521,7 +491,8 @@
|
||||
to_chat(mob_occupant, span_notice("Equipment control unit has been rebooted successfully."))
|
||||
set_mouse_pointer()
|
||||
|
||||
/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.
|
||||
/// Updates the values given by scanning module and capacitor tier, called when a part is removed or inserted.
|
||||
/obj/vehicle/sealed/mecha/proc/update_part_values()
|
||||
update_energy_drain()
|
||||
|
||||
if(capacitor)
|
||||
@@ -599,7 +570,7 @@
|
||||
|
||||
/obj/vehicle/sealed/mecha/generate_integrity_message()
|
||||
var/examine_text = ""
|
||||
var/integrity = atom_integrity*100/max_integrity
|
||||
var/integrity = atom_integrity / max_integrity * 100
|
||||
|
||||
switch(integrity)
|
||||
if(85 to 100)
|
||||
@@ -615,7 +586,7 @@
|
||||
|
||||
return examine_text
|
||||
|
||||
///Locate an internal tack in the utility modules
|
||||
/// Locate an internal tack in the utility modules
|
||||
/obj/vehicle/sealed/mecha/proc/get_internal_tank()
|
||||
var/obj/item/mecha_parts/mecha_equipment/air_tank/module = locate(/obj/item/mecha_parts/mecha_equipment/air_tank) in equip_by_category[MECHA_UTILITY]
|
||||
return module?.internal_tank
|
||||
@@ -742,7 +713,7 @@
|
||||
playsound(src,'sound/machines/clockcult/brass_skewer.ogg', 40, TRUE)
|
||||
log_message("Toggled lights off due to the lack of power.", LOG_MECHA)
|
||||
|
||||
///Called when a driver clicks somewhere. Handles everything like equipment, punches, etc.
|
||||
/// Called when a driver clicks somewhere. Handles everything like equipment, punches, etc.
|
||||
/obj/vehicle/sealed/mecha/proc/on_mouseclick(mob/user, atom/target, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
|
||||
@@ -756,14 +727,7 @@
|
||||
return
|
||||
if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled
|
||||
return
|
||||
if(completely_disabled || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT))
|
||||
return
|
||||
if(phasing)
|
||||
balloon_alert(user, "not while [phasing]!")
|
||||
return
|
||||
if(user.incapacitated)
|
||||
return
|
||||
if(!get_charge())
|
||||
if(can_interact_with(target, user, modifiers))
|
||||
return
|
||||
if(src == target)
|
||||
return
|
||||
@@ -818,6 +782,15 @@
|
||||
if(target.mech_melee_attack(src, user))
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown)
|
||||
|
||||
/obj/vehicle/sealed/mecha/proc/can_interact_with(atom/target, mob/user, list/modifiers)
|
||||
if(completely_disabled || is_currently_ejecting || (mecha_flags & CANNOT_INTERACT))
|
||||
return FALSE
|
||||
if(user.incapacitated)
|
||||
return FALSE
|
||||
if(!get_charge())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Driver alt clicks anything while in mech
|
||||
/obj/vehicle/sealed/mecha/proc/on_click_alt(mob/user, atom/target, params)
|
||||
SIGNAL_HANDLER
|
||||
@@ -837,13 +810,13 @@
|
||||
toggle_strafe()
|
||||
|
||||
|
||||
/// middle mouse click signal wrapper for AI users
|
||||
/// Middle mouse click signal wrapper for AI users
|
||||
/obj/vehicle/sealed/mecha/proc/on_middlemouseclick(mob/user, atom/target, params)
|
||||
SIGNAL_HANDLER
|
||||
if(isAI(user))
|
||||
on_mouseclick(user, target, params)
|
||||
|
||||
///Displays a special speech bubble when someone inside the mecha speaks
|
||||
/// Displays a special speech bubble when someone inside the mecha speaks
|
||||
/obj/vehicle/sealed/mecha/proc/display_speech_bubble(datum/source, list/speech_args)
|
||||
SIGNAL_HANDLER
|
||||
var/list/speech_bubble_recipients = list()
|
||||
@@ -854,10 +827,7 @@
|
||||
var/image/mech_speech = image('icons/mob/effects/talk.dmi', src, "machine[say_test(speech_args[SPEECH_MESSAGE])]",MOB_LAYER+1)
|
||||
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay_global), mech_speech, speech_bubble_recipients, 3 SECONDS)
|
||||
|
||||
/////////////////////////////////////
|
||||
//////// Atmospheric stuff ////////
|
||||
/////////////////////////////////////
|
||||
|
||||
// Atmospheric stuff
|
||||
/obj/vehicle/sealed/mecha/remove_air(amount)
|
||||
if((mecha_flags & IS_ENCLOSED) && cabin_sealed)
|
||||
return cabin_air.remove(amount)
|
||||
@@ -871,17 +841,17 @@
|
||||
/obj/vehicle/sealed/mecha/return_analyzable_air()
|
||||
return cabin_air
|
||||
|
||||
///fetches pressure of the gas mixture we are using
|
||||
/// Fetches pressure of the gas mixture we are using
|
||||
/obj/vehicle/sealed/mecha/proc/return_pressure()
|
||||
var/datum/gas_mixture/air = return_air()
|
||||
return air?.return_pressure()
|
||||
|
||||
///fetches temp of the gas mixture we are using
|
||||
/// Fetches temp of the gas mixture we are using
|
||||
/obj/vehicle/sealed/mecha/return_temperature()
|
||||
var/datum/gas_mixture/air = return_air()
|
||||
return air?.return_temperature()
|
||||
|
||||
///makes cabin unsealed, dumping cabin air outside or airtight filling the cabin with external air mix
|
||||
/// Makes cabin unsealed, dumping cabin air outside or airtight filling the cabin with external air mix
|
||||
/obj/vehicle/sealed/mecha/proc/set_cabin_seal(mob/user, cabin_sealed)
|
||||
if(!(mecha_flags & IS_ENCLOSED))
|
||||
balloon_alert(user, "cabin can't be sealed!")
|
||||
@@ -962,16 +932,18 @@
|
||||
overclock_mode = forced_state
|
||||
else
|
||||
overclock_mode = !overclock_mode
|
||||
|
||||
log_message("Toggled [overclock_name].", LOG_MECHA)
|
||||
for(var/mob/occupant as anything in occupants)
|
||||
balloon_alert(occupant, "[overclock_name] [overclock_mode ? "on":"off"]")
|
||||
var/datum/action/act = locate(/datum/action/vehicle/sealed/mecha/mech_overclock) in occupant.actions
|
||||
act?.build_all_button_icons(UPDATE_BUTTON_ICON)
|
||||
|
||||
if(overclock_mode)
|
||||
movedelay = movedelay / overclock_coeff
|
||||
movedelay /= overclock_coeff
|
||||
visible_message(span_notice("[src] starts heating up, making humming sounds."))
|
||||
else
|
||||
movedelay = initial(movedelay)
|
||||
movedelay *= overclock_coeff
|
||||
visible_message(span_notice("[src] cools down and the humming stops."))
|
||||
update_energy_drain()
|
||||
return TRUE
|
||||
@@ -982,15 +954,14 @@
|
||||
step_energy_drain = initial(step_energy_drain) / servo.rating
|
||||
else
|
||||
step_energy_drain = 2 * initial(step_energy_drain)
|
||||
|
||||
if(overclock_mode)
|
||||
step_energy_drain *= overclock_coeff
|
||||
|
||||
if(capacitor)
|
||||
phasing_energy_drain = initial(phasing_energy_drain) / capacitor.rating
|
||||
melee_energy_drain = initial(melee_energy_drain) / capacitor.rating
|
||||
light_power_drain = initial(light_power_drain) / capacitor.rating
|
||||
else
|
||||
phasing_energy_drain = initial(phasing_energy_drain)
|
||||
melee_energy_drain = initial(melee_energy_drain)
|
||||
light_power_drain = initial(light_power_drain)
|
||||
|
||||
|
||||
@@ -20,7 +20,13 @@
|
||||
MECHA_POWER = 1,
|
||||
MECHA_ARMOR = 1,
|
||||
)
|
||||
var/obj/durand_shield/shield
|
||||
|
||||
/// Bool for energy shield on/off
|
||||
var/defense_mode = FALSE
|
||||
/// Fake shield object we use as a way to redirect attacks off ourselves
|
||||
var/obj/durand_shield/shield = null
|
||||
/// Is the shield currently switching modes?
|
||||
var/switching = FALSE
|
||||
|
||||
/datum/armor/mecha_durand
|
||||
melee = 40
|
||||
@@ -33,137 +39,145 @@
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/Initialize(mapload)
|
||||
. = ..()
|
||||
shield = new /obj/durand_shield(loc, src, plane, layer, dir)
|
||||
RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(relay))
|
||||
shield = new(src, src)
|
||||
vis_contents += shield
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/Destroy()
|
||||
if(shield)
|
||||
QDEL_NULL(shield)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/generate_actions()
|
||||
. = ..()
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_defense_mode)
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/process()
|
||||
. = ..()
|
||||
if(defense_mode && !use_energy(0.01 * STANDARD_CELL_CHARGE)) //Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle
|
||||
for(var/O in occupants)
|
||||
var/mob/living/occupant = O
|
||||
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
|
||||
if(action)
|
||||
action.Trigger()
|
||||
break
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/Move(direction)
|
||||
. = ..()
|
||||
if(shield)
|
||||
shield.forceMove(loc)
|
||||
shield.setDir(dir)
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/forceMove(turf/T)
|
||||
. = ..()
|
||||
shield.forceMove(T)
|
||||
// Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle
|
||||
if(defense_mode && !use_energy(0.01 * STANDARD_CELL_CHARGE))
|
||||
toggle_defense()
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/mob_exit(mob/M, silent = FALSE, randomstep = FALSE, forced = FALSE)
|
||||
if(defense_mode)
|
||||
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, M, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
|
||||
if(action)
|
||||
INVOKE_ASYNC(action, TYPE_PROC_REF(/datum/action, Trigger), null, NONE, FALSE)
|
||||
toggle_defense()
|
||||
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/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)
|
||||
|
||||
//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true.
|
||||
/obj/vehicle/sealed/mecha/durand/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked)
|
||||
if(defense_check(hitting_projectile.loc) && shield)
|
||||
return shield.projectile_hit(hitting_projectile, def_zone, piercing_hit, blocked)
|
||||
return ..()
|
||||
|
||||
/**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.*/
|
||||
/**
|
||||
* 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/durand/proc/defense_check(turf/aloc)
|
||||
if (!defense_mode || !shield || shield.switching)
|
||||
if (!defense_mode || !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
|
||||
if (NORTH)
|
||||
return abs(x - aloc.x) <= (y - aloc.y) * -2
|
||||
if (SOUTH)
|
||||
return abs(x - aloc.x) <= (y - aloc.y) * 2
|
||||
if (EAST)
|
||||
return abs(y - aloc.y) <= (x - aloc.x) * -2
|
||||
if (WEST)
|
||||
return abs(y - aloc.y) <= (x - aloc.x) * 2
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/proc/toggle_defense(mob/living/user)
|
||||
if(!LAZYLEN(occupants))
|
||||
return
|
||||
|
||||
if(switching && (user || !defense_mode)) // Allow force shutdowns during animation
|
||||
return
|
||||
|
||||
if(!defense_mode && cell?.charge < 100) // If it's off, and we have less than 100 units of power
|
||||
if (user)
|
||||
balloon_alert(user, "insufficient power")
|
||||
return
|
||||
|
||||
switching = TRUE
|
||||
defense_mode = !defense_mode
|
||||
|
||||
if(user)
|
||||
balloon_alert(user, "shield [defense_mode ? "enabled" : "disabled"]")
|
||||
log_message("User has toggled defense mode -- now [defense_mode ? "enabled" : "disabled"].", LOG_MECHA)
|
||||
else
|
||||
log_message("defense mode state changed -- now [defense_mode ? "enabled" : "disabled"].", LOG_MECHA)
|
||||
|
||||
for(var/mob/living/occupant as anything in occupants)
|
||||
var/datum/action/button = occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode]
|
||||
button.button_icon_state = "mech_defense_mode_[defense_mode ? "on" : "off"]"
|
||||
button.build_all_button_icons()
|
||||
|
||||
shield.set_light_on(defense_mode)
|
||||
|
||||
if(defense_mode)
|
||||
shield.icon_state = "shield"
|
||||
flick("shield_raise", shield)
|
||||
playsound(src, 'sound/vehicles/mecha/mech_shield_raise.ogg', 50, FALSE)
|
||||
else
|
||||
shield.icon_state = "shield_null"
|
||||
flick("shield_drop", shield)
|
||||
playsound(src, 'sound/vehicles/mecha/mech_shield_drop.ogg', 50, FALSE)
|
||||
|
||||
addtimer(VARSET_CALLBACK(src, switching, FALSE), 0.7 SECONDS) // Shield animation length
|
||||
|
||||
/obj/vehicle/sealed/mecha/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))
|
||||
if(defense_check(get_turf(user)))
|
||||
log_message("Attack absorbed by defense field. Attacker - [user].", LOG_MECHA, color="orange")
|
||||
return shield.attack_generic(user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/mecha/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/durand/blob_act(obj/structure/blob/blob)
|
||||
if(!defense_check(get_turf(blob)))
|
||||
return ..()
|
||||
log_message("Attack by blob. Attacker - [blob].", LOG_MECHA, color="red")
|
||||
log_message("Attack absorbed by defense field.", LOG_MECHA, color="orange")
|
||||
return shield.blob_act(blob)
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/attackby(obj/item/W as obj, mob/user as mob, list/modifiers, list/attack_modifiers)
|
||||
if(defense_check(user.loc))
|
||||
log_message("Attack absorbed by defense field. Attacker - [user], with [W]", LOG_MECHA, color="orange")
|
||||
shield.attackby(W, user, modifiers)
|
||||
else
|
||||
. = ..()
|
||||
/obj/vehicle/sealed/mecha/durand/attackby(obj/item/weapon, mob/user as mob, list/modifiers, list/attack_modifiers)
|
||||
if(defense_check(get_turf(user)))
|
||||
log_message("Attack absorbed by defense field. Attacker - [user], with [weapon]", LOG_MECHA, color="orange")
|
||||
return shield.attackby(weapon, user, modifiers)
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/mecha/durand/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
if(defense_check(AM.loc))
|
||||
if(defense_check(get_turf(AM)))
|
||||
log_message("Impact with [AM] absorbed by defense field.", LOG_MECHA, color="orange")
|
||||
shield.hitby(AM, skipcatch, hitpush, blocked, throwingdatum)
|
||||
else
|
||||
. = ..()
|
||||
return shield.hitby(AM, skipcatch, hitpush, blocked, throwingdatum)
|
||||
return ..()
|
||||
|
||||
/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."
|
||||
name = "Toggle Shield"
|
||||
desc = "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(mob/clicker, trigger_flags, forced_state = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!chassis || !(owner in chassis.occupants))
|
||||
return
|
||||
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
|
||||
if(chassis && (owner in chassis.occupants))
|
||||
var/obj/vehicle/sealed/mecha/durand/durand = chassis
|
||||
durand.toggle_defense(owner)
|
||||
|
||||
////////////////////////////
|
||||
///// Shield processing ////
|
||||
////////////////////////////
|
||||
// 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.*/
|
||||
/**
|
||||
* An object to take the hit for us when using the Durand's defense mode.
|
||||
* It is spawned in during the durand's initilization.
|
||||
* 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/mob/effects/durand_shield.dmi'
|
||||
icon_state = "shield_null"
|
||||
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
|
||||
pixel_y = 4
|
||||
pixel_z = 4
|
||||
max_integrity = 10000
|
||||
anchored = TRUE
|
||||
light_system = OVERLAY_LIGHT
|
||||
@@ -171,100 +185,22 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
|
||||
light_power = 1
|
||||
light_color = LIGHT_COLOR_FAINT_CYAN
|
||||
light_on = FALSE
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF //The shield should not take damage from fire, lava, or acid; that's the mech's job.
|
||||
///Our link back to the durand
|
||||
light_flags = LIGHT_ATTACHED
|
||||
vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF // The shield should not take damage from fire, lava, or acid; that's the mech's job.
|
||||
/// Our link back to the durand
|
||||
var/obj/vehicle/sealed/mecha/durand/chassis
|
||||
///To keep track of things during the animation
|
||||
var/switching = FALSE
|
||||
|
||||
/obj/durand_shield/Initialize(mapload, chassis, plane, layer, dir)
|
||||
/obj/durand_shield/Initialize(mapload, obj/vehicle/sealed/mecha/durand/chassis)
|
||||
. = ..()
|
||||
src.chassis = chassis
|
||||
src.layer = ABOVE_MOB_LAYER
|
||||
SET_PLANE_IMPLICIT(src, plane)
|
||||
setDir(dir)
|
||||
RegisterSignal(chassis, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(activate))
|
||||
RegisterSignal(chassis, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(shield_glide_size_update))
|
||||
|
||||
/obj/durand_shield/Destroy()
|
||||
UnregisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER)
|
||||
if(chassis)
|
||||
UnregisterSignal(chassis, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE)
|
||||
chassis.shield = null
|
||||
chassis = null
|
||||
return ..()
|
||||
|
||||
/obj/durand_shield/proc/shield_glide_size_update(datum/source, target)
|
||||
SIGNAL_HANDLER
|
||||
glide_size = target
|
||||
|
||||
/**
|
||||
* 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" variable, `signal_args[1]`, will
|
||||
* skip the to-pilot text and is meant for when the shield is disabled by
|
||||
* means other than the action button (like running out of power).
|
||||
*
|
||||
* Arguments:
|
||||
* * source: the shield
|
||||
* * owner: mob that activated the shield
|
||||
* * signal_args: whether it's forced
|
||||
*/
|
||||
/obj/durand_shield/proc/activate(datum/source, mob/owner, list/signal_args)
|
||||
SIGNAL_HANDLER
|
||||
if(!LAZYLEN(chassis?.occupants))
|
||||
return
|
||||
if(switching && !signal_args[1])
|
||||
return
|
||||
if(!chassis.defense_mode && (!chassis.cell || chassis.cell.charge < 100)) //If it's off, and we have less than 100 units of power
|
||||
chassis.balloon_alert(owner, "insufficient power")
|
||||
return
|
||||
switching = TRUE
|
||||
chassis.defense_mode = !chassis.defense_mode
|
||||
if(!signal_args[1])
|
||||
chassis.balloon_alert(owner, "shield [chassis.defense_mode?"enabled":"disabled"]")
|
||||
chassis.log_message("User has toggled defense mode -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
|
||||
else
|
||||
chassis.log_message("defense mode state changed -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
|
||||
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.build_all_button_icons()
|
||||
|
||||
set_light_on(chassis.defense_mode)
|
||||
|
||||
if(chassis.defense_mode)
|
||||
SetInvisibility(INVISIBILITY_NONE, id=type)
|
||||
flick("shield_raise", src)
|
||||
playsound(src, 'sound/vehicles/mecha/mech_shield_raise.ogg', 50, FALSE)
|
||||
icon_state = "shield"
|
||||
resetdir(chassis, dir, dir) // to set the plane for the shield properly when it's turned on
|
||||
RegisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE, PROC_REF(resetdir))
|
||||
else
|
||||
flick("shield_drop", src)
|
||||
playsound(src, 'sound/vehicles/mecha/mech_shield_drop.ogg', 50, FALSE)
|
||||
icon_state = "shield_null"
|
||||
addtimer(CALLBACK(src, PROC_REF(make_invisible)), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
UnregisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE)
|
||||
switching = FALSE
|
||||
|
||||
/**
|
||||
* Sets invisibility to INVISIBILITY_MAXIMUM if defense mode is disabled
|
||||
*
|
||||
* We need invisibility set to higher than 25 for the shield to not appear
|
||||
* in the right-click context menu, but if we do it too early, we miss the
|
||||
* deactivate animation. Hense, timer and this proc.
|
||||
*/
|
||||
/obj/durand_shield/proc/make_invisible()
|
||||
if(!chassis.defense_mode)
|
||||
RemoveInvisibility(type)
|
||||
|
||||
/obj/durand_shield/proc/resetdir(datum/source, olddir, newdir)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
setDir(newdir)
|
||||
|
||||
/obj/durand_shield/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0)
|
||||
if(!chassis)
|
||||
qdel(src)
|
||||
@@ -277,10 +213,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
|
||||
return
|
||||
if(!chassis.use_energy(. * (STANDARD_CELL_CHARGE / 150)))
|
||||
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()
|
||||
chassis.toggle_defense()
|
||||
atom_integrity = 10000
|
||||
|
||||
/obj/durand_shield/play_attack_sound()
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
)
|
||||
bumpsmash = TRUE
|
||||
|
||||
/// Reusable smoke generator system
|
||||
var/datum/effect_system/fluid_spread/smoke/smoke_system
|
||||
/// Remaining smoke charges
|
||||
var/smoke_charges = 5
|
||||
/// Cooldown between using smoke
|
||||
var/smoke_cooldown = 10 SECONDS
|
||||
/// Bool for zoom on/off
|
||||
var/zoom_mode = FALSE
|
||||
|
||||
/datum/armor/mecha_marauder
|
||||
melee = 70
|
||||
bullet = 60
|
||||
@@ -33,6 +42,14 @@
|
||||
fire = 100
|
||||
acid = 100
|
||||
|
||||
/obj/vehicle/sealed/mecha/marauder/Initialize(mapload, built_manually)
|
||||
. = ..()
|
||||
smoke_system = new(src, 3, holder = src)
|
||||
|
||||
/obj/vehicle/sealed/mecha/marauder/Destroy()
|
||||
QDEL_NULL(smoke_system)
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/mecha/marauder/generate_actions()
|
||||
. = ..()
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_smoke)
|
||||
@@ -54,20 +71,51 @@
|
||||
servo = new /obj/item/stock_parts/servo/femto(src)
|
||||
update_part_values()
|
||||
|
||||
/obj/vehicle/sealed/mecha/marauder/remove_occupant(mob/driver)
|
||||
. = ..()
|
||||
zoom_mode = FALSE
|
||||
|
||||
/obj/vehicle/sealed/mecha/marauder/can_move(direction)
|
||||
. = ..()
|
||||
if(!. || !zoom_mode)
|
||||
return
|
||||
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to move while in zoom mode!")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
|
||||
/datum/action/vehicle/sealed/mecha/mech_smoke
|
||||
name = "Smoke"
|
||||
button_icon_state = "mech_smoke"
|
||||
|
||||
/datum/action/vehicle/sealed/mecha/mech_smoke/IsAvailable(feedback)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
|
||||
var/obj/vehicle/sealed/mecha/marauder/maradeur = chassis
|
||||
if(!TIMER_COOLDOWN_FINISHED(maradeur, COOLDOWN_MECHA_SMOKE))
|
||||
if (feedback)
|
||||
owner.balloon_alert(owner, "smoke charges on cooldown!")
|
||||
return FALSE
|
||||
|
||||
if (!maradeur.smoke_charges)
|
||||
if (feedback)
|
||||
owner.balloon_alert(owner, "out of smoke charges!")
|
||||
return FALSE
|
||||
|
||||
/datum/action/vehicle/sealed/mecha/mech_smoke/Trigger(mob/clicker, trigger_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!chassis || !(owner in chassis.occupants))
|
||||
return
|
||||
if(TIMER_COOLDOWN_FINISHED(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)
|
||||
var/obj/vehicle/sealed/mecha/marauder/maradeur = chassis
|
||||
if(TIMER_COOLDOWN_FINISHED(maradeur, COOLDOWN_MECHA_SMOKE) && maradeur.smoke_charges)
|
||||
maradeur.smoke_system.start()
|
||||
maradeur.smoke_charges--
|
||||
TIMER_COOLDOWN_START(maradeur, COOLDOWN_MECHA_SMOKE, maradeur.smoke_cooldown)
|
||||
|
||||
/datum/action/vehicle/sealed/mecha/mech_zoom
|
||||
name = "Zoom"
|
||||
@@ -79,11 +127,12 @@
|
||||
return
|
||||
if(!owner.client || !chassis || !(owner in chassis.occupants))
|
||||
return
|
||||
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)]<font color='[chassis.zoom_mode?"blue":"red"]'>Zoom mode [chassis.zoom_mode?"en":"dis"]abled.</font>")
|
||||
if(chassis.zoom_mode)
|
||||
var/obj/vehicle/sealed/mecha/marauder/maradeur = chassis
|
||||
maradeur.zoom_mode = !maradeur.zoom_mode
|
||||
button_icon_state = "mech_zoom_[maradeur.zoom_mode ? "on" : "off"]"
|
||||
maradeur.log_message("Toggled zoom mode.", LOG_MECHA)
|
||||
to_chat(owner, "[icon2html(maradeur, owner)]<font color='[maradeur.zoom_mode ? "blue" : "red"]'>Zoom mode [maradeur.zoom_mode ? "en" : "dis"]abled.</font>")
|
||||
if(maradeur.zoom_mode)
|
||||
owner.client.view_size.setTo(4.5)
|
||||
SEND_SOUND(owner, sound('sound/vehicles/mecha/imag_enh.ogg', volume=50))
|
||||
else
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/vehicle/sealed/mecha/phazon
|
||||
desc = "This is a Phazon exosuit. The pinnacle of scientific research and pride of Nanotrasen, it uses cutting edge anomalous technology and expensive materials."
|
||||
name = "\improper Phazon"
|
||||
desc = "This is a Phazon exosuit. The pinnacle of scientific research and pride of Nanotrasen, it uses cutting edge anomalous technology and expensive materials."
|
||||
icon_state = "phazon"
|
||||
base_icon_state = "phazon"
|
||||
movedelay = 2
|
||||
@@ -21,7 +21,13 @@
|
||||
MECHA_POWER = 1,
|
||||
MECHA_ARMOR = 2,
|
||||
)
|
||||
phase_state = "phazon-phase"
|
||||
|
||||
/// Are we currently phasing through walls?
|
||||
var/phasing = FALSE
|
||||
/// Power we use every time we phaze through something
|
||||
var/phasing_energy_drain = 0.2 * STANDARD_CELL_CHARGE
|
||||
/// Icon_state for flick() when phasing
|
||||
var/phase_state = "phazon-phase"
|
||||
|
||||
/datum/armor/mecha_phazon
|
||||
melee = 30
|
||||
@@ -37,6 +43,42 @@
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_phasing)
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_switch_damtype)
|
||||
|
||||
/obj/vehicle/sealed/mecha/phazon/CanPassThrough(atom/blocker, movement_dir, blocker_opinion)
|
||||
if(!phasing || get_charge() <= phasing_energy_drain || throwing)
|
||||
return ..()
|
||||
if(phase_state)
|
||||
flick(phase_state, src)
|
||||
var/turf/destination_turf = get_step(loc, movement_dir)
|
||||
if(!check_teleport_valid(src, destination_turf) || SSmapping.level_trait(destination_turf.z, ZTRAIT_NOPHASE))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/vehicle/sealed/mecha/phazon/vehicle_move(direction, forcerotate)
|
||||
. = ..()
|
||||
if(. && phasing)
|
||||
use_energy(phasing_energy_drain)
|
||||
|
||||
/obj/vehicle/sealed/mecha/phazon/try_bumpsmash(atom/obstacle)
|
||||
if(phasing) // Theres only one cause for phasing canpass fails
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("A dull, universal force is preventing you from phasing here!")]")
|
||||
spark_system.start()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/mecha/phazon/update_energy_drain()
|
||||
. = ..()
|
||||
if(capacitor)
|
||||
phasing_energy_drain = initial(phasing_energy_drain) / capacitor.rating
|
||||
else
|
||||
phasing_energy_drain = initial(phasing_energy_drain)
|
||||
|
||||
/obj/vehicle/sealed/mecha/phazon/can_interact_with(atom/target, mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if (!. || !phasing)
|
||||
return
|
||||
balloon_alert(user, "not while phasing!")
|
||||
return FALSE
|
||||
|
||||
/datum/action/vehicle/sealed/mecha/mech_switch_damtype
|
||||
name = "Reconfigure arm microtool arrays"
|
||||
button_icon_state = "mech_damtype_brute"
|
||||
@@ -73,7 +115,8 @@
|
||||
return
|
||||
if(!chassis || !(owner in chassis.occupants))
|
||||
return
|
||||
chassis.phasing = chassis.phasing ? "" : "phasing"
|
||||
button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]"
|
||||
chassis.balloon_alert(owner, "[chassis.phasing ? "enabled" : "disabled"] phasing")
|
||||
var/obj/vehicle/sealed/mecha/phazon/phazon = chassis
|
||||
phazon.phasing = !phazon.phasing
|
||||
button_icon_state = "mech_phasing_[phazon.phasing ? "on" : "off"]"
|
||||
phazon.balloon_alert(owner, "[phazon.phasing ? "enabled" : "disabled"] phasing")
|
||||
build_all_button_icons()
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
MECHA_POWER = 1,
|
||||
MECHA_ARMOR = 1,
|
||||
)
|
||||
//no tax on flying, since the power cost is in the leap itself.
|
||||
phasing_energy_drain = 0
|
||||
/// Are we currently in the middle of a skyfall jump?
|
||||
var/flying = FALSE
|
||||
|
||||
/datum/armor/mecha_savannah_ivanov
|
||||
melee = 45
|
||||
@@ -71,6 +71,22 @@
|
||||
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/skyfall, VEHICLE_CONTROL_DRIVE)
|
||||
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/ivanov_strike, VEHICLE_CONTROL_EQUIPMENT)
|
||||
|
||||
// Pass through obstacles freely if we're flying
|
||||
/obj/vehicle/sealed/mecha/savannah_ivanov/CanPassThrough(atom/blocker, movement_dir, blocker_opinion)
|
||||
if(!flying || throwing)
|
||||
return ..()
|
||||
var/turf/destination_turf = get_step(loc, movement_dir)
|
||||
if(!check_teleport_valid(src, destination_turf) || SSmapping.level_trait(destination_turf.z, ZTRAIT_NOPHASE))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/vehicle/sealed/mecha/savannah_ivanov/can_interact_with(atom/target, mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if (!. || !flying)
|
||||
return
|
||||
balloon_alert(user, "not while airborne!")
|
||||
return FALSE
|
||||
|
||||
///Savannah Skyfall
|
||||
/datum/action/vehicle/sealed/mecha/skyfall
|
||||
name = "Savannah Skyfall"
|
||||
@@ -86,17 +102,18 @@
|
||||
return
|
||||
if(!owner || !chassis || !(owner in chassis.occupants))
|
||||
return
|
||||
if(chassis.phasing)
|
||||
var/obj/vehicle/sealed/mecha/savannah_ivanov/savannah = chassis
|
||||
if(savannah.flying)
|
||||
to_chat(owner, span_warning("You're already airborne!"))
|
||||
return
|
||||
if(TIMER_COOLDOWN_RUNNING(chassis, COOLDOWN_MECHA_SKYFALL))
|
||||
var/timeleft = S_TIMER_COOLDOWN_TIMELEFT(chassis, COOLDOWN_MECHA_SKYFALL)
|
||||
if(TIMER_COOLDOWN_RUNNING(savannah, COOLDOWN_MECHA_SKYFALL))
|
||||
var/timeleft = S_TIMER_COOLDOWN_TIMELEFT(savannah, COOLDOWN_MECHA_SKYFALL)
|
||||
to_chat(owner, span_warning("You need to wait [DisplayTimeText(timeleft, 1)] before attempting to Skyfall."))
|
||||
return
|
||||
if(skyfall_charge_level)
|
||||
abort_skyfall()
|
||||
return
|
||||
chassis.balloon_alert(owner, "charging skyfall...")
|
||||
savannah.balloon_alert(owner, "charging skyfall...")
|
||||
INVOKE_ASYNC(src, PROC_REF(skyfall_charge_loop))
|
||||
|
||||
/**
|
||||
@@ -146,7 +163,8 @@
|
||||
new /obj/effect/skyfall_landingzone(launch_turf, chassis)
|
||||
chassis.resistance_flags |= INDESTRUCTIBLE //not while jumping at least
|
||||
chassis.mecha_flags |= QUIET_STEPS|QUIET_TURNS|CANNOT_INTERACT
|
||||
chassis.phasing = "flying"
|
||||
var/obj/vehicle/sealed/mecha/savannah_ivanov/savannah = chassis
|
||||
savannah.flying = TRUE
|
||||
chassis.movedelay = 1
|
||||
chassis.set_density(FALSE)
|
||||
chassis.layer = ABOVE_ALL_MOB_LAYER
|
||||
@@ -177,7 +195,8 @@
|
||||
playsound(chassis, 'sound/effects/explosion/explosion1.ogg', 50, 1)
|
||||
chassis.resistance_flags &= ~INDESTRUCTIBLE
|
||||
chassis.mecha_flags &= ~(QUIET_STEPS|QUIET_TURNS|CANNOT_INTERACT)
|
||||
chassis.phasing = initial(chassis.phasing)
|
||||
var/obj/vehicle/sealed/mecha/savannah_ivanov/savannah = chassis
|
||||
savannah.flying = FALSE
|
||||
chassis.movedelay = initial(chassis.movedelay)
|
||||
chassis.set_density(TRUE)
|
||||
chassis.layer = initial(chassis.layer)
|
||||
|
||||
@@ -160,8 +160,8 @@
|
||||
if(flags & MECH_DO_AFTER_ADJACENCY_FLAG && !(chassis.Adjacent(target)))
|
||||
return FALSE
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/vehicle/sealed/mecha/M, attach_right = FALSE, mob/user)
|
||||
return default_can_attach(M, attach_right, user)
|
||||
/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/vehicle/sealed/mecha/mech, attach_right = FALSE, mob/user)
|
||||
return default_can_attach(mech, attach_right, user)
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/proc/default_can_attach(obj/vehicle/sealed/mecha/mech, attach_right = FALSE, mob/user)
|
||||
if(!(mech_flags & mech.mech_type))
|
||||
|
||||
@@ -107,7 +107,6 @@
|
||||
|
||||
chassis.toggle_strafe()
|
||||
|
||||
|
||||
/obj/vehicle/sealed/mecha/proc/toggle_strafe()
|
||||
if(!(mecha_flags & CAN_STRAFE))
|
||||
to_chat(occupants, "this mecha doesn't support strafing!")
|
||||
@@ -124,7 +123,7 @@
|
||||
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/strafe)
|
||||
action?.build_all_button_icons()
|
||||
|
||||
///swap seats, for two person mecha
|
||||
/// Swap seats, for two person mecha
|
||||
/datum/action/vehicle/sealed/mecha/swap_seat
|
||||
name = "Switch Seats"
|
||||
button_icon_state = "mech_seat_swap"
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
/obj/vehicle/sealed/mecha/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(. || !user.combat_mode)
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_MELEE) // Ugh. Ideally we shouldn't be setting cooldowns outside of click code.
|
||||
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
|
||||
@@ -73,26 +73,25 @@
|
||||
/obj/vehicle/sealed/mecha/attack_alien(mob/living/user, list/modifiers)
|
||||
log_message("Attack by alien. Attacker - [user].", LOG_MECHA, color="red")
|
||||
playsound(loc, 'sound/items/weapons/slash.ogg', 100, TRUE)
|
||||
attack_generic(user, rand(user.melee_damage_lower, user.melee_damage_upper), BRUTE, MELEE, 0)
|
||||
return attack_generic(user, rand(user.melee_damage_lower, user.melee_damage_upper), BRUTE, MELEE, 0)
|
||||
|
||||
/obj/vehicle/sealed/mecha/attack_animal(mob/living/simple_animal/user, list/modifiers)
|
||||
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
|
||||
return FALSE
|
||||
|
||||
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")
|
||||
return attack_generic(user, animal_damage, user.melee_damage_type, MELEE, play_soundeffect)
|
||||
|
||||
/obj/vehicle/sealed/mecha/hulk_damage()
|
||||
return 15
|
||||
@@ -420,16 +419,18 @@
|
||||
if(servo)
|
||||
stock_parts += servo
|
||||
|
||||
if(length(stock_parts))
|
||||
var/obj/item/stock_parts/part_to_remove = tgui_input_list(user, "Which part to remove?", "Part Removal", stock_parts)
|
||||
if(!(locate(part_to_remove) in contents))
|
||||
return
|
||||
user.put_in_hands(part_to_remove)
|
||||
locate_parts()
|
||||
diag_hud_set_mechcell()
|
||||
tool.play_tool_sound(src)
|
||||
if(!length(stock_parts))
|
||||
balloon_alert(user, "no parts!")
|
||||
return
|
||||
balloon_alert(user, "no parts!")
|
||||
|
||||
var/obj/item/stock_parts/part_to_remove = tgui_input_list(user, "Which part to remove?", "Part Removal", stock_parts)
|
||||
if(!(locate(part_to_remove) in contents))
|
||||
return
|
||||
|
||||
user.put_in_hands(part_to_remove)
|
||||
locate_parts()
|
||||
diag_hud_set_mechcell()
|
||||
tool.play_tool_sound(src)
|
||||
|
||||
/obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W)
|
||||
if(user.combat_mode)
|
||||
@@ -445,7 +446,7 @@
|
||||
return
|
||||
user.balloon_alert_to_viewers("started welding [src]", "started repairing [src]")
|
||||
audible_message(span_hear("You hear welding."))
|
||||
var/did_the_thing
|
||||
var/did_the_thing = FALSE
|
||||
while(atom_integrity < max_integrity)
|
||||
if(W.use_tool(src, user, 2.5 SECONDS, volume=50))
|
||||
did_the_thing = TRUE
|
||||
@@ -453,12 +454,12 @@
|
||||
audible_message(span_hear("You hear welding."))
|
||||
else
|
||||
break
|
||||
|
||||
if(did_the_thing)
|
||||
user.balloon_alert_to_viewers("[(atom_integrity >= max_integrity) ? "fully" : "partially"] repaired [src]")
|
||||
else
|
||||
user.balloon_alert_to_viewers("stopped welding [src]", "interrupted the repair!")
|
||||
|
||||
|
||||
/obj/vehicle/sealed/mecha/proc/full_repair(charge_cell)
|
||||
repair_damage(max_integrity)
|
||||
if(cell && charge_cell)
|
||||
@@ -489,62 +490,66 @@
|
||||
visual_effect_icon = ATTACK_EFFECT_MECHFIRE
|
||||
else if(damtype == TOX)
|
||||
visual_effect_icon = ATTACK_EFFECT_MECHTOXIN
|
||||
..()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/vehicle/sealed/mecha/proc/ammo_resupply(obj/item/mecha_ammo/A, mob/user,fail_chat_override = FALSE)
|
||||
if(!A.rounds)
|
||||
/obj/vehicle/sealed/mecha/proc/ammo_resupply(obj/item/mecha_ammo/ammo, mob/user,fail_chat_override = FALSE)
|
||||
if(!ammo.rounds)
|
||||
if(!fail_chat_override)
|
||||
balloon_alert(user, "the box is empty!")
|
||||
return FALSE
|
||||
|
||||
var/ammo_needed
|
||||
var/found_gun
|
||||
|
||||
for(var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun in flat_equipment)
|
||||
ammo_needed = 0
|
||||
|
||||
if(gun.ammo_type != A.ammo_type)
|
||||
if(gun.ammo_type != ammo.ammo_type)
|
||||
continue
|
||||
found_gun = TRUE
|
||||
if(A.direct_load)
|
||||
if(ammo.direct_load)
|
||||
ammo_needed = initial(gun.projectiles) - gun.projectiles
|
||||
else
|
||||
ammo_needed = gun.projectiles_cache_max - gun.projectiles_cache
|
||||
|
||||
if(!ammo_needed)
|
||||
continue
|
||||
if(ammo_needed < A.rounds)
|
||||
if(A.direct_load)
|
||||
|
||||
if(ammo_needed < ammo.rounds)
|
||||
if(ammo.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, span_notice("You add [ammo_needed] [A.ammo_type][ammo_needed > 1?"s":""] to \the [gun]"))
|
||||
A.rounds = A.rounds - ammo_needed
|
||||
if(A.custom_materials) //Change material content of the ammo box according to the amount of ammo deposited into the weapon
|
||||
playsound(get_turf(user), ammo.load_audio, 50, TRUE)
|
||||
to_chat(user, span_notice("You add [ammo_needed] [ammo.ammo_type][ammo_needed > 1 ? "s" : ""] to \the [gun]"))
|
||||
ammo.rounds = ammo.rounds - ammo_needed
|
||||
if(ammo.custom_materials) //Change material content of the ammo box according to the amount of ammo deposited into the weapon
|
||||
/// list of materials contained in the ammo box after we put it through the equation so we can stick this list into set_custom_materials()
|
||||
var/list/new_material_content = list()
|
||||
for(var/datum/material/current_material in A.custom_materials)
|
||||
for(var/datum/material/current_material in ammo.custom_materials)
|
||||
if(istype(current_material, /datum/material/iron)) //we can flatten an empty ammo box into a sheet of iron (2000 units) so we have to make sure the box always has this amount at minimum
|
||||
new_material_content[current_material] = (A.custom_materials[current_material] - SHEET_MATERIAL_AMOUNT) * (A.rounds / initial(A.rounds)) + SHEET_MATERIAL_AMOUNT
|
||||
new_material_content[current_material] = (ammo.custom_materials[current_material] - SHEET_MATERIAL_AMOUNT) * (ammo.rounds / initial(ammo.rounds)) + SHEET_MATERIAL_AMOUNT
|
||||
else
|
||||
new_material_content[current_material] = A.custom_materials[current_material] * (A.rounds / initial(A.rounds))
|
||||
A.set_custom_materials(new_material_content)
|
||||
A.update_name()
|
||||
new_material_content[current_material] = ammo.custom_materials[current_material] * (ammo.rounds / initial(ammo.rounds))
|
||||
ammo.set_custom_materials(new_material_content)
|
||||
ammo.update_name()
|
||||
return TRUE
|
||||
|
||||
if(A.direct_load)
|
||||
gun.projectiles = gun.projectiles + A.rounds
|
||||
if(ammo.direct_load)
|
||||
gun.projectiles = gun.projectiles + ammo.rounds
|
||||
else
|
||||
gun.projectiles_cache = gun.projectiles_cache + A.rounds
|
||||
playsound(get_turf(user),A.load_audio,50,TRUE)
|
||||
to_chat(user, span_notice("You add [A.rounds] [A.ammo_type][A.rounds > 1?"s":""] to \the [gun]"))
|
||||
if(A.qdel_on_empty)
|
||||
qdel(A)
|
||||
gun.projectiles_cache = gun.projectiles_cache + ammo.rounds
|
||||
|
||||
playsound(get_turf(user),ammo.load_audio,50,TRUE)
|
||||
to_chat(user, span_notice("You add [ammo.rounds] [ammo.ammo_type][ammo.rounds > 1 ? "s" : ""] to \the [gun]"))
|
||||
if(ammo.qdel_on_empty)
|
||||
qdel(ammo)
|
||||
return TRUE
|
||||
A.rounds = 0
|
||||
A.set_custom_materials(list(/datum/material/iron=SHEET_MATERIAL_AMOUNT))
|
||||
A.update_appearance()
|
||||
ammo.rounds = 0
|
||||
ammo.set_custom_materials(list(/datum/material/iron=SHEET_MATERIAL_AMOUNT))
|
||||
ammo.update_appearance()
|
||||
return TRUE
|
||||
|
||||
if(!fail_chat_override)
|
||||
if(found_gun)
|
||||
balloon_alert(user, "ammo storage is full!")
|
||||
|
||||
@@ -197,7 +197,6 @@
|
||||
if(driver.client)
|
||||
driver.update_mouse_pointer()
|
||||
driver.client.view_size.resetToDefault()
|
||||
zoom_mode = FALSE
|
||||
. = ..()
|
||||
update_appearance()
|
||||
|
||||
|
||||
@@ -75,49 +75,24 @@
|
||||
/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(!can_move(direction))
|
||||
return FALSE
|
||||
|
||||
if(ismovable(loc)) //Mech is inside an object, tell it we moved
|
||||
var/atom/loc_atom = loc
|
||||
return loc_atom.relaymove(src, direction)
|
||||
var/obj/machinery/portable_atmospherics/canister/internal_tank = get_internal_tank()
|
||||
if(internal_tank?.connected_port)
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to move while connected to the air system port!")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
|
||||
if(!Process_Spacemove(direction))
|
||||
return FALSE
|
||||
if(zoom_mode)
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to move while in zoom mode!")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
var/list/missing_parts = list()
|
||||
if(isnull(cell))
|
||||
missing_parts += "power cell"
|
||||
if(isnull(capacitor))
|
||||
missing_parts += "capacitor"
|
||||
if(isnull(servo))
|
||||
missing_parts += "servo"
|
||||
if(length(missing_parts))
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Missing [english_list(missing_parts)].")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
if((step_energy_drain != 0) && !use_energy(step_energy_drain))
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Insufficient power to move!")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
if(lavaland_only && is_mining_level(z))
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Invalid Environment.")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
|
||||
var/olddir = dir
|
||||
|
||||
@@ -148,20 +123,46 @@
|
||||
//Otherwise just walk normally
|
||||
. = try_step_multiz(direction)
|
||||
|
||||
if(phasing)
|
||||
use_energy(phasing_energy_drain)
|
||||
if(strafe)
|
||||
setDir(olddir)
|
||||
|
||||
/// Check if anything is blocking our movement
|
||||
/obj/vehicle/sealed/mecha/proc/can_move(direction)
|
||||
var/obj/machinery/portable_atmospherics/canister/internal_tank = get_internal_tank()
|
||||
if(internal_tank?.connected_port)
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to move while connected to the air system port!")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
|
||||
var/list/missing_parts = list()
|
||||
if(isnull(cell))
|
||||
missing_parts += "power cell"
|
||||
if(isnull(capacitor))
|
||||
missing_parts += "capacitor"
|
||||
if(isnull(servo))
|
||||
missing_parts += "servo"
|
||||
|
||||
if(length(missing_parts))
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Missing [english_list(missing_parts)].")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
|
||||
if((step_energy_drain != 0) && !use_energy(step_energy_drain))
|
||||
if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE))
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("Insufficient power to move!")]")
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/vehicle/sealed/mecha/Bump(atom/obstacle)
|
||||
. = ..()
|
||||
if(phasing) //Theres only one cause for phasing canpass fails
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_warning("A dull, universal force is preventing you from [phasing] here!")]")
|
||||
spark_system.start()
|
||||
return
|
||||
if(.) //mech was thrown/door/whatever
|
||||
return
|
||||
try_bumpsmash(obstacle)
|
||||
|
||||
/obj/vehicle/sealed/mecha/proc/try_bumpsmash(atom/obstacle)
|
||||
// Whether or not we're on our mecha melee cooldown
|
||||
var/on_cooldown = TIMER_COOLDOWN_RUNNING(src, COOLDOWN_MECHA_MELEE_ATTACK)
|
||||
|
||||
@@ -172,6 +173,7 @@
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown * 0.3)
|
||||
if(!obstacle || obstacle.CanPass(src, get_dir(obstacle, src) || dir)) // The else is in case the obstacle is in the same turf.
|
||||
step(src,dir)
|
||||
|
||||
if(isobj(obstacle))
|
||||
var/obj/obj_obstacle = obstacle
|
||||
if(!obj_obstacle.anchored && obj_obstacle.move_resist <= move_force)
|
||||
|
||||
@@ -47,19 +47,13 @@
|
||||
. = ..()
|
||||
ore_box = new(src)
|
||||
|
||||
/obj/vehicle/sealed/mecha/clarke/atom_destruction()
|
||||
if(ore_box)
|
||||
INVOKE_ASYNC(ore_box, TYPE_PROC_REF(/obj/structure/ore_box, dump_box_contents))
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/mecha/clarke/generate_actions()
|
||||
. = ..()
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_search_ruins)
|
||||
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/clarke_scoop_body)
|
||||
|
||||
//Ore Box Controls
|
||||
|
||||
///Special equipment for the Clarke mech, handles moving ore without giving the mech a hydraulic clamp and cargo compartment.
|
||||
// Ore Box Controls
|
||||
/// Special equipment for the Clarke mech, handles moving ore without giving the mech a hydraulic clamp and cargo compartment.
|
||||
/obj/item/mecha_parts/mecha_equipment/orebox_manager
|
||||
name = "ore storage module"
|
||||
desc = "An automated ore box management device, complete with a built-in boulder processor."
|
||||
|
||||
Reference in New Issue
Block a user