mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
## About The Pull Request Projectile refactor pulled armor check above the pre-hit comsig, this fixes that. No need to check armor before you're hit when you potentially will not be. ## Changelog 🆑 fix: Sleeping Carp and Cain & Abel no longer tell you about armor penetration when you reflect projectiles with them /🆑
561 lines
22 KiB
Plaintext
561 lines
22 KiB
Plaintext
/*!
|
|
* # Mecha defence explanation
|
|
* Mechs focus is on a more heavy-but-slower damage approach
|
|
* For this they have the following mechanics
|
|
*
|
|
* ## Backstab
|
|
* Basically the tldr is that mechs are less flexible so we encourage good positioning, pretty simple
|
|
* ## Armor modules
|
|
* Pretty simple, adds armor, you can choose against what
|
|
* ## Internal damage
|
|
* When taking damage will force you to take some time to repair, encourages improvising in a fight
|
|
* Targeting different def zones will damage them to encurage a more strategic approach to fights
|
|
* where they target the "dangerous" modules
|
|
*/
|
|
|
|
/// tries to damage mech equipment depending on damage and where is being targeted
|
|
/obj/vehicle/sealed/mecha/proc/try_damage_component(damage, def_zone)
|
|
if(damage < component_damage_threshold)
|
|
return
|
|
var/obj/item/mecha_parts/mecha_equipment/gear
|
|
switch(def_zone)
|
|
if(BODY_ZONE_L_ARM)
|
|
gear = equip_by_category[MECHA_L_ARM]
|
|
if(BODY_ZONE_R_ARM)
|
|
gear = equip_by_category[MECHA_R_ARM]
|
|
if(!gear)
|
|
return
|
|
var/component_health = gear.get_integrity()
|
|
// always leave at least 1 health
|
|
var/damage_to_deal = min(component_health - 1, damage)
|
|
if(damage_to_deal <= 0)
|
|
return
|
|
|
|
gear.take_damage(damage_to_deal)
|
|
if(gear.get_integrity() <= 1)
|
|
to_chat(occupants, "[icon2html(src, occupants)][span_danger("[gear] is critically damaged!")]")
|
|
playsound(src, gear.destroy_sound, 50)
|
|
|
|
/obj/vehicle/sealed/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0)
|
|
var/damage_taken = ..()
|
|
if(damage_taken <= 0 || atom_integrity < 0)
|
|
return damage_taken
|
|
|
|
diag_hud_set_mechhealth()
|
|
spark_system?.start()
|
|
try_deal_internal_damage(damage_taken)
|
|
if(damage_taken >= 5 || prob(33))
|
|
to_chat(occupants, "[icon2html(src, occupants)][span_userdanger("Taking damage!")]")
|
|
log_message("Took [damage_taken] points of damage. Damage type: [damage_type]", LOG_MECHA)
|
|
|
|
return damage_taken
|
|
|
|
/obj/vehicle/sealed/mecha/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration)
|
|
. = ..()
|
|
if(attack_dir)
|
|
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
|
|
if(.)
|
|
. *= facing_modifier
|
|
|
|
/obj/vehicle/sealed/mecha/attack_hand(mob/living/user, list/modifiers)
|
|
. = ..()
|
|
if(.)
|
|
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)
|
|
playsound(loc, 'sound/items/weapons/tap.ogg', 40, TRUE, -1)
|
|
user.visible_message(span_danger("[user] hits [src]. Nothing happens."), null, null, COMBAT_MESSAGE_RANGE)
|
|
log_message("Attack by hand/paw (no damage). Attacker - [user].", LOG_MECHA, color="red")
|
|
|
|
/obj/vehicle/sealed/mecha/attack_paw(mob/user, list/modifiers)
|
|
return attack_hand(user, modifiers)
|
|
|
|
/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)
|
|
|
|
/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
|
|
|
|
|
|
/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")
|
|
return ..()
|
|
|
|
/obj/vehicle/sealed/mecha/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked)
|
|
// Determine our potential to shoot through the mech and into the cockpit, hitting the pilot
|
|
var/kill_the_meat = clamp(hitting_projectile.armour_penetration - get_armor_rating(hitting_projectile.armor_flag), 0, 100)
|
|
// Allows bullets to hit the pilot of open-canopy mechs, or if the bullet penetrates to the pilot, or the bullet can pass through structures
|
|
if (!LAZYLEN(occupants) || (mecha_flags & SILICON_PILOT))
|
|
return ..()
|
|
if (def_zone != BODY_ZONE_HEAD && def_zone != BODY_ZONE_CHEST)
|
|
return ..()
|
|
if ((mecha_flags & IS_ENCLOSED) && !(kill_the_meat && prob(kill_the_meat) && !(mecha_flags & CANNOT_OVERPENETRATE)) && !(hitting_projectile.pass_flags & (PASSSTRUCTURE|PASSVEHICLE)))
|
|
return ..()
|
|
var/mob/living/hitmob = pick(occupants)
|
|
return hitmob.projectile_hit(hitting_projectile, def_zone, piercing_hit) //If we've passed any of the above conditions, the pilot can be hit
|
|
|
|
/obj/vehicle/sealed/mecha/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked = null)
|
|
. = ..()
|
|
log_message("Hit by projectile. Type: [hitting_projectile]([hitting_projectile.damage_type]).", LOG_MECHA, color="red")
|
|
// yes we *have* to run the armor calc proc here I love tg projectile code too
|
|
try_damage_component(run_atom_armor(
|
|
damage_amount = hitting_projectile.damage,
|
|
damage_type = hitting_projectile.damage_type,
|
|
damage_flag = hitting_projectile.armor_flag,
|
|
attack_dir = REVERSE_DIR(hitting_projectile.dir),
|
|
armour_penetration = hitting_projectile.armour_penetration,
|
|
), def_zone)
|
|
|
|
/obj/vehicle/sealed/mecha/ex_act(severity, target)
|
|
log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red")
|
|
return ..()
|
|
|
|
/obj/vehicle/sealed/mecha/contents_explosion(severity, target)
|
|
severity--
|
|
|
|
switch(severity)
|
|
if(EXPLODE_DEVASTATE)
|
|
if(flat_equipment)
|
|
SSexplosions.high_mov_atom += flat_equipment
|
|
if(trackers)
|
|
SSexplosions.high_mov_atom += trackers
|
|
if(occupants)
|
|
SSexplosions.high_mov_atom += occupants
|
|
if(EXPLODE_HEAVY)
|
|
if(flat_equipment)
|
|
SSexplosions.med_mov_atom += flat_equipment
|
|
if(trackers)
|
|
SSexplosions.med_mov_atom += trackers
|
|
if(occupants)
|
|
SSexplosions.med_mov_atom += occupants
|
|
if(EXPLODE_LIGHT)
|
|
if(flat_equipment)
|
|
SSexplosions.low_mov_atom += flat_equipment
|
|
if(trackers)
|
|
SSexplosions.low_mov_atom += trackers
|
|
if(occupants)
|
|
SSexplosions.low_mov_atom += occupants
|
|
|
|
/obj/vehicle/sealed/mecha/emp_act(severity)
|
|
. = ..()
|
|
if (. & EMP_PROTECT_SELF)
|
|
return
|
|
|
|
var/mecha_explodies_vulnerability = (severity * capacitor.rating) //The more severe the EMP, the worse the outcome. The higher the tier of the capacitor, the less severe the outcome.
|
|
|
|
if(get_charge())
|
|
use_energy(round((cell.maxcharge / 2) / mecha_explodies_vulnerability, 1))
|
|
|
|
var/how_hard_are_we_explodies = rand(MECH_EMP_DAMAGE_LOWER, MECH_EMP_DAMAGE_UPPER)
|
|
take_damage(how_hard_are_we_explodies / mecha_explodies_vulnerability, BURN)
|
|
|
|
log_message("EMP detected", LOG_MECHA, color="red")
|
|
|
|
//Mess with the focus of the inbuilt camera if present
|
|
if(chassis_camera && !chassis_camera.is_emp_scrambled)
|
|
chassis_camera.setViewRange(chassis_camera.short_range)
|
|
chassis_camera.is_emp_scrambled = TRUE
|
|
diag_hud_set_camera()
|
|
addtimer(CALLBACK(chassis_camera, TYPE_PROC_REF(/obj/machinery/camera/exosuit, emp_refocus), src), 10 SECONDS / severity)
|
|
|
|
for(var/obj/item/mecha_parts/mecha_tracking/tracker in trackers) // Go through our list of trackers and potentially delete our trackers due to an EMP.
|
|
if(prob(MECH_EMP_BEACON_DESTRUCTION_PROB / severity))
|
|
if((mecha_flags & SILICON_PILOT) && tracker.ai_beacon) // ignore any beacons which allows our AI pilot to be in the mech. Even if it isn't using a beacon, let's just do this to be safe. The code doesn't make a distinction! YAY!
|
|
continue // Does this mean that a AI tracking beacon can be EMP'd over and over without risk of self-destruction? Yes. Is this a nerf to silicon mechs? I guess. Do I care? No.
|
|
qdel(tracker)
|
|
|
|
if(!equipment_disabled && LAZYLEN(occupants)) //prevent spamming this message with back-to-back EMPs
|
|
to_chat(occupants, span_warning("Error -- Connection to equipment control unit has been lost."))
|
|
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/vehicle/sealed/mecha, restore_equipment)), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
|
|
equipment_disabled = TRUE
|
|
set_mouse_pointer()
|
|
|
|
/obj/vehicle/sealed/mecha/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
|
|
return exposed_temperature > max_temperature
|
|
|
|
/obj/vehicle/sealed/mecha/atmos_expose(datum/gas_mixture/air, exposed_temperature)
|
|
log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red")
|
|
take_damage(5, BURN, 0, 1)
|
|
|
|
/obj/vehicle/sealed/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech
|
|
. = ..()
|
|
if(mecha_flags & IS_ENCLOSED || mecha_flags & SILICON_PILOT)
|
|
return
|
|
for(var/mob/living/cookedalive as anything in occupants)
|
|
if(cookedalive.fire_stacks < 5)
|
|
cookedalive.adjust_fire_stacks(1)
|
|
cookedalive.ignite_mob()
|
|
|
|
/obj/vehicle/sealed/mecha/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
|
|
if(istype(tool, /obj/item/mecha_parts))
|
|
var/obj/item/mecha_parts/parts = tool
|
|
return parts.try_attach_part(user, src, TRUE)
|
|
return ..()
|
|
|
|
/obj/vehicle/sealed/mecha/attackby(obj/item/weapon, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
. = ..()
|
|
//If our weapon that we are hitting the mech with has armour penetration, we could potentially get a hit in on the occupant
|
|
var/peeling_the_onion = clamp(weapon.armour_penetration - (get_armor_rating(MELEE)/2), 0, 100)
|
|
|
|
if(peeling_the_onion && prob(peeling_the_onion) && !(mecha_flags & CANNOT_OVERPENETRATE) \
|
|
&& LAZYLEN(occupants) \
|
|
&& !(mecha_flags & SILICON_PILOT))
|
|
var/mob/living/hitmob = pick(occupants)
|
|
weapon.melee_attack_chain(user, hitmob, modifiers, list("[FORCE_MULTIPLIER]" = (peeling_the_onion/100), "[SILENCE_DEFAULT_MESSAGES]" = TRUE)) //Perform an extra attack on the occupant if all the above conditions pass
|
|
|
|
/obj/vehicle/sealed/mecha/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
|
if(istype(tool, /obj/item/mmi))
|
|
if(!mmi_move_inside(tool,user))
|
|
balloon_alert(user, "initialization of MMI failed!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
balloon_alert(user, "initialized MMI")
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/mecha_ammo))
|
|
if(ammo_resupply(tool, user))
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/rcd_upgrade))
|
|
return upgrade_rcd(tool, user)
|
|
|
|
if(tool.GetID())
|
|
if(!allowed(user))
|
|
if(mecha_flags & ID_LOCK_ON)
|
|
balloon_alert(user, "access denied!")
|
|
else
|
|
balloon_alert(user, "unable to set id lock!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
mecha_flags ^= ID_LOCK_ON
|
|
balloon_alert(user, "[mecha_flags & ID_LOCK_ON ? "enabled" : "disabled"] id lock!")
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/mecha_parts))
|
|
var/obj/item/mecha_parts/part = tool
|
|
return part.try_attach_part(user, src, FALSE)
|
|
|
|
if(is_wire_tool(tool) && (mecha_flags & PANEL_OPEN))
|
|
if(user.combat_mode)
|
|
return
|
|
if(wires.interact(user))
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/stock_parts))
|
|
return try_insert_part(tool, user)
|
|
|
|
return NONE
|
|
|
|
/// Try to insert a stock part into the mech
|
|
/obj/vehicle/sealed/mecha/proc/try_insert_part(obj/item/stock_parts/tool, mob/living/user)
|
|
if(!(mecha_flags & PANEL_OPEN))
|
|
balloon_alert(user, "open the panel first!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
if(istype(tool, /obj/item/stock_parts/power_store/cell))
|
|
if(cell)
|
|
balloon_alert(user, "already installed!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
if(!user.transferItemToLoc(tool, src, silent = FALSE))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
cell = tool
|
|
balloon_alert(user, "installed power cell")
|
|
diag_hud_set_mechcell()
|
|
playsound(src, 'sound/items/tools/screwdriver2.ogg', 50, FALSE)
|
|
log_message("Power cell installed", LOG_MECHA)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/stock_parts/scanning_module))
|
|
if(scanmod)
|
|
balloon_alert(user, "already installed!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
if(!user.transferItemToLoc(tool, src, silent = FALSE))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
scanmod = tool
|
|
balloon_alert(user, "installed scanning module")
|
|
playsound(src, 'sound/items/tools/screwdriver2.ogg', 50, FALSE)
|
|
log_message("[tool] installed", LOG_MECHA)
|
|
update_part_values()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/stock_parts/capacitor))
|
|
if(capacitor)
|
|
balloon_alert(user, "already installed!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
if(!user.transferItemToLoc(tool, src, silent = FALSE))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
capacitor = tool
|
|
balloon_alert(user, "installed capacitor")
|
|
playsound(src, 'sound/items/tools/screwdriver2.ogg', 50, FALSE)
|
|
log_message("[tool] installed", LOG_MECHA)
|
|
update_part_values()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/stock_parts/servo))
|
|
if(servo)
|
|
balloon_alert(user, "already installed!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
if(!user.transferItemToLoc(tool, src, silent = FALSE))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
servo = tool
|
|
balloon_alert(user, "installed servo")
|
|
playsound(src, 'sound/items/tools/screwdriver2.ogg', 50, FALSE)
|
|
log_message("[tool] installed", LOG_MECHA)
|
|
update_part_values()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
return NONE
|
|
|
|
/obj/vehicle/sealed/mecha/attacked_by(obj/item/attacking_item, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
var/final_force = CALCULATE_FORCE(attacking_item, attack_modifiers) * attacking_item.get_demolition_modifier(src)
|
|
if(!final_force)
|
|
return 0
|
|
|
|
var/damage_taken = take_damage(final_force, attacking_item.damtype, MELEE, 1, get_dir(src, user))
|
|
try_damage_component(damage_taken, user.zone_selected)
|
|
|
|
var/hit_verb = length(attacking_item.attack_verb_simple) ? "[pick(attacking_item.attack_verb_simple)]" : "hit"
|
|
user.visible_message(
|
|
span_danger("[user] [hit_verb][plural_s(hit_verb)] [src] with [attacking_item][damage_taken ? "." : ", without leaving a mark!"]"),
|
|
span_danger("You [hit_verb] [src] with [attacking_item][damage_taken ? "." : ", without leaving a mark!"]"),
|
|
span_hear("You hear a [hit_verb]."),
|
|
COMBAT_MESSAGE_RANGE,
|
|
)
|
|
|
|
log_combat(user, src, "attacked", attacking_item)
|
|
log_message("Attacked by [user]. Item - [attacking_item], Damage - [damage_taken]", LOG_MECHA)
|
|
return damage_taken
|
|
|
|
/obj/vehicle/sealed/mecha/attack_generic(mob/user, damage_amount, damage_type, damage_flag, effects, armor_penetration)
|
|
. = ..()
|
|
if(.)
|
|
try_damage_component(., user.zone_selected)
|
|
diag_hud_set_mechhealth()
|
|
|
|
/obj/vehicle/sealed/mecha/examine(mob/user)
|
|
. = ..()
|
|
if(mecha_flags & PANEL_OPEN)
|
|
. += span_notice("The panel is open. You could use a <b>crowbar</b> to eject parts or lock the panel back with a <b>screwdriver</b>.")
|
|
else
|
|
. += span_notice("You could unlock the maintenance cover with a <b>screwdriver</b>.")
|
|
|
|
/obj/vehicle/sealed/mecha/screwdriver_act(mob/living/user, obj/item/tool)
|
|
..()
|
|
. = TRUE
|
|
|
|
if(LAZYLEN(occupants))
|
|
balloon_alert(user, "panel blocked")
|
|
return
|
|
|
|
mecha_flags ^= PANEL_OPEN
|
|
balloon_alert(user, (mecha_flags & PANEL_OPEN) ? "panel open" : "panel closed")
|
|
tool.play_tool_sound(src)
|
|
|
|
/obj/vehicle/sealed/mecha/crowbar_act(mob/living/user, obj/item/tool)
|
|
..()
|
|
. = TRUE
|
|
if(istype(tool, /obj/item/crowbar/mechremoval))
|
|
var/obj/item/crowbar/mechremoval/remover = tool
|
|
remover.empty_mech(src, user)
|
|
return
|
|
if(!(mecha_flags & PANEL_OPEN))
|
|
balloon_alert(user, "open the panel first!")
|
|
return
|
|
if(dna_lock && user.has_dna())
|
|
var/mob/living/carbon/user_carbon = user
|
|
if(user_carbon.dna.unique_enzymes != dna_lock)
|
|
balloon_alert(user, "access with this DNA denied!")
|
|
return
|
|
if((mecha_flags & ID_LOCK_ON) && !allowed(user))
|
|
balloon_alert(user, "access denied!")
|
|
return
|
|
|
|
var/list/stock_parts = list()
|
|
if(cell)
|
|
stock_parts += cell
|
|
if(scanmod)
|
|
stock_parts += scanmod
|
|
if(capacitor)
|
|
stock_parts += capacitor
|
|
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)
|
|
return
|
|
balloon_alert(user, "no parts!")
|
|
|
|
/obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W)
|
|
if(user.combat_mode)
|
|
return
|
|
. = TRUE
|
|
if(DOING_INTERACTION(user, src))
|
|
balloon_alert(user, "you're already repairing this!")
|
|
return
|
|
if(atom_integrity >= max_integrity)
|
|
balloon_alert(user, "it's not damaged!")
|
|
return
|
|
if(!W.tool_start_check(user, amount=1, heat_required = HIGH_TEMPERATURE_REQUIRED))
|
|
return
|
|
user.balloon_alert_to_viewers("started welding [src]", "started repairing [src]")
|
|
audible_message(span_hear("You hear welding."))
|
|
var/did_the_thing
|
|
while(atom_integrity < max_integrity)
|
|
if(W.use_tool(src, user, 2.5 SECONDS, volume=50))
|
|
did_the_thing = TRUE
|
|
repair_damage(10)
|
|
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)
|
|
cell.charge = cell.maxcharge
|
|
diag_hud_set_mechcell()
|
|
if(internal_damage & MECHA_INT_FIRE)
|
|
clear_internal_damage(MECHA_INT_FIRE)
|
|
if(internal_damage & MECHA_INT_TEMP_CONTROL)
|
|
clear_internal_damage(MECHA_INT_TEMP_CONTROL)
|
|
if(internal_damage & MECHA_INT_SHORT_CIRCUIT)
|
|
clear_internal_damage(MECHA_INT_SHORT_CIRCUIT)
|
|
if(internal_damage & MECHA_CABIN_AIR_BREACH)
|
|
clear_internal_damage(MECHA_CABIN_AIR_BREACH)
|
|
if(internal_damage & MECHA_INT_CONTROL_LOST)
|
|
clear_internal_damage(MECHA_INT_CONTROL_LOST)
|
|
|
|
/obj/vehicle/sealed/mecha/repair_damage(amount)
|
|
. = ..()
|
|
diag_hud_set_mechhealth()
|
|
|
|
/obj/vehicle/sealed/mecha/narsie_act()
|
|
emp_act(EMP_HEAVY)
|
|
|
|
/obj/vehicle/sealed/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
|
if(!no_effect && !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/proc/ammo_resupply(obj/item/mecha_ammo/A, mob/user,fail_chat_override = FALSE)
|
|
if(!A.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)
|
|
continue
|
|
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)
|
|
continue
|
|
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, 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
|
|
/// 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)
|
|
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
|
|
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()
|
|
return TRUE
|
|
|
|
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, span_notice("You add [A.rounds] [A.ammo_type][A.rounds > 1?"s":""] to \the [gun]"))
|
|
if(A.qdel_on_empty)
|
|
qdel(A)
|
|
return TRUE
|
|
A.rounds = 0
|
|
A.set_custom_materials(list(/datum/material/iron=SHEET_MATERIAL_AMOUNT))
|
|
A.update_appearance()
|
|
return TRUE
|
|
if(!fail_chat_override)
|
|
if(found_gun)
|
|
balloon_alert(user, "ammo storage is full!")
|
|
else
|
|
balloon_alert(user, "can't use this ammo!")
|
|
return FALSE
|
|
|
|
///Upgrades any attached RCD equipment.
|
|
/obj/vehicle/sealed/mecha/proc/upgrade_rcd(obj/item/rcd_upgrade/rcd_upgrade, mob/user)
|
|
for(var/obj/item/mecha_parts/mecha_equipment/rcd/rcd_equip in flat_equipment)
|
|
if(rcd_equip.internal_rcd.install_upgrade(rcd_upgrade, user))
|
|
return ITEM_INTERACT_SUCCESS
|
|
return ITEM_INTERACT_BLOCKING
|