Merge branch 'master' into Projectile_Rework

This commit is contained in:
Lin
2022-04-09 04:19:56 +00:00
committed by GitHub
410 changed files with 7476 additions and 7443 deletions
+5 -3
View File
@@ -4,9 +4,10 @@
icon = 'icons/obj/vehicles.dmi'
icon_state = "fuckyou"
max_integrity = 300
armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 60)
armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 60, ACID = 60)
density = TRUE
anchored = FALSE
COOLDOWN_DECLARE(cooldown_vehicle_move)
var/list/mob/occupants //mob = bitflags of their control level.
var/max_occupants = 1
var/max_drivers = 1
@@ -23,6 +24,7 @@
var/list/autogrant_actions_controller //assoc list "[bitflag]" = list(typepaths)
var/list/mob/occupant_actions //assoc list mob = list(type = action datum assigned to mob)
var/obj/vehicle/trailer
var/mouse_pointer //do we have a special mouse
/obj/vehicle/Initialize(mapload)
. = ..()
@@ -121,9 +123,9 @@
vehicle_move(direction)
/obj/vehicle/proc/vehicle_move(direction)
if(lastmove + movedelay > world.time)
if(!COOLDOWN_FINISHED(src, cooldown_vehicle_move))
return FALSE
lastmove = world.time
COOLDOWN_START(src, cooldown_vehicle_move, movedelay)
if(trailer)
var/dir_to_move = get_dir(trailer.loc, loc)
var/did_move = step(src, direction)
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "How someone could even fit in there is byond me."
icon_state = "clowncar"
max_integrity = 150
armor = list("melee" = 70, "bullet" = 40, "laser" = 40, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
armor = list(MELEE = 70, BULLET = 40, LASER = 40, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 80, ACID = 80)
enter_delay = 20
max_occupants = 50
movedelay = 0.6
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
/obj/vehicle/sealed/mecha/combat
force = 30
internals_req_access = list(ACCESS_ROBOTICS, ACCESS_SECURITY)
internal_damage_threshold = 50
armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 20, BOMB = 20, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
mouse_pointer = 'icons/mecha/mecha_mouse.dmi'
destruction_sleep_duration = 40
exit_delay = 40
/obj/vehicle/sealed/mecha/combat/restore_equipment()
mouse_pointer = 'icons/mecha/mecha_mouse.dmi'
. = ..()
/obj/vehicle/sealed/mecha/combat/proc/max_ammo() //Max the ammo stored for Nuke Ops mechs, or anyone else that calls this
for(var/obj/item/I in equipment)
if(istype(I, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/))
var/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/gun = I
gun.projectiles_cache = gun.projectiles_cache_max
@@ -0,0 +1,241 @@
/obj/vehicle/sealed/mecha/combat/durand
desc = "An aging combat exosuit utilized by the Nanotrasen corporation. Originally developed to combat hostile alien lifeforms."
name = "\improper Durand"
icon_state = "durand"
movedelay = 4
dir_in = 1 //Facing North.
max_integrity = 400
deflect_chance = 20
armor = list(MELEE = 40, BULLET = 35, LASER = 15, ENERGY = 10, BOMB = 20, BIO = 0, RAD = 50, FIRE = 100, ACID = 100)
max_temperature = 30000
force = 40
wreckage = /obj/structure/mecha_wreckage/durand
var/obj/durand_shield/shield
/obj/vehicle/sealed/mecha/combat/durand/Initialize()
. = ..()
shield = new /obj/durand_shield(loc, src, layer, dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, .proc/relay)
RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, .proc/prehit)
/obj/vehicle/sealed/mecha/combat/durand/Destroy()
if(shield)
QDEL_NULL(shield)
return ..()
/obj/vehicle/sealed/mecha/combat/durand/generate_actions()
. = ..()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_defense_mode)
/obj/vehicle/sealed/mecha/combat/durand/process()
. = ..()
if(defense_mode && !use_power(100)) //Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle
for(var/O in occupants)
var/mob/living/occupant = O
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
if(action)
INVOKE_ASYNC(action, /datum/action.proc/Trigger)
break
/obj/vehicle/sealed/mecha/combat/durand/Move(direction)
. = ..()
if(shield)
shield.forceMove(loc)
shield.setDir(dir)
/obj/vehicle/sealed/mecha/combat/durand/forceMove(turf/T)
. = ..()
shield.forceMove(T)
/obj/vehicle/sealed/mecha/combat/durand/mob_exit(mob/M, silent, randomstep, forced)
if(defense_mode)
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, M, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
if(action)
INVOKE_ASYNC(action, /datum/action.proc/Trigger, FALSE)
return ..()
///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA.
/obj/vehicle/sealed/mecha/combat/durand/proc/relay(datum/source, mob/owner, list/signal_args)
SIGNAL_HANDLER
if(!shield) //if the shield somehow got deleted
stack_trace("Durand triggered relay without a shield")
shield = new /obj/durand_shield(loc, src, layer)
shield.setDir(dir)
SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_TRIGGER, owner, signal_args)
//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true.
/obj/vehicle/sealed/mecha/combat/durand/proc/prehit(obj/item/projectile/source, list/signal_args)
if(defense_check(source.loc) && shield)
signal_args[2] = shield
/**Checks if defense mode is enabled, and if the attacker is standing in an area covered by the shield.
Expects a turf. Returns true if the attack should be blocked, false if not.*/
/obj/vehicle/sealed/mecha/combat/durand/proc/defense_check(turf/aloc)
if (!defense_mode || !shield || shield.switching)
return FALSE
. = FALSE
switch(dir)
if (1)
if(abs(x - aloc.x) <= (y - aloc.y) * -2)
. = TRUE
if (2)
if(abs(x - aloc.x) <= (y - aloc.y) * 2)
. = TRUE
if (4)
if(abs(y - aloc.y) <= (x - aloc.x) * -2)
. = TRUE
if (8)
if(abs(y - aloc.y) <= (x - aloc.x) * 2)
. = TRUE
return
/obj/vehicle/sealed/mecha/combat/durand/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0)
if(defense_check(user.loc))
log_message("Attack absorbed by defense field. Attacker - [user].", LOG_MECHA, color="orange")
shield.attack_generic(user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
else
. = ..()
/obj/vehicle/sealed/mecha/combat/durand/blob_act(obj/structure/blob/B)
if(defense_check(B.loc))
log_message("Attack by blob. Attacker - [B].", LOG_MECHA, color="red")
log_message("Attack absorbed by defense field.", LOG_MECHA, color="orange")
shield.blob_act(B)
else
. = ..()
/obj/vehicle/sealed/mecha/combat/durand/attackby(obj/item/W as obj, mob/user as mob, params)
if(defense_check(user.loc))
log_message("Attack absorbed by defense field. Attacker - [user], with [W]", LOG_MECHA, color="orange")
shield.attackby(W, user, params)
else
. = ..()
/obj/vehicle/sealed/mecha/combat/durand/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(defense_check(AM.loc))
log_message("Impact with [AM] absorbed by defense field.", LOG_MECHA, color="orange")
shield.hitby(AM, skipcatch, hitpush, blocked, throwingdatum)
else
. = ..()
////////////////////////////
///// Shield processing ////
////////////////////////////
/**An object to take the hit for us when using the Durand's defense mode.
It is spawned in during the durand's initilization, and always stays on the same tile.
Normally invisible, until defense mode is actvated. When the durand detects an attack that should be blocked, the
attack is passed to the shield. The shield takes the damage, uses it to calculate charge cost, and then sets its
own integrity back to max. Shield is automatically dropped if we run out of power or the user gets out.*/
/obj/durand_shield //projectiles get passed to this when defense mode is enabled
name = "defense grid"
icon = 'icons/mecha/durand_shield.dmi'
icon_state = "shield_null"
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
pixel_y = 4
max_integrity = 10000
obj_integrity = 10000
anchored = TRUE
light_range = MINIMUM_USEFUL_LIGHT_RANGE
light_power = 5
light_color = COLOR_CYAN
///Our link back to the durand
var/obj/vehicle/sealed/mecha/combat/durand/chassis
///To keep track of things during the animation
var/switching = FALSE
var/currentuser
/obj/durand_shield/Initialize(mapload, _chassis, _layer, _dir)
. = ..()
chassis = _chassis
layer = _layer
setDir(_dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, .proc/activate)
/obj/durand_shield/Destroy()
if(chassis)
chassis.shield = null
chassis = null
return ..()
/**
*Handles activating and deactivating the shield. This proc is called by a signal sent from the mech's action button
*and relayed by the mech itself. The "forced" variabe, signal_args[1], will skip the to-pilot text and is meant for when
*the shield is disabled by means other than the action button (like running out of power)
* Arguments:
* * source: the shield
* * owner: mob that activated the shield
* * signal_args: whether it's forced
*/
/obj/durand_shield/proc/activate(datum/source, mob/owner, list/signal_args)
SIGNAL_HANDLER
currentuser = owner
if(!chassis?.occupants)
return
if(switching && !signal_args[1])
return
if(!chassis.defense_mode && (!chassis.cell || chassis.cell.charge < 100)) //If it's off, and we have less than 100 units of power
to_chat(currentuser, "[icon2html(src, currentuser)]<span class='warn'>Insufficient power; cannot activate defense mode.</span>")
return
switching = TRUE
chassis.defense_mode = !chassis.defense_mode
if(!signal_args[1])
to_chat(currentuser, "[icon2html(src, currentuser)]<span class='notice'>Defense mode [chassis.defense_mode?"enabled":"disabled"].</span>")
chassis.log_message("User has toggled defense mode -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
else
chassis.log_message("defense mode state changed -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
for(var/occupant in chassis.occupants)
var/datum/action/button = chassis.occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode]
button.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]"
button.UpdateButtonIcon()
set_light(light_range, light_power, light_color)
if(chassis.defense_mode)
invisibility = 0
flick("shield_raise", src)
playsound(src, 'sound/mecha/mech_shield_raise.ogg', 50, FALSE)
set_light(l_range = MINIMUM_USEFUL_LIGHT_RANGE , l_power = 5, l_color = "#00FFFF")
icon_state = "shield"
RegisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE, .proc/resetdir)
else
flick("shield_drop", src)
playsound(src, 'sound/mecha/mech_shield_drop.ogg', 50, FALSE)
set_light(0)
icon_state = "shield_null"
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
UnregisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE)
switching = FALSE
/obj/durand_shield/proc/resetdir(datum/source, olddir, newdir)
setDir(newdir)
/obj/durand_shield/take_damage()
if(!chassis)
qdel(src)
return
if(!chassis.defense_mode) //if defense mode is disabled, we're taking damage that we shouldn't be taking
return
. = ..()
flick("shield_impact", src)
if(!chassis.use_power((max_integrity - obj_integrity) * 100))
chassis.cell?.charge = 0
for(var/O in chassis.occupants)
var/mob/living/occupant = O
var/datum/action/action = LAZYACCESSASSOC(chassis.occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
action.Trigger(FALSE)
obj_integrity = 10000
/obj/durand_shield/play_attack_sound()
playsound(src, 'sound/mecha/mech_shield_deflect.ogg', 100, TRUE)
/obj/durand_shield/bullet_act()
play_attack_sound()
. = ..()
@@ -0,0 +1,21 @@
/obj/vehicle/sealed/mecha/combat/five_stars
desc = "A state of the art tank deployed by the Spinward Stellar Coalition National Guard."
name = "\improper Tank"
icon = 'icons/mecha/mecha_96x96.dmi'
icon_state = "five_stars"
armor = list(MELEE = 100, BULLET = 50, LASER = 35, ENERGY = 35, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
step_in = 4
dir_in = 1 //Facing North.
max_integrity = 800
pixel_x = -32
pixel_y = -32
/obj/vehicle/sealed/mecha/combat/five_stars/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/spacecops(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
ME.attach(src)
max_ammo()
@@ -0,0 +1,59 @@
/obj/vehicle/sealed/mecha/combat/gygax
desc = "A lightweight, security exosuit. Popular among private and corporate security."
name = "\improper Gygax"
icon_state = "gygax"
allow_diagonal_movement = TRUE
movedelay = 3
dir_in = 1 //Facing North.
max_integrity = 250
deflect_chance = 5
armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
max_temperature = 25000
leg_overload_coeff = 80
force = 25
wreckage = /obj/structure/mecha_wreckage/gygax
internal_damage_threshold = 35
max_equip = 3
step_energy_drain = 3
/obj/vehicle/sealed/mecha/combat/gygax/dark
desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications."
name = "\improper Dark Gygax"
icon_state = "darkgygax"
max_integrity = 300
deflect_chance = 20
armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 35, BOMB = 20, BIO = 0, RAD =20, FIRE = 100, ACID = 100)
max_temperature = 35000
leg_overload_coeff = 70
force = 30
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/gygax/dark
max_equip = 5
destruction_sleep_duration = 20
/obj/vehicle/sealed/mecha/combat/gygax/dark/loaded/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
ME.attach(src)
max_ammo()
/obj/vehicle/sealed/mecha/combat/gygax/dark/add_cell(obj/item/stock_parts/cell/C=null)
if(C)
C.forceMove(src)
cell = C
return
cell = new /obj/item/stock_parts/cell/bluespace(src)
/obj/vehicle/sealed/mecha/combat/gygax/generate_actions()
. = ..()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_overload_mode)
@@ -0,0 +1,167 @@
/obj/vehicle/sealed/mecha/combat/honker
desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. Used to spread the fun and joy of life. HONK!"
name = "\improper H.O.N.K"
icon_state = "honker"
movedelay = 3
max_integrity = 140
deflect_chance = 60
internal_damage_threshold = 60
armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
max_temperature = 25000
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_ROBOTICS, ACCESS_THEATRE)
wreckage = /obj/structure/mecha_wreckage/honker
mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS
max_equip = 3
var/squeak = TRUE
/obj/vehicle/sealed/mecha/combat/honker/get_stats_part(mob/user)
var/integrity = obj_integrity/max_integrity*100
var/cell_charge = get_charge()
var/datum/gas_mixture/int_tank_air = internal_tank.return_air()
var/tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
var/tank_temperature = internal_tank ? int_tank_air.return_temperature() : "Unknown"
var/cabin_pressure = round(return_pressure(),0.01)
var/output = {"[report_internal_damage()]
[integrity<30?"<font color='red'><b>DAMAGE LEVEL CRITICAL</b></font><br>":null]
[internal_damage&MECHA_INT_TEMP_CONTROL?"<font color='red'><b>CLOWN SUPPORT SYSTEM MALFUNCTION</b></font><br>":null]
[internal_damage&MECHA_INT_TANK_BREACH?"<font color='red'><b>GAS TANK HONK</b></font><br>":null]
[internal_damage&MECHA_INT_CONTROL_LOST?"<font color='red'><b>HONK-A-DOODLE</b></font> - <a href='?src=[REF(src)];repair_int_control_lost=1'>Recalibrate</a><br>":null]
<b>IntegriHONK: </b> [integrity]%<br>
<b>PowerHONK charge: </b>[isnull(cell_charge)?"No power cell installed":"[cell.percent()]%"]<br>
<b>Air source: </b>[use_internal_tank?"Internal Airtank":"Environment"]<br>
<b>AirHONK pressure: </b>[tank_pressure]kPa<br>
<b>AirHONK temperature: </b>[tank_temperature]&deg;K|[tank_temperature - T0C]&deg;C<br>
<b>HONK pressure: </b>[cabin_pressure>WARNING_HIGH_PRESSURE ? "<font color='red'>[cabin_pressure]</font>": cabin_pressure]kPa<br>
<b>HONK temperature: </b> [return_temperature()]&deg;K|[return_temperature() - T0C]&deg;C<br>
<b>Lights: </b>[(mecha_flags & LIGHTS_ON)?"on":"off"]<br>
[dna_lock?"<b>DNA-locked:</b><br> <span style='font-size:10px;letter-spacing:-1px;'>[dna_lock]</span> \[<a href='?src=[REF(src)];reset_dna=1'>Reset</a>\]<br>":null]
"}
return output
/obj/vehicle/sealed/mecha/combat/honker/get_stats_html(mob/user)
var/output = {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[src.name] data</title>
<style>
body {color: #00ff00; background: #32CD32; font-family:"Courier",monospace; font-size: 12px;}
hr {border: 1px solid #0f0; color: #fff; background-color: #000;}
a {padding:2px 5px;;color:#0f0;}
.wr {margin-bottom: 5px;}
.header {cursor:pointer;}
.open, .closed {background: #32CD32; color:#000; padding:1px 2px;}
.links a {margin-bottom: 2px;padding-top:3px;}
.visible {display: block;}
.hidden {display: none;}
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
[js_dropdowns]
function SSticker() {
setInterval(function(){
window.location='byond://?src=[REF(src)]&update_content=1';
document.body.style.color = get_rand_color_string();
document.body.style.background = get_rand_color_string();
}, 1000);
}
function get_rand_color_string() {
var color = new Array;
for(var i=0;i<3;i++){
color.push(Math.floor(Math.random()*255));
}
return "rgb("+color.toString()+")";
}
window.onload = function() {
dropdowns();
SSticker();
}
</script>
</head>
<body>
<div id='content'>
[src.get_stats_part(user)]
</div>
<div id='eq_list'>
[src.get_equipment_list()]
</div>
<hr>
<div id='commands'>
[src.get_commands()]
</div>
</body>
</html>
"}
return output
/obj/vehicle/sealed/mecha/combat/honker/get_commands()
var/output = {"<div class='wr'>
<div class='header'>Sounds of HONK:</div>
<div class='links'>
<a href='?src=[REF(src)];play_sound=sadtrombone'>Sad Trombone</a>
<a href='?src=[REF(src)];play_sound=bikehorn'>Bike Horn</a>
<a href='?src=[REF(src)];play_sound=airhorn2'>Air Horn</a>
<a href='?src=[REF(src)];play_sound=carhorn'>Car Horn</a>
<a href='?src=[REF(src)];play_sound=party_horn'>Party Horn</a>
<a href='?src=[REF(src)];play_sound=reee'>Reee</a>
<a href='?src=[REF(src)];play_sound=weeoo1'>Siren</a>
<a href='?src=[REF(src)];play_sound=hiss1'>Hissing Creature</a>
<a href='?src=[REF(src)];play_sound=armbomb'>Armed Grenade</a>
<a href='?src=[REF(src)];play_sound=saberon'>Energy Sword</a>
<a href='?src=[REF(src)];play_sound=airlock_alien_prying'>Airlock Prying</a>
<a href='?src=[REF(src)];play_sound=lightningbolt'>Lightning Bolt</a>
<a href='?src=[REF(src)];play_sound=explosionfar'>Distant Explosion</a>
</div>
</div>
"}
output += ..()
return output
/obj/vehicle/sealed/mecha/combat/honker/get_equipment_list()
if(!LAZYLEN(equipment))
return
var/output = "<b>Honk-ON-Systems:</b><div style=\"margin-left: 15px;\">"
for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment)
output += "<div id='[REF(MT)]'>[MT.get_equip_info()]</div>"
output += "</div>"
return output
/obj/vehicle/sealed/mecha/combat/honker/play_stepsound()
if(squeak)
playsound(src, "clownstep", 70, 1)
squeak = !squeak
/obj/vehicle/sealed/mecha/combat/honker/Topic(href, href_list)
..()
if (href_list["play_sound"])
switch(href_list["play_sound"])
if("sadtrombone")
playsound(src, 'sound/misc/sadtrombone.ogg', 50)
if("bikehorn")
playsound(src, 'sound/items/bikehorn.ogg', 50)
if("airhorn2")
playsound(src, 'sound/items/airhorn2.ogg', 40) //soundfile has higher than average volume
if("carhorn")
playsound(src, 'sound/items/carhorn.ogg', 80) //soundfile has lower than average volume
if("party_horn")
playsound(src, 'sound/items/party_horn.ogg', 50)
if("reee")
playsound(src, 'sound/effects/reee.ogg', 50)
if("weeoo1")
playsound(src, 'sound/items/weeoo1.ogg', 50)
if("hiss1")
playsound(src, 'sound/voice/hiss1.ogg', 50)
if("armbomb")
playsound(src, 'sound/weapons/armbomb.ogg', 50)
if("saberon")
playsound(src, 'sound/weapons/saberon.ogg', 50)
if("airlock_alien_prying")
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50)
if("lightningbolt")
playsound(src, 'sound/magic/lightningbolt.ogg', 50)
if("explosionfar")
playsound(src, 'sound/effects/explosionfar.ogg', 50)
return
@@ -0,0 +1,97 @@
/obj/vehicle/sealed/mecha/combat/marauder
desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations."
name = "\improper Marauder"
icon_state = "marauder"
movedelay = 5
max_integrity = 500
deflect_chance = 25
armor = list(MELEE = 50, BULLET = 55, LASER = 40, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 60, FIRE = 100, ACID = 100)
max_temperature = 60000
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
operation_req_access = list(ACCESS_CENT_SPECOPS)
internals_req_access = list(ACCESS_CENT_SPECOPS)
wreckage = /obj/structure/mecha_wreckage/marauder
mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS
internal_damage_threshold = 25
force = 45
max_equip = 5
bumpsmash = TRUE
/obj/vehicle/sealed/mecha/combat/marauder/generate_actions()
. = ..()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_smoke)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_zoom)
/obj/vehicle/sealed/mecha/combat/marauder/loaded/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
ME.attach(src)
max_ammo()
/obj/vehicle/sealed/mecha/combat/marauder/seraph
desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel."
name = "\improper Seraph"
icon_state = "seraph"
operation_req_access = list(ACCESS_CENT_SPECOPS)
internals_req_access = list(ACCESS_CENT_SPECOPS)
movedelay = 3
max_integrity = 550
wreckage = /obj/structure/mecha_wreckage/seraph
internal_damage_threshold = 20
force = 55
max_equip = 6
/obj/vehicle/sealed/mecha/combat/marauder/seraph/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/teleporter(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
ME.attach(src)
max_ammo()
/obj/vehicle/sealed/mecha/combat/marauder/mauler
desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model."
name = "\improper Mauler"
icon_state = "mauler"
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/mauler
max_equip = 6
destruction_sleep_duration = 20
/obj/vehicle/sealed/mecha/combat/marauder/mauler/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
ME.attach(src)
/obj/vehicle/sealed/mecha/combat/marauder/mauler/loaded/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src)
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
ME.attach(src)
max_ammo()
@@ -0,0 +1,36 @@
/obj/vehicle/sealed/mecha/medical/medigax
desc = "A Gygax with it's actuator overload stripped and a slick white paint scheme, for medical use, These exosuits are developed and produced by Vey-Med. (&copy; All rights reserved)."
name = "\improper Medical Gygax"
icon_state = "medigax"
allow_diagonal_movement = TRUE
movedelay = 2
dir_in = 1 //Facing North.
max_integrity = 250
deflect_chance = 15
armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
max_temperature = 25000
wreckage = /obj/structure/mecha_wreckage/odysseus
internal_damage_threshold = 35
step_energy_drain = 6
infra_luminosity = 6
internals_req_access = list(ACCESS_ROBOTICS, ACCESS_MEDICAL)
/obj/vehicle/sealed/mecha/medical/medigax/moved_inside(mob/living/carbon/human/H)
. = ..()
if(.)
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.add_hud_to(H)
/obj/vehicle/sealed/mecha/medical/medigax/remove_occupant(mob/M)
if(isliving(M))
var/mob/living/L = M
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.remove_hud_from(L)
return ..()
/obj/vehicle/sealed/mecha/medical/medigax/mmi_moved_inside(obj/item/mmi/M, mob/user)
. = ..()
if(.)
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
var/mob/living/brain/B = M.brainmob
hud.add_hud_to(B)
@@ -0,0 +1,102 @@
/obj/vehicle/sealed/mecha/combat/neovgre
name = "Neovgre, the Anima Bulwark"
desc = "Nezbere's most powerful creation, a mighty war machine of unmatched power said to have ended wars in a single night. Armed with a heavy laser and a tesla sphere generator. Requires a pilot and a gunner."
icon = 'icons/mecha/neovgre.dmi'
icon_state = "neovgre"
max_integrity = 500 //This is THE ratvarian superweaon, its deployment is an investment
armor = list(MELEE = 50, BULLET = 40, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100) //Its similar to the clockwork armour albeit with a few buffs becuase RATVARIAN SUPERWEAPON!!
force = 50 //SMASHY SMASHY!!
movedelay = 3
internal_damage_threshold = 0
pixel_x = -16
layer = ABOVE_MOB_LAYER
var/breach_time = 100 //ten seconds till all goes to shit
var/recharge_rate = 100
internals_req_access = list()
wreckage = /obj/structure/mecha_wreckage/durand/neovgre
stepsound = 'sound/mecha/neostep2.ogg'
turnsound = 'sound/mecha/powerloader_step.ogg'
max_occupants = 2
//override this proc if you need to split up mecha control between multiple people (see savannah_ivanov.dm)
/obj/vehicle/sealed/mecha/combat/neovgre/auto_assign_occupant_flags(mob/M)
if(driver_amount() < max_drivers)
add_control_flags(M, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
else
add_control_flags(M, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
/obj/vehicle/sealed/mecha/combat/neovgre/mob_exit(mob/M, silent, forced)
if(forced)
..()
/obj/vehicle/sealed/mecha/combat/neovgre/MouseDrop_T(mob/M, mob/user)
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='neovgre'>BEGONE HEATHEN!</span>")
return
else
..()
/obj/vehicle/sealed/mecha/combat/neovgre/moved_inside(mob/living/carbon/human/H)
var/list/Itemlist = H.get_contents()
for(var/obj/item/clockwork/slab/W in Itemlist)
to_chat(H, "<span class='brass'>You safely store [W] inside [src].</span>")
qdel(W)
. = ..()
/obj/vehicle/sealed/mecha/combat/neovgre/obj_destruction()
for(var/mob/M in src)
to_chat(M, "<span class='brass'>You are consumed by the fires raging within Neovgre...</span>")
M.dust()
playsound(src, 'sound/effects/neovgre_exploding.ogg', 100, 0)
src.visible_message("<span class = 'userdanger'>The reactor has gone critical, its going to blow!</span>")
addtimer(CALLBACK(src,.proc/go_critical),breach_time)
/obj/vehicle/sealed/mecha/combat/neovgre/proc/go_critical()
explosion(get_turf(loc), 3, 5, 10, 20, 30)
Destroy(src)
/obj/vehicle/sealed/mecha/combat/neovgre/container_resist(mob/living/user)
to_chat(user, "<span class='brass'>Neovgre requires a lifetime commitment friend, no backing out now!</span>")
return
/obj/vehicle/sealed/mecha/combat/neovgre/process()
..()
if(!obj_integrity) //Integrity is zero but we would heal out of that state if we went into this before it recognises it being zero
return
if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hope to stop the superweapon
cell.charge = INFINITY
max_integrity = INFINITY
obj_integrity = max_integrity
else
if(cell.charge < cell.maxcharge)
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
if (get_clockwork_power() >= delta)
cell.charge += delta
adjust_clockwork_power(-delta)
if(obj_integrity < max_integrity && istype(loc, /turf/open/floor/clockwork))
obj_integrity += min(max_integrity - obj_integrity, max_integrity / 200)
/obj/vehicle/sealed/mecha/combat/neovgre/Initialize()
.=..()
GLOB.neovgre_exists ++
var/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/N = new
N.attach(src)
var/obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla/shocking = new
shocking.attach(src)
/obj/structure/mecha_wreckage/durand/neovgre
name = "\improper Neovgre wreckage?"
desc = "On closer inspection this looks like the wreck of a durand with some spraypainted cardboard duct taped to it!"
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre
equip_cooldown = 8 //Rapid fire heavy laser cannon, simple yet elegant
energy_drain = 30
name = "Arbiter Laser Cannon"
desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere"
fire_sound = 'sound/weapons/neovgre_laser.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/vehicle/sealed/mecha/combat/neovgre/M)
if(istype(M))
return 1
return 0
@@ -0,0 +1,21 @@
/obj/vehicle/sealed/mecha/combat/phazon
desc = "This is a Phazon exosuit. The pinnacle of scientific research and pride of Nanotrasen, it uses cutting edge bluespace technology and expensive materials."
name = "\improper Phazon"
icon_state = "phazon"
movedelay = 2
dir_in = 2 //Facing South.
step_energy_drain = 3
max_integrity = 200
deflect_chance = 30
armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 50, FIRE = 100, ACID = 100)
max_temperature = 25000
wreckage = /obj/structure/mecha_wreckage/phazon
internal_damage_threshold = 25
force = 15
max_equip = 3
phase_state = "phazon-phase"
/obj/vehicle/sealed/mecha/combat/phazon/generate_actions()
. = ..()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_phasing)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_switch_damtype)
@@ -0,0 +1,27 @@
/obj/vehicle/sealed/mecha/combat/reticence
desc = "A silent, fast, and nigh-invisible miming exosuit. Popular among mimes and mime assassins."
name = "\improper reticence"
icon_state = "reticence"
movedelay = 2
dir_in = 1 //Facing North.
max_integrity = 100
deflect_chance = 3
armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
max_temperature = 15000
wreckage = /obj/structure/mecha_wreckage/reticence
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_ROBOTICS, ACCESS_THEATRE)
mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS
internal_damage_threshold = 25
max_equip = 2
step_energy_drain = 3
color = "#87878715"
stepsound = null
turnsound = null
/obj/vehicle/sealed/mecha/combat/reticence/loaded/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/rcd //HAHA IT MAKES WALLS GET IT
ME.attach(src)
@@ -0,0 +1,153 @@
//DO NOT ADD MECHA PARTS TO THE GAME WITH THE DEFAULT "SPRITE ME" SPRITE!
//I'm annoyed I even have to tell you this! SPRITE FIRST, then commit.
/obj/item/mecha_parts/mecha_equipment
name = "mecha equipment"
icon = 'icons/mecha/mecha_equipment.dmi'
icon_state = "mecha_equip"
force = 5
max_integrity = 300
var/equip_cooldown = 0
var/equip_ready = TRUE //whether the equipment is ready for use. (or deactivated/activated for static stuff)
var/energy_drain = 0
var/obj/vehicle/sealed/mecha/chassis = null
///Bitflag. Determines the range of the equipment.
var/range = MECHA_MELEE
/// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this.
var/mech_flags = NONE
var/salvageable = 1
var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed
var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates
var/harmful = FALSE //Controls if equipment can be used to attack by a pacifist.
var/destroy_sound = 'sound/mecha/critdestr.ogg'
/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page()
if(chassis)
send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
send_byjax(chassis.occupants,"exosuit.browser","equipment_menu",chassis.get_equipment_menu(),"dropdowns")
return TRUE
return
/obj/item/mecha_parts/mecha_equipment/proc/update_equip_info()
if(chassis)
send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",get_equip_info())
return TRUE
return
/obj/item/mecha_parts/mecha_equipment/Destroy()
if(chassis)
LAZYREMOVE(chassis.equipment, src)
if(chassis.selected == src)
chassis.selected = null
update_chassis_page()
log_message("[src] is destroyed.", LOG_MECHA)
if(chassis.occupants)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='danger'>[src] is destroyed!</span>")
playsound(chassis, destroy_sound, 50)
if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in.
chassis.max_equip--
chassis = null
return ..()
/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
if(can_attach(M))
if(!user.temporarilyRemoveItemFromInventory(src))
return FALSE
attach(M)
user.visible_message("<span class='notice'>[user] attaches [src] to [M].</span>", "<span class='notice'>You attach [src] to [M].</span>")
return TRUE
to_chat(user, "<span class='warning'>You are unable to attach [src] to [M]!</span>")
return FALSE
/obj/item/mecha_parts/mecha_equipment/proc/get_equip_info()
if(!chassis)
return
var/txt = "<span style=\"color:[equip_ready?"#0f0":"#f00"];\">*</span>&nbsp;"
if(chassis.selected == src)
txt += "<b>[src.name]</b>"
else if(selectable)
txt += "<a href='?src=[REF(chassis)];select_equip=[REF(src)]'>[src.name]</a>"
else
txt += "[src.name]"
return txt
/obj/item/mecha_parts/mecha_equipment/proc/action_checks(atom/target)
if(!target)
return FALSE
if(!chassis)
return FALSE
if(!equip_ready)
return FALSE
if(energy_drain && !chassis.has_charge(energy_drain))
return FALSE
if(chassis.is_currently_ejecting)
return FALSE
if(chassis.equipment_disabled)
to_chat(chassis.occupants, "<span=warn>Error -- Equipment control unit is unresponsive.</span>")
return FALSE
if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT))
return FALSE
return TRUE
/obj/item/mecha_parts/mecha_equipment/proc/action(mob/source, atom/target, params)
TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_EQUIPMENT, equip_cooldown)//Cooldown is on the MECH so people dont bypass it by switching equipment
send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
chassis.use_power(energy_drain)
return TRUE
/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target, mob/user)
if(!chassis)
return FALSE
chassis.use_power(energy_drain)
return do_after(user, equip_cooldown, target, extra_checks = CALLBACK(src, .proc/do_after_checks, target))
/obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, mob/user, delay)
return do_after(user, delay, target, extra_checks = CALLBACK(src, .proc/do_after_checks, target))
/// do after checks for the mecha equipment do afters
/obj/item/mecha_parts/mecha_equipment/proc/do_after_checks(atom/target)
return chassis && (get_dir(chassis, target) & chassis.dir)
/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/vehicle/sealed/mecha/M)
if(LAZYLEN(M.equipment)<M.max_equip)
return TRUE
/obj/item/mecha_parts/mecha_equipment/proc/attach(obj/vehicle/sealed/mecha/M)
LAZYADD(M.equipment, src)
chassis = M
forceMove(M)
log_message("[src] initialized.", LOG_MECHA)
update_chassis_page()
return
/obj/item/mecha_parts/mecha_equipment/proc/detach(atom/moveto=null)
moveto = moveto || get_turf(chassis)
if(src.Move(moveto))
LAZYREMOVE(chassis.equipment, src)
if(chassis.selected == src)
chassis.selected = null
update_chassis_page()
log_message("[src] removed from equipment.", LOG_MECHA)
chassis = null
return
/obj/item/mecha_parts/mecha_equipment/Topic(href,href_list)
if(href_list["detach"])
detach()
/obj/item/mecha_parts/mecha_equipment/log_message(message, message_type=LOG_GAME, color=null, log_globally)
if(chassis)
chassis.log_message("ATTACHMENT: [src] [message]", message_type, color)
else
..()
//Used for reloading weapons/tools etc. that use some form of resource
/obj/item/mecha_parts/mecha_equipment/proc/rearm()
return FALSE
/obj/item/mecha_parts/mecha_equipment/proc/needs_rearm()
return FALSE
@@ -0,0 +1,556 @@
// Sleeper, Medical Beam, and Syringe gun
/obj/item/mecha_parts/mecha_equipment/medical
mech_flags = EXOSUIT_MODULE_MEDICAL
/obj/item/mecha_parts/mecha_equipment/medical/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/mecha_parts/mecha_equipment/medical/can_attach(obj/vehicle/sealed/mecha/medical/M)
if(..() && istype(M))
return 1
/obj/item/mecha_parts/mecha_equipment/medical/attach(obj/vehicle/sealed/mecha/M)
..()
START_PROCESSING(SSobj, src)
/obj/item/mecha_parts/mecha_equipment/medical/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/process()
if(!chassis)
return PROCESS_KILL
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/detach()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper
name = "mounted sleeper"
desc = "Equipment for medical exosuits. A mounted sleeper that stabilizes patients and can inject reagents in the exosuit's reserves."
icon = 'icons/obj/machines/sleeper.dmi'
icon_state = "sleeper"
energy_drain = 20
range = MECHA_MELEE
equip_cooldown = 20
var/mob/living/carbon/patient = null
var/inject_amount = 10
salvageable = 0
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/Destroy()
for(var/atom/movable/AM in src)
AM.forceMove(get_turf(src))
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/Exit(atom/movable/O)
return 0
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/action(mob/source, mob/living/carbon/target, params)
if(!action_checks(target))
return
if(!istype(target))
return
if(!patient_insertion_check(target))
return
to_chat(source, "[icon2html(src, source)]<span class='notice'>You start putting [target] into [src]...</span>")
chassis.visible_message("<span class='warning'>[chassis] starts putting [target] into \the [src].</span>")
if(do_after(source, equip_cooldown, target=target))
if(!chassis || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir))
return
if(!patient_insertion_check(target, source))
return
target.forceMove(src)
patient = target
START_PROCESSING(SSobj, src)
update_equip_info()
to_chat(source, "[icon2html(src, source)]<span class='notice'>[target] successfully loaded into [src]. Life support functions engaged.</span>")
chassis.visible_message("<span class='warning'>[chassis] loads [target] into [src].</span>")
log_message("[target] loaded. Life support functions engaged.", LOG_MECHA)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/patient_insertion_check(mob/living/carbon/target, mob/user)
if(target.buckled)
to_chat(user, "[icon2html(src, user)]<span class='warning'>[target] will not fit into the sleeper because [target.p_theyre()] buckled to [target.buckled]!</span>")
return
if(target.has_buckled_mobs())
to_chat(user, "[icon2html(src, user)]<span class='warning'>[target] will not fit into the sleeper because of the creatures attached to it!</span>")
return
if(patient)
to_chat(user, "[icon2html(src, user)]<span class='warning'>The sleeper is already occupied!</span>")
return
return TRUE
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/go_out()
if(!patient)
return
patient.forceMove(get_turf(src))
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>[patient] ejected. Life support functions disabled.</span>")
log_message("[patient] ejected. Life support functions disabled.", LOG_MECHA)
STOP_PROCESSING(SSobj, src)
patient = null
update_equip_info()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/detach()
if(patient)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='warning'>Unable to detach [src] - equipment occupied!</span>")
return
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/get_equip_info()
var/output = ..()
if(output)
var/temp = ""
if(patient)
temp = "<br />\[Occupant: [patient] ([patient.stat > 1 ? "*DECEASED*" : "Health: [patient.health]%"])\]<br /><a href='?src=[REF(src)];view_stats=1'>View stats</a>|<a href='?src=[REF(src)];eject=1'>Eject</a>"
return "[output] [temp]"
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/Topic(href,href_list)
. = ..()
if(.)
return
if(!(usr in chassis.occupants))
return
if(href_list["eject"])
go_out()
if(href_list["view_stats"])
usr << browse(get_patient_stats(),"window=msleeper")
onclose(usr, "msleeper")
return
if(href_list["inject"])
var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG = locate() in chassis
var/datum/reagent/R = locate(href_list["inject"]) in SG.reagents.reagent_list
if(istype(R))
inject_reagent(R, SG)
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_stats()
if(!patient)
return
return {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[patient] statistics</title>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
<style>
h3 {margin-bottom:2px;font-size:14px;}
#lossinfo, #reagents, #injectwith {padding-left:15px;}
</style>
</head>
<body>
<h3>Health statistics</h3>
<div id="lossinfo">
[get_patient_dam()]
</div>
<h3>Reagents in bloodstream</h3>
<div id="reagents">
[get_patient_reagents()]
</div>
<div id="injectwith">
[get_available_reagents()]
</div>
</body>
</html>"}
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_dam()
var/t1
switch(patient.stat)
if(0)
t1 = "Conscious"
if(1)
t1 = "Unconscious"
if(2)
t1 = "*dead*"
else
t1 = "Unknown"
return {"<font color="[patient.health > 50 ? "#3d5bc3" : "#c51e1e"]"><b>Health:</b> [patient.stat > 1 ? "[t1]" : "[patient.health]% ([t1])"]</font><br />
<font color="[patient.bodytemperature > 50 ? "#3d5bc3" : "#c51e1e"]"><b>Core Temperature:</b> [patient.bodytemperature-T0C]&deg;C ([patient.bodytemperature*1.8-459.67]&deg;F)</font><br />
<font color="[patient.getBruteLoss() < 60 ? "#3d5bc3" : "#c51e1e"]"><b>Brute Damage:</b> [patient.getBruteLoss()]%</font><br />
<font color="[patient.getOxyLoss() < 60 ? "#3d5bc3" : "#c51e1e"]"><b>Respiratory Damage:</b> [patient.getOxyLoss()]%</font><br />
<font color="[patient.getToxLoss() < 60 ? "#3d5bc3" : "#c51e1e"]"><b>Toxin Content:</b> [patient.getToxLoss()]%</font><br />
<font color="[patient.getFireLoss() < 60 ? "#3d5bc3" : "#c51e1e"]"><b>Burn Severity:</b> [patient.getFireLoss()]%</font><br />
<span class='danger'>[patient.getCloneLoss() ? "Subject appears to have cellular damage." : ""]</span><br />
<span class='danger'>[patient.getOrganLoss(ORGAN_SLOT_BRAIN) ? "Significant brain damage detected." : ""]</span><br />
<span class='danger'>[length(patient.get_traumas()) ? "Brain Traumas detected." : ""]</span><br />
"}
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_reagents()
if(patient.reagents)
for(var/datum/reagent/R in patient.reagents.reagent_list)
if(R.volume > 0)
. += "[R]: [round(R.volume,0.01)]<br />"
return . || "None"
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_available_reagents()
var/output
var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun) in chassis
if(SG && SG.reagents && islist(SG.reagents.reagent_list))
for(var/datum/reagent/R in SG.reagents.reagent_list)
if(R.volume > 0)
output += "<a href=\"?src=[REF(src)];inject=[REF(R)]\">Inject [R.name]</a><br />"
return output
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/inject_reagent(datum/reagent/R,obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG)
if(!R || !patient || !SG || !(SG in chassis.equipment))
return 0
var/to_inject = min(R.volume, inject_amount)
if(to_inject && patient.reagents.get_reagent_amount(R.type) + to_inject <= inject_amount*2)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>Injecting [patient] with [to_inject] units of [R.name].</span>")
log_message("Injecting [patient] with [to_inject] units of [R.name].", LOG_MECHA)
log_combat(chassis.occupants, patient, "injected", "[name] ([R] - [to_inject] units)")
SG.reagents.trans_id_to(patient,R.type,to_inject)
update_equip_info()
return
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/update_equip_info()
if(..())
if(patient)
send_byjax(chassis.occupants,"msleeper.browser","lossinfo",get_patient_dam())
send_byjax(chassis.occupants,"msleeper.browser","reagents",get_patient_reagents())
send_byjax(chassis.occupants,"msleeper.browser","injectwith",get_available_reagents())
return 1
return
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/container_resist(mob/living/user)
go_out()
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/process()
if(..())
return
if(!chassis.has_charge(energy_drain))
log_message("Deactivated.", LOG_MECHA)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='warning'>[src] deactivated - no power.</span>")
STOP_PROCESSING(SSobj, src)
return
var/mob/living/carbon/M = patient
if(!M)
return
if(M.health > 0)
M.adjustOxyLoss(-1)
M.AdjustStun(-80)
M.AdjustKnockdown(-80)
M.AdjustParalyzed(-80)
M.AdjustImmobilized(-80)
M.AdjustUnconscious(-80)
if(M.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) < 5)
M.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5)
chassis.use_power(energy_drain)
update_equip_info()
///////////////////////////////// Syringe Gun ///////////////////////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun
name = "exosuit syringe gun"
desc = "Equipment for medical exosuits. A chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur."
icon = 'icons/obj/guns/projectile.dmi'
icon_state = "syringegun"
var/list/syringes
var/list/known_reagents
var/list/processed_reagents
var/max_syringes = 10
var/max_volume = 75 //max reagent volume
var/synth_speed = 5 //[num] reagent units per cycle
energy_drain = 10
var/mode = 0 //0 - fire syringe, 1 - analyze reagents.
range = MECHA_MELEE|MECHA_RANGED
equip_cooldown = 10
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Initialize()
. = ..()
create_reagents(max_volume, NO_REACT)
syringes = new
known_reagents = list(/datum/reagent/medicine/epinephrine="Epinephrine")
processed_reagents = new
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/detach()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/vehicle/sealed/mecha/medical/M)
. = ..()
if(!istype(M))
return FALSE
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/get_equip_info()
var/output = ..()
if(output)
return "[output] \[<a href=\"?src=[REF(src)];toggle_mode=1\">[mode? "Analyze" : "Launch"]</a>\]<br />\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]<br /><a href='?src=[REF(src)];show_reagents=1'>Reagents list</a>"
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/action(mob/source, atom/movable/target, params)
if(!action_checks(target))
return
if(istype(target, /obj/item/reagent_containers/syringe))
return load_syringe(target)
if(istype(target, /obj/item/storage))//Loads syringes from boxes
for(var/obj/item/reagent_containers/syringe/S in target.contents)
load_syringe(S, source)
return
if(mode)
return analyze_reagents(target, source)
if(!syringes.len)
to_chat(source, "[icon2html(src, source)]<span class=\"alert\">No syringes loaded.</span>")
return
if(reagents.total_volume<=0)
to_chat(source, "[icon2html(src, source)]<span class=\"alert\">No available reagents to load syringe with.</span>")
return
if(HAS_TRAIT(source, TRAIT_PACIFISM))
to_chat(source, "<span class=\"alert\">The [src] is lethally chambered! You don't want to risk harming anyone...</span>")
return
var/turf/trg = get_turf(target)
var/obj/item/reagent_containers/syringe/mechsyringe = syringes[1]
mechsyringe.forceMove(get_turf(chassis))
reagents.trans_to(mechsyringe, min(mechsyringe.volume, reagents.total_volume))
syringes -= mechsyringe
mechsyringe.icon = 'icons/obj/chemical.dmi'
mechsyringe.icon_state = "syringeproj"
playsound(chassis, 'sound/items/syringeproj.ogg', 50, TRUE)
log_message("Launched [mechsyringe] from [src] by [source], targeting [target].", LOG_MECHA)
spawn(0) //This code is trash and whoever wrote it should feel bad
for(var/i=0, i<6, i++)
if(!mechsyringe)
break
if(step_towards(mechsyringe,trg))
var/list/mobs = new
for(var/mob/living/carbon/M in mechsyringe.loc)
mobs += M
if(length(mobs))
var/mob/living/carbon/M = pick(mobs)
var/R
mechsyringe.visible_message("<span class=\"attack\"> [M] is hit by the syringe!</span>")
if(M.can_inject(null, 1))
if(mechsyringe.reagents)
for(var/datum/reagent/A in mechsyringe.reagents.reagent_list)
R += "[A.name] ([num2text(A.volume)]"
mechsyringe.icon_state = initial(mechsyringe.icon_state)
mechsyringe.icon = initial(mechsyringe.icon)
mechsyringe.reagents.reaction(M, INJECT)
mechsyringe.reagents.trans_to(M, mechsyringe.reagents.total_volume, log = TRUE)
M.take_bodypart_damage(2)
log_combat(source, M, "shot", "syringegun")
break
else if(mechsyringe.loc == trg)
mechsyringe.icon_state = initial(mechsyringe.icon_state)
mechsyringe.icon = initial(mechsyringe.icon)
mechsyringe.update_icon()
break
else
mechsyringe.icon_state = initial(mechsyringe.icon_state)
mechsyringe.icon = initial(mechsyringe.icon)
mechsyringe.update_icon()
break
sleep(1)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Topic(href,href_list)
..()
if (href_list["toggle_mode"])
mode = !mode
update_equip_info()
return
if (href_list["select_reagents"])
processed_reagents.len = 0
var/m = 0
var/message
for(var/i=1 to known_reagents.len)
if(m>=synth_speed)
break
var/reagent = text2path(href_list["reagent_[i]"])
if(reagent && (reagent in known_reagents))
message = "[m ? ", " : null][known_reagents[reagent]]"
processed_reagents += reagent
m++
if(processed_reagents.len)
message += " added to production"
START_PROCESSING(SSobj, src)
to_chat(usr, message)
to_chat(usr, "[icon2html(src, usr)]<span class='notice'>Reagent processing started.</span>")
log_message("Reagent processing started.", LOG_MECHA)
return
if (href_list["show_reagents"])
if(!(usr in chassis.occupants))
return
usr << browse(get_reagents_page(),"window=msyringegun")
if (href_list["purge_reagent"])
var/reagent = href_list["purge_reagent"]
if(reagent)
reagents.del_reagent(reagent)
return
if (href_list["purge_all"])
reagents.clear_reagents()
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_reagents_page()
var/output = {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>Reagent Synthesizer</title>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
<style>
h3 {margin-bottom:2px;font-size:14px;}
#reagents, #reagents_form {}
form {width: 90%; margin:10px auto; border:1px dotted #999; padding:6px;}
#submit {margin-top:5px;}
</style>
</head>
<body>
<h3>Current reagents:</h3>
<div id="reagents">
[get_current_reagents()]
</div>
<h3>Reagents production:</h3>
<div id="reagents_form">
[get_reagents_form()]
</div>
</body>
</html>
"}
return output
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_reagents_form()
var/r_list = get_reagents_list()
var/inputs
if(r_list)
inputs += "<input type=\"hidden\" name=\"src\" value=\"[REF(src)]\">"
inputs += "<input type=\"hidden\" name=\"select_reagents\" value=\"1\">"
inputs += "<input id=\"submit\" type=\"submit\" value=\"Apply settings\">"
var/output = {"<form action="byond://" method="get">
[r_list || "No known reagents"]
[inputs]
</form>
[r_list? "<span style=\"font-size:80%;\">Only the first [synth_speed] selected reagent\s will be added to production</span>" : null]
"}
return output
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_reagents_list()
var/output
for(var/i=1 to known_reagents.len)
var/reagent_id = known_reagents[i]
output += {"<input type="checkbox" value="[reagent_id]" name="reagent_[i]" [(reagent_id in processed_reagents)? "checked=\"1\"" : null]> [known_reagents[reagent_id]]<br />"}
return output
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_current_reagents()
var/output
for(var/datum/reagent/R in reagents.reagent_list)
if(R.volume > 0)
output += "[R]: [round(R.volume,0.001)] - <a href=\"?src=[REF(src)];purge_reagent=[R]\">Purge Reagent</a><br />"
if(output)
output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - <a href=\"?src=[REF(src)];purge_all=1\">Purge All</a>"
return output || "None"
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/load_syringe(obj/item/reagent_containers/syringe/S, mob/user)
if(syringes.len<max_syringes)
if(get_dist(src,S) >= 2)
to_chat(user, "[icon2html(src, user)]<span class='warning'>The syringe is too far away!</span>")
return 0
for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows)
if(!(D.CanPass(S,src.loc)))
to_chat(user, "[icon2html(src, user)]<span class='warning'>Unable to load syringe!</span>")
return 0
for(var/obj/machinery/door/D in S.loc)//Checks for doors
if(!(D.CanPass(S,src.loc)))
to_chat(user, "[icon2html(src, user)]<span class='warning'>Unable to load syringe!</span>")
return 0
S.reagents.trans_to(src, S.reagents.total_volume)
S.forceMove(src)
syringes += S
to_chat(user, "[icon2html(src, user)]<span class='notice'>Syringe loaded.</span>")
update_equip_info()
return 1
to_chat(user, "[icon2html(src, user)]<span class='warning'>[src]'s syringe chamber is full!</span>")
return 0
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/analyze_reagents(atom/A, mob/user)
if(get_dist(src,A) >= 4)
to_chat(user, "[icon2html(src, user)]<span class='notice'>The object is too far away!</span>")
return FALSE
if(!A.reagents || ismob(A))
to_chat(user, "[icon2html(src, user)]<span class='warning'>No reagent info gained from [A].</span>")
return FALSE
to_chat(user, "[icon2html(src, user)]<span class='notice'>Analyzing reagents...</span>")
for(var/datum/reagent/R in A.reagents.reagent_list)
if(R.can_synth && add_known_reagent(R.type,R.name))
to_chat(user, "[icon2html(src, user)]<span class='notice'>Reagent analyzed, identified as [R.name] and added to database.</span>")
send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form())
to_chat(user, "[icon2html(src, user)]<span class='notice'>Analysis complete.</span>")
return TRUE
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/add_known_reagent(r_id,r_name)
if(!(r_id in known_reagents))
known_reagents += r_id
known_reagents[r_id] = r_name
return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/update_equip_info()
if(..())
send_byjax(chassis.occupants,"msyringegun.browser","reagents",get_current_reagents())
send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form())
return TRUE
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/on_reagent_change(changetype)
..()
update_equip_info()
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/process()
if(..())
return
if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(energy_drain))
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='alert'>Reagent processing stopped.</span>")
log_message("Reagent processing stopped.", LOG_MECHA)
STOP_PROCESSING(SSobj, src)
return
var/amount = synth_speed / processed_reagents.len
for(var/reagent in processed_reagents)
reagents.add_reagent(reagent,amount)
chassis.use_power(energy_drain)
///////////////////////////////// Medical Beam ///////////////////////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam
name = "exosuit medical beamgun"
desc = "Equipment for medical exosuits. Generates a focused beam of medical nanites."
icon_state = "mecha_medigun"
energy_drain = 10
range = MECHA_MELEE|MECHA_RANGED
equip_cooldown = 0
var/obj/item/gun/medbeam/mech/medigun
custom_materials = list(/datum/material/iron = 15000, /datum/material/glass = 8000, /datum/material/plasma = 3000, /datum/material/gold = 8000, /datum/material/diamond = 2000)
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/Initialize()
. = ..()
medigun = new(src)
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/Destroy()
qdel(medigun)
return ..()
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/process()
if(..())
return
medigun.process()
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/action(mob/source, atom/movable/target, params)
medigun.process_fire(target, loc)
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/detach()
STOP_PROCESSING(SSobj, src)
medigun.LoseTarget()
return ..()
@@ -0,0 +1,183 @@
// Drill, Diamond drill, Mining scanner
#define DRILL_BASIC 1
#define DRILL_HARDENED 2
/obj/item/mecha_parts/mecha_equipment/drill
name = "exosuit drill"
desc = "Equipment for engineering and combat exosuits. This is the drill that'll pierce the heavens!"
icon_state = "mecha_drill"
equip_cooldown = 15
energy_drain = 10
force = 15
harmful = TRUE
range = MECHA_MELEE
tool_behaviour = TOOL_DRILL
toolspeed = 0.9
var/drill_delay = 7
var/drill_level = DRILL_BASIC
mech_flags = EXOSUIT_MODULE_WORKING | EXOSUIT_MODULE_COMBAT
/obj/item/mecha_parts/mecha_equipment/drill/Initialize()
. = ..()
AddComponent(/datum/component/butchering, 50, 100, null, null, TRUE)
/obj/item/mecha_parts/mecha_equipment/drill/action(mob/source, atom/target, params)
if(!action_checks(target))
return
if(isspaceturf(target))
return
if(isobj(target))
var/obj/target_obj = target
if(target_obj.resistance_flags & UNACIDABLE)
return
target.visible_message("<span class='warning'>[chassis] starts to drill [target].</span>", \
"<span class='userdanger'>[chassis] starts to drill [target]...</span>", \
"<span class='hear'>You hear drilling.</span>")
if(do_after_cooldown(target, source))
log_message("Started drilling [target]", LOG_MECHA)
if(isturf(target))
var/turf/T = target
T.drill_act(src, source)
return
while(do_after_mecha(target, source, drill_delay))
if(isliving(target))
drill_mob(target, source)
playsound(src,'sound/weapons/drill.ogg',40,TRUE)
else if(isobj(target))
var/obj/O = target
O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target))
playsound(src,'sound/weapons/drill.ogg',40,TRUE)
else
return
return ..()
/turf/proc/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user)
return
/turf/closed/wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user)
if(drill.do_after_mecha(src, user, 60 / drill.drill_level))
drill.log_message("Drilled through [src]", LOG_MECHA)
dismantle_wall(TRUE, FALSE)
/turf/closed/wall/r_wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user)
if(drill.drill_level >= DRILL_HARDENED)
if(drill.do_after_mecha(src, user, 120 / drill.drill_level))
drill.log_message("Drilled through [src]", LOG_MECHA)
dismantle_wall(TRUE, FALSE)
else
to_chat(user, "[icon2html(src, user)]<span class='danger'>[src] is too durable to drill through.</span>")
/turf/closed/mineral/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill, mob/user)
for(var/turf/closed/mineral/M in range(drill.chassis,1))
if(get_dir(drill.chassis,M)&drill.chassis.dir)
M.gets_drilled()
drill.log_message("[user] drilled through [src]", LOG_MECHA)
drill.move_ores()
/turf/open/floor/plating/asteroid/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill)
for(var/turf/open/floor/plating/asteroid/M in range(1, drill.chassis))
if((get_dir(drill.chassis,M)&drill.chassis.dir) && !M.dug)
M.getDug()
drill.log_message("Drilled through [src]", LOG_MECHA)
drill.move_ores()
/obj/item/mecha_parts/mecha_equipment/drill/proc/move_ores()
if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.equipment && istype(chassis, /obj/vehicle/sealed/mecha/working/ripley))
var/obj/vehicle/sealed/mecha/working/ripley/R = chassis //we could assume that it's a ripley because it has a clamp, but that's ~unsafe~ and ~bad practice~
R.collect_ore()
/obj/item/mecha_parts/mecha_equipment/drill/can_attach(obj/vehicle/sealed/mecha/M as obj)
if(..())
if(istype(M, /obj/vehicle/sealed/mecha/working) || istype(M, /obj/vehicle/sealed/mecha/combat))
return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/drill/attach(obj/vehicle/sealed/mecha/M)
..()
var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
butchering.butchering_enabled = TRUE
/obj/item/mecha_parts/mecha_equipment/drill/detach(atom/moveto)
..()
var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
butchering.butchering_enabled = FALSE
/obj/item/mecha_parts/mecha_equipment/drill/proc/drill_mob(mob/living/target, mob/user)
target.visible_message("<span class='danger'>[chassis] is drilling [target] with [src]!</span>", \
"<span class='userdanger'>[chassis] is drilling you with [src]!</span>")
log_combat(user, target, "drilled", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
if(target.stat == DEAD && target.getBruteLoss() >= 200)
log_combat(user, target, "gibbed", name)
if(LAZYLEN(target.butcher_results) || LAZYLEN(target.guaranteed_butcher_results))
var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
butchering.Butcher(chassis, target)
else
target.gib()
else
//drill makes a hole
var/obj/item/bodypart/target_part = target.get_bodypart(ran_zone(BODY_ZONE_CHEST))
target.apply_damage(10, BRUTE, BODY_ZONE_CHEST, target.run_armor_check(target_part, MELEE))
//blood splatters
var/splatter_dir = get_dir(chassis, target)
if(isalien(target))
new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target.drop_location(), splatter_dir)
else
if(ishuman(target))
var/mob/living/carbon/human/H = target
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir, H.dna.species.exotic_blood_color)
else
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir)
//organs go everywhere
if(target_part && prob(10 * drill_level))
target_part.dismember(BRUTE)
/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill
name = "diamond-tipped exosuit drill"
desc = "Equipment for engineering and combat exosuits. This is an upgraded version of the drill that'll pierce the heavens!"
icon_state = "mecha_diamond_drill"
equip_cooldown = 10
drill_delay = 4
drill_level = DRILL_HARDENED
force = 15
toolspeed = 0.7
/obj/item/mecha_parts/mecha_equipment/mining_scanner
name = "exosuit mining scanner"
desc = "Equipment for working exosuits. It will automatically check surrounding rock for useful minerals."
icon_state = "mecha_analyzer"
selectable = 0
equip_cooldown = 15
var/scanning_time = 0
mech_flags = EXOSUIT_MODULE_WORKING
/obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize()
. = ..()
START_PROCESSING(SSfastprocess, src)
/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/vehicle/sealed/mecha/M as obj)
if(..())
if(istype(M, /obj/vehicle/sealed/mecha/working))
return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/mining_scanner/process()
if(!loc)
STOP_PROCESSING(SSfastprocess, src)
qdel(src)
if(istype(loc, /obj/vehicle/sealed/mecha/working) && scanning_time <= world.time)
var/obj/vehicle/sealed/mecha/working/mecha = loc
if(!mecha.occupants)
return
scanning_time = world.time + equip_cooldown
mineral_scan_pulse(get_turf(src))
#undef DRILL_BASIC
#undef DRILL_HARDENED
@@ -0,0 +1,571 @@
// Teleporter, Wormhole generator, Gravitational catapult, Armor booster modules,
// Repair droid, Tesla Energy relay, Generators
////////////////////////////////////////////// TELEPORTER ///////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/teleporter
name = "mounted teleporter"
desc = "An exosuit module that allows exosuits to teleport to any position in view."
icon_state = "mecha_teleport"
equip_cooldown = 150
energy_drain = 1000
range = MECHA_RANGED
var/teleport_range = 7
/obj/item/mecha_parts/mecha_equipment/teleporter/action(mob/source, atom/target, params)
if(!action_checks(target) || is_centcom_level(loc.z))
return
var/turf/T = get_turf(target)
if(T && (loc.z == T.z) && (get_dist(loc, T) <= teleport_range))
do_teleport(chassis, T, 4, channel = TELEPORT_CHANNEL_BLUESPACE)
return ..()
////////////////////////////////////////////// WORMHOLE GENERATOR //////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/wormhole_generator
name = "mounted wormhole generator"
desc = "An exosuit module that allows generating of small quasi-stable wormholes."
icon_state = "mecha_wholegen"
equip_cooldown = 50
energy_drain = 300
range = MECHA_RANGED
/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(mob/source, atom/target, params)
if(!action_checks(target) || is_centcom_level(loc.z))
return
var/list/theareas = get_areas_in_range(100, chassis)
if(!theareas.len)
return
var/area/thearea = pick(theareas)
var/list/L = list()
var/turf/pos = get_turf(src)
for(var/turf/T in get_area_turfs(thearea.type))
if(!T.density && pos.z == T.z)
var/clear = TRUE
for(var/obj/O in T)
if(O.density)
clear = FALSE
break
if(clear)
L+=T
if(!L.len)
return
var/turf/target_turf = pick(L)
if(!target_turf)
return
var/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, 300, 1, /obj/effect/portal/anom)
var/turf/T = get_turf(target)
message_admins("[ADMIN_LOOKUPFLW(source)] used a Wormhole Generator in [ADMIN_VERBOSEJMP(T)]")
log_game("[key_name(source)] used a Wormhole Generator in [AREACOORD(T)]")
src = null
QDEL_LIST_IN(created, rand(150,300))
return ..()
/////////////////////////////////////// GRAVITATIONAL CATAPULT ///////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/gravcatapult
name = "mounted gravitational catapult"
desc = "An exosuit mounted Gravitational Catapult."
icon_state = "mecha_teleport"
equip_cooldown = 10
energy_drain = 100
range = MECHA_MELEE|MECHA_RANGED
var/atom/movable/locked
var/mode = 1 //1 - gravsling 2 - gravpush
/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(mob/source, atom/movable/target, params)
if(!action_checks(target))
return
switch(mode)
if(1)
if(!locked)
if(!istype(target) || target.anchored || target.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)
to_chat(source, "[icon2html(src, source)]<span class='warning'>Unable to lock on [target]!</span>")
return
if(ismob(target))
var/mob/M = target
if(M.mob_negates_gravity())
to_chat(source, "[icon2html(src, source)]<span class='warning'>Unable to lock on [target]!</span>")
return
locked = target
to_chat(source, "[icon2html(src, source)]<span class='notice'>Locked on [target].</span>")
send_byjax(source,"exosuit.browser","[REF(src)]",src.get_equip_info())
else if(target!=locked)
if(locked in view(chassis))
var/turf/targ = get_turf(target)
var/turf/orig = get_turf(locked)
locked.throw_at(target, 14, 1.5)
locked = null
send_byjax(source,"exosuit.browser","[REF(src)]",src.get_equip_info())
log_game("[key_name(source)] used a Gravitational Catapult to throw [locked] (From [AREACOORD(orig)]) at [target] ([AREACOORD(targ)]).")
return ..()
else
locked = null
to_chat(source, "[icon2html(src, source)]<span class='notice'>Lock on [locked] disengaged.</span>")
send_byjax(source,"exosuit.browser","[REF(src)]",src.get_equip_info())
if(2)
var/list/atoms = list()
if(isturf(target))
atoms = range(3, target)
else
atoms = orange(3, target)
for(var/atom/movable/A in atoms)
if(A.anchored || A.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)
continue
if(ismob(A))
var/mob/M = A
if(M.mob_negates_gravity())
continue
INVOKE_ASYNC(src, .proc/do_scatter, A, target)
var/turf/T = get_turf(target)
log_game("[key_name(source)] used a Gravitational Catapult repulse wave on [AREACOORD(T)]")
return ..()
/obj/item/mecha_parts/mecha_equipment/gravcatapult/proc/do_scatter(atom/movable/A, atom/movable/target)
var/iter = 5-get_dist(A,target)
for(var/i in 0 to iter)
step_away(A,target)
sleep(2)
/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info()
return "[..()] [mode==1?"([locked||"Nothing"])":null] \[<a href='?src=[REF(src)];mode=1'>S</a>|<a href='?src=[REF(src)];mode=2'>P</a>\]"
/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list)
..()
if(href_list["mode"])
mode = text2num(href_list["mode"])
send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
return
//////////////////////////// ARMOR BOOSTER MODULES //////////////////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants.
name = "armor booster module (Close Combat Weaponry)"
desc = "Boosts exosuit armor against armed melee attacks. Requires energy to operate."
icon_state = "mecha_abooster_ccw"
equip_cooldown = 10
energy_drain = 50
range = 0
var/deflect_coeff = 1.15
var/damage_coeff = 0.8
selectable = 0
/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/attack_react()
if(energy_drain && !chassis.has_charge(energy_drain))
return FALSE
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_ARMOR, equip_cooldown)
return TRUE
/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
name = "armor booster module (Ranged Weaponry)"
desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots. Requires energy to operate."
icon_state = "mecha_abooster_proj"
equip_cooldown = 10
energy_drain = 50
range = 0
var/deflect_coeff = 1.15
var/damage_coeff = 0.8
selectable = 0
/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/projectile_react()
if(energy_drain && !chassis.has_charge(energy_drain))
return FALSE
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_ARMOR, equip_cooldown)
return TRUE
////////////////////////////////// REPAIR DROID //////////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/repair_droid
name = "exosuit repair droid"
desc = "An automated repair droid for exosuits. Scans for damage and repairs it. Can fix almost all types of external or internal damage."
icon_state = "repair_droid"
energy_drain = 50
range = 0
var/health_boost = 1
var/icon/droid_overlay
var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH)
selectable = 0
/obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy()
STOP_PROCESSING(SSobj, src)
if(chassis)
chassis.cut_overlay(droid_overlay)
return ..()
/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/vehicle/sealed/mecha/M)
..()
droid_overlay = new(src.icon, icon_state = "repair_droid")
M.add_overlay(droid_overlay)
/obj/item/mecha_parts/mecha_equipment/repair_droid/detach()
chassis.cut_overlay(droid_overlay)
STOP_PROCESSING(SSobj, src)
..()
/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info()
if(!chassis)
return
return "<span style=\"color:[equip_ready?"#0f0":"#f00"];\">*</span>&nbsp; [src.name] - <a href='?src=[REF(src)];toggle_repairs=1'>[equip_ready?"A":"Dea"]ctivate</a>"
/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list)
..()
if(href_list["toggle_repairs"])
chassis.cut_overlay(droid_overlay)
if(equip_ready)
START_PROCESSING(SSobj, src)
droid_overlay = new(src.icon, icon_state = "repair_droid_a")
log_message("Activated.", LOG_MECHA)
else
STOP_PROCESSING(SSobj, src)
droid_overlay = new(src.icon, icon_state = "repair_droid")
log_message("Deactivated.", LOG_MECHA)
chassis.add_overlay(droid_overlay)
send_byjax(chassis.occupants,"exosuit.browser", "[REF(src)]", get_equip_info())
/obj/item/mecha_parts/mecha_equipment/repair_droid/process()
if(!chassis)
STOP_PROCESSING(SSobj, src)
return
var/h_boost = health_boost
var/repaired = 0
if(chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT)
h_boost *= -2
else if(chassis.internal_damage && prob(15))
for(var/int_dam_flag in repairable_damage)
if(chassis.internal_damage & int_dam_flag)
chassis.clearInternalDamage(int_dam_flag)
repaired = 1
break
if(h_boost<0 || chassis.obj_integrity < chassis.max_integrity)
chassis.obj_integrity += min(h_boost, chassis.max_integrity-chassis.obj_integrity)
repaired = 1
if(repaired)
if(!chassis.use_power(energy_drain))
STOP_PROCESSING(SSobj, src)
else //no repair needed, we turn off
STOP_PROCESSING(SSobj, src)
chassis.cut_overlay(droid_overlay)
droid_overlay = new(src.icon, icon_state = "repair_droid")
chassis.add_overlay(droid_overlay)
/////////////////////////////////// TESLA ENERGY RELAY ////////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
name = "exosuit energy relay"
desc = "An exosuit module that wirelessly drains energy from any available power channel in area. The performance index is quite low."
icon_state = "tesla"
energy_drain = 0
range = 0
var/coeff = 100
var/list/use_channels = list(EQUIP,ENVIRON,LIGHT)
selectable = 0
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach()
STOP_PROCESSING(SSobj, src)
..()
return
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_charge()
if(equip_ready) //disabled
return
var/area/A = get_area(chassis)
var/pow_chan = GET_MUTATION_POWER_channel(A)
if(pow_chan)
return 1000 //making magic
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/GET_MUTATION_POWER_channel(area/A)
var/pow_chan
if(A)
for(var/c in use_channels)
if(A.powered(c))
pow_chan = c
break
return pow_chan
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list)
..()
if(href_list["toggle_relay"])
if(equip_ready) //inactive
START_PROCESSING(SSobj, src)
log_message("Activated.", LOG_MECHA)
else
STOP_PROCESSING(SSobj, src)
log_message("Deactivated.", LOG_MECHA)
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info()
if(!chassis)
return
return "<span style=\"color:[equip_ready?"#0f0":"#f00"];\">*</span>&nbsp; [src.name] - <a href='?src=[REF(src)];toggle_relay=1'>[equip_ready?"A":"Dea"]ctivate</a>"
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/process()
if(!chassis || chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT)
STOP_PROCESSING(SSobj, src)
return
var/cur_charge = chassis.get_charge()
if(isnull(cur_charge) || !chassis.cell)
STOP_PROCESSING(SSobj, src)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>No power cell detected.</span>")
return
if(cur_charge < chassis.cell.maxcharge)
var/area/A = get_area(chassis)
if(A)
var/pow_chan
for(var/c in use_channels)
if(A.powered(c))
pow_chan = c
break
if(pow_chan)
var/delta = min(20, chassis.cell.maxcharge-cur_charge)
chassis.give_power(delta)
A.use_power(delta*coeff, pow_chan)
/////////////////////////////////////////// GENERATOR /////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/generator
name = "exosuit plasma converter"
desc = "An exosuit module that generates power using solid plasma as fuel. Pollutes the environment."
icon_state = "tesla"
range = MECHA_MELEE
var/coeff = 100
var/obj/item/stack/sheet/fuel
var/max_fuel = 150000
var/fuel_per_cycle_idle = 25
var/fuel_per_cycle_active = 200
var/power_per_cycle = 20
/obj/item/mecha_parts/mecha_equipment/generator/Initialize()
. = ..()
generator_init()
/obj/item/mecha_parts/mecha_equipment/generator/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/mecha_parts/mecha_equipment/generator/proc/generator_init()
fuel = new /obj/item/stack/sheet/mineral/plasma(src, 0)
/obj/item/mecha_parts/mecha_equipment/generator/detach()
STOP_PROCESSING(SSobj, src)
..()
/obj/item/mecha_parts/mecha_equipment/generator/Topic(href, href_list)
..()
if(href_list["toggle"])
if(equip_ready) //inactive
START_PROCESSING(SSobj, src)
log_message("Activated.", LOG_MECHA)
else
STOP_PROCESSING(SSobj, src)
log_message("Deactivated.", LOG_MECHA)
/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
var/output = ..()
if(output)
return "[output] \[[fuel]: [round(fuel.amount*MINERAL_MATERIAL_AMOUNT,0.1)] cm<sup>3</sup>\] - <a href='?src=[REF(src)];toggle=1'>[equip_ready?"A":"Dea"]ctivate</a>"
/obj/item/mecha_parts/mecha_equipment/generator/action(mob/source, atom/movable/target, params)
if(chassis)
if(load_fuel(target, source))
send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
return ..()
/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(obj/item/stack/sheet/P, mob/user)
if(P.type == fuel.type && P.amount > 0)
var/to_load = max(max_fuel - fuel.amount*MINERAL_MATERIAL_AMOUNT,0)
if(to_load)
var/units = min(max(round(to_load / MINERAL_MATERIAL_AMOUNT),1),P.amount)
fuel.amount += units
P.use(units)
to_chat(user, "[icon2html(src, user)]<span class='notice'>[units] unit\s of [fuel] successfully loaded.</span>")
return units
else
to_chat(user, "[icon2html(src, user)]<span class='notice'>Unit is full.</span>")
return 0
else
to_chat(user, "[icon2html(src, user)]<span class='warning'>[fuel] traces in target minimal! [P] cannot be used as fuel.</span>")
return
/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user, params)
load_fuel(weapon)
/obj/item/mecha_parts/mecha_equipment/generator/process()
if(!chassis)
STOP_PROCESSING(SSobj, src)
return
if(fuel.amount<=0)
STOP_PROCESSING(SSobj, src)
log_message("Deactivated - no fuel.", LOG_MECHA)
return
var/cur_charge = chassis.get_charge()
if(isnull(cur_charge))
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>No power cell detected.</span>")
log_message("Deactivated.", LOG_MECHA)
STOP_PROCESSING(SSobj, src)
return
var/use_fuel = fuel_per_cycle_idle
if(cur_charge < chassis.cell.maxcharge)
use_fuel = fuel_per_cycle_active
chassis.give_power(power_per_cycle)
fuel.amount -= min(use_fuel/MINERAL_MATERIAL_AMOUNT,fuel.amount)
update_equip_info()
return TRUE
/obj/item/mecha_parts/mecha_equipment/generator/nuclear
name = "exonuclear reactor"
desc = "An exosuit module that generates power using uranium as fuel. Pollutes the environment."
icon_state = "tesla"
max_fuel = 50000
fuel_per_cycle_idle = 10
fuel_per_cycle_active = 30
power_per_cycle = 50
var/rad_per_cycle = 30
/obj/item/mecha_parts/mecha_equipment/generator/nuclear/generator_init()
fuel = new /obj/item/stack/sheet/mineral/uranium(src, 0)
/obj/item/mecha_parts/mecha_equipment/generator/nuclear/process()
if(..())
radiation_pulse(get_turf(src), rad_per_cycle)
/////////////////////////////////////////// THRUSTERS /////////////////////////////////////////////
/obj/item/mecha_parts/mecha_equipment/thrusters
name = "generic exosuit thrusters" //parent object, in-game sources will be a child object
desc = "A generic set of thrusters, from an unknown source. Uses not-understood methods to propel exosuits seemingly for free."
icon_state = "thrusters"
selectable = FALSE
var/effect_type = /obj/effect/particle_effect/sparks
/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
for(var/obj/item/I in M.equipment)
if(istype(I, src))
to_chat(user, "<span class='warning'>[M] already has this thruster package!</span>")
return FALSE
. = ..()
/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/vehicle/sealed/mecha/M)
M.active_thrusters = src //Enable by default
. = ..()
/obj/item/mecha_parts/mecha_equipment/thrusters/detach()
if(chassis?.active_thrusters == src)
chassis.active_thrusters = null
. = ..()
/obj/item/mecha_parts/mecha_equipment/thrusters/Destroy()
if(chassis?.active_thrusters == src)
chassis.active_thrusters = null
. = ..()
/obj/item/mecha_parts/mecha_equipment/thrusters/Topic(href,href_list)
..()
if(!chassis)
return
if(href_list["mode"])
var/mode = text2num(href_list["mode"])
switch(mode)
if(0)
enable()
if(1)
disable()
return
/obj/item/mecha_parts/mecha_equipment/thrusters/proc/enable()
if (chassis.active_thrusters == src)
return
chassis.active_thrusters = src
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>[src] enabled.</span>")
/obj/item/mecha_parts/mecha_equipment/thrusters/proc/disable()
if(chassis.active_thrusters != src)
return
chassis.active_thrusters = null
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>[src] disabled.</span>")
/obj/item/mecha_parts/mecha_equipment/thrusters/get_equip_info()
return "[..()] \[<a href='?src=[REF(src)];mode=0'>Enable</a>|<a href='?src=[REF(src)];mode=1'>Disable</a>\]"
/obj/item/mecha_parts/mecha_equipment/thrusters/proc/thrust(movement_dir)
if(!chassis)
return FALSE
generate_effect(movement_dir)
return TRUE //This parent should never exist in-game outside admeme use, so why not let it be a creative thruster?
/obj/item/mecha_parts/mecha_equipment/thrusters/proc/generate_effect(movement_dir)
var/obj/effect/particle_effect/E = new effect_type(get_turf(chassis))
E.dir = turn(movement_dir, 180)
step(E, turn(movement_dir, 180))
QDEL_IN(E, 5)
/obj/item/mecha_parts/mecha_equipment/thrusters/gas
name = "RCS thruster package"
desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments, by expelling gas from the internal life support tank."
effect_type = /obj/effect/particle_effect/smoke
var/move_cost = 20 //moles per step
/obj/item/mecha_parts/mecha_equipment/thrusters/gas/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
if(!M.internal_tank)
to_chat(user, "<span class='warning'>[M] does not have an internal tank and cannot support this upgrade!</span>")
return FALSE
. = ..()
/obj/item/mecha_parts/mecha_equipment/thrusters/gas/thrust(movement_dir)
if(!chassis || !chassis.internal_tank)
return FALSE
var/moles = chassis.internal_tank.air_contents.total_moles()
if(moles < move_cost)
chassis.internal_tank.air_contents.remove(moles)
return FALSE
chassis.internal_tank.air_contents.remove(move_cost)
generate_effect(movement_dir)
return TRUE
/obj/item/mecha_parts/mecha_equipment/thrusters/ion //for mechs with built-in thrusters, should never really exist un-attached to a mech
name = "Ion thruster package"
desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments."
detachable = FALSE
salvageable = FALSE
effect_type = /obj/effect/particle_effect/ion_trails
/obj/item/mecha_parts/mecha_equipment/thrusters/ion/thrust(movement_dir)
if(!chassis)
return FALSE
if(chassis.use_power(chassis.step_energy_drain))
generate_effect(movement_dir)
return TRUE
return FALSE
@@ -0,0 +1,14 @@
/obj/item/mecha_parts/concealed_weapon_bay
name = "concealed weapon bay"
desc = "A compartment that allows a non-combat mecha to equip one weapon while hiding the weapon from plain sight."
icon = 'icons/mecha/mecha_equipment.dmi'
icon_state = "mecha_weapon_bay"
/obj/item/mecha_parts/concealed_weapon_bay/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
if(istype(M, /obj/vehicle/sealed/mecha/combat))
to_chat(user, "<span class='warning'>[M] can already hold weapons!</span>")
return
if(locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents)
to_chat(user, "<span class='warning'>[M] already has a concealed weapon bay!</span>")
return
..()
@@ -0,0 +1,410 @@
//Hydraulic clamp, Kill clamp, Extinguisher, RCD, Cable layer.
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp
name = "hydraulic clamp"
desc = "Equipment for engineering exosuits. Lifts objects and loads them into cargo."
icon_state = "mecha_clamp"
equip_cooldown = 15
energy_drain = 10
tool_behaviour = TOOL_RETRACTOR
range = MECHA_MELEE
toolspeed = 0.8
var/dam_force = 20
var/obj/vehicle/sealed/mecha/working/ripley/cargo_holder
harmful = TRUE
mech_flags = EXOSUIT_MODULE_RIPLEY
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/vehicle/sealed/mecha/working/ripley/M)
if(..())
if(istype(M))
return 1
return 0
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/attach(obj/vehicle/sealed/mecha/M)
..()
cargo_holder = M
return
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/detach(atom/moveto = null)
..()
cargo_holder = null
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(mob/source, atom/target, params)
if(!action_checks(target))
return
if(!cargo_holder)
return
if(ismecha(target))
var/obj/vehicle/sealed/mecha/M = target
var/have_ammo
for(var/obj/item/mecha_ammo/box in cargo_holder.cargo)
if(istype(box, /obj/item/mecha_ammo) && box.rounds)
have_ammo = TRUE
if(M.ammo_resupply(box, source, TRUE))
return
if(have_ammo)
to_chat(source, "No further supplies can be provided to [M].")
else
to_chat(source, "No providable supplies found in cargo hold")
return
if(isobj(target))
var/obj/O = target
if(istype(O, /obj/machinery/door/firedoor))
var/obj/machinery/door/firedoor/D = O
D.try_to_crowbar(src, source)
return
if(istype(O, /obj/machinery/door/airlock/))
var/obj/machinery/door/airlock/D = O
D.try_to_crowbar(src, source)
return
if(!O.anchored)
if(cargo_holder.cargo.len < cargo_holder.cargo_capacity)
chassis.visible_message("<span class='notice'>[chassis] lifts [target] and starts to load it into cargo compartment.</span>")
O.set_anchored(TRUE)
if(do_after_cooldown(target, source))
cargo_holder.cargo += O
O.forceMove(chassis)
O.set_anchored(FALSE)
to_chat(source, "[icon2html(src, source)]<span class='notice'>[target] successfully loaded.</span>")
log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]", LOG_MECHA)
else
O.set_anchored(initial(O.anchored))
else
to_chat(source, "[icon2html(src, source)]<span class='warning'>Not enough room in cargo compartment!</span>")
else
to_chat(source, "[icon2html(src, source)]<span class='warning'>[target] is firmly secured!</span>")
else if(isliving(target))
var/mob/living/M = target
if(M.stat == DEAD)
return
if(source.a_intent == INTENT_HARM)
M.take_overall_damage(dam_force)
if(!M)
return
M.adjustOxyLoss(round(dam_force/2))
M.updatehealth()
target.visible_message("<span class='danger'>[chassis] squeezes [target]!</span>", \
"<span class='userdanger'>[chassis] squeezes you!</span>",\
"<span class='hear'>You hear something crack.</span>")
log_combat(source, M, "attacked", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
else
step_away(M,chassis)
to_chat(source, "[icon2html(src, source)]<span class='notice'>You push [target] out of the way.</span>")
chassis.visible_message("<span class='notice'>[chassis] pushes [target] out of the way.</span>")
return ..()
//This is pretty much just for the death-ripley
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill
name = "\improper KILL CLAMP"
desc = "They won't know what clamped them!"
energy_drain = 0
dam_force = 0
var/real_clamp = FALSE
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/real
desc = "They won't know what clamped them! This time for real!"
energy_drain = 10
dam_force = 20
real_clamp = TRUE
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/action(mob/source, atom/target, params)
if(!action_checks(target))
return
if(!cargo_holder)
return
if(isobj(target))
var/obj/O = target
if(!O.anchored)
if(cargo_holder.cargo.len < cargo_holder.cargo_capacity)
chassis.visible_message("<span class='notice'>[chassis] lifts [target] and starts to load it into cargo compartment.</span>")
O.set_anchored(TRUE)
if(do_after_cooldown(target, source))
cargo_holder.cargo += O
O.forceMove(chassis)
O.set_anchored(FALSE)
to_chat(source, "[icon2html(src, source)]<span class='notice'>[target] successfully loaded.</span>")
log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]", LOG_MECHA)
else
O.set_anchored(initial(O.anchored))
else
to_chat(source, "[icon2html(src, source)]<span class='warning'>Not enough room in cargo compartment!</span>")
else
to_chat(source, "[icon2html(src, source)]<span class='warning'>[target] is firmly secured!</span>")
else if(isliving(target))
var/mob/living/M = target
if(M.stat == DEAD)
return
if(source.a_intent == INTENT_HARM)
if(real_clamp)
M.take_overall_damage(dam_force)
if(!M)
return
M.adjustOxyLoss(round(dam_force/2))
M.updatehealth()
target.visible_message("<span class='danger'>[chassis] destroys [target] in an unholy fury!</span>", \
"<span class='userdanger'>[chassis] destroys you in an unholy fury!</span>")
log_combat(source, M, "attacked", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
else
target.visible_message("<span class='danger'>[chassis] destroys [target] in an unholy fury!</span>", \
"<span class='userdanger'>[chassis] destroys you in an unholy fury!</span>")
else if(source.a_intent == INTENT_DISARM)
if(real_clamp)
var/mob/living/carbon/C = target
var/play_sound = FALSE
var/limbs_gone = ""
var/obj/item/bodypart/affected = C.get_bodypart(BODY_ZONE_L_ARM)
if(affected != null)
affected.dismember(damtype)
play_sound = TRUE
limbs_gone = ", [affected]"
affected = C.get_bodypart(BODY_ZONE_R_ARM)
if(affected != null)
affected.dismember(damtype)
play_sound = TRUE
limbs_gone = "[limbs_gone], [affected]"
if(play_sound)
playsound(src, get_dismember_sound(), 80, TRUE)
target.visible_message("<span class='danger'>[chassis] rips [target]'s arms off!</span>", \
"<span class='userdanger'>[chassis] rips your arms off!</span>")
log_combat(source, M, "dismembered of[limbs_gone],", "[name]", "(INTENT: [uppertext(source.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
else
target.visible_message("<span class='danger'>[chassis] rips [target]'s arms off!</span>", \
"<span class='userdanger'>[chassis] rips your arms off!</span>")
else
step_away(M,chassis)
target.visible_message("<span class='danger'>[chassis] tosses [target] like a piece of paper!</span>", \
"<span class='userdanger'>[chassis] tosses you like a piece of paper!</span>")
return ..()
/obj/item/mecha_parts/mecha_equipment/extinguisher
name = "exosuit extinguisher"
desc = "Equipment for engineering exosuits. A rapid-firing high capacity fire extinguisher."
icon_state = "mecha_exting"
equip_cooldown = 5
energy_drain = 0
range = MECHA_MELEE|MECHA_RANGED
mech_flags = EXOSUIT_MODULE_WORKING
/obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize()
. = ..()
create_reagents(1000)
reagents.add_reagent(/datum/reagent/water, 1000)
/obj/item/mecha_parts/mecha_equipment/extinguisher/action(mob/source, atom/target, params) //copypasted from extinguisher. TODO: Rewrite from scratch.//Still todo
if(!action_checks(target) || get_dist(chassis, target)>3)
return
if(istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1)
var/obj/structure/reagent_dispensers/watertank/WT = target
WT.reagents.trans_to(src, 1000)
to_chat(chassis.occupants,"<span class='notice'>Extinguisher refilled.</span>")
playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6)
else
if(reagents.total_volume > 0)
playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3)
var/direction = get_dir(chassis,target)
var/turf/T = get_turf(target)
var/turf/T1 = get_step(T,turn(direction, 90))
var/turf/T2 = get_step(T,turn(direction, -90))
var/list/the_targets = list(T,T1,T2)
spawn(0)
for(var/a=0, a<5, a++)
var/obj/effect/particle_effect/water/W = new /obj/effect/particle_effect/water(get_turf(chassis))
if(!W)
return
var/turf/my_target = pick(the_targets)
var/datum/reagents/R = new/datum/reagents(5)
W.reagents = R
R.my_atom = W
reagents.trans_to(W,1)
for(var/b=0, b<4, b++)
if(!W)
return
step_towards(W,my_target)
if(!W)
return
var/turf/W_turf = get_turf(W)
W.reagents.reaction(W_turf)
for(var/atom/atm in W_turf)
W.reagents.reaction(atm)
if(W.loc == my_target)
break
sleep(2)
return 1
/obj/item/mecha_parts/mecha_equipment/extinguisher/get_equip_info()
return "[..()] \[[src.reagents.total_volume]\]"
/obj/item/mecha_parts/mecha_equipment/extinguisher/can_attach(obj/vehicle/sealed/mecha/working/M as obj)
if(..())
if(istype(M))
return 1
return 0
/obj/item/mecha_parts/mecha_equipment/rcd
name = "mounted RCD"
desc = "An exosuit-mounted Rapid Construction Device."
icon_state = "mecha_rcd"
equip_cooldown = 10
energy_drain = 250
range = MECHA_MELEE|MECHA_RANGED
item_flags = NO_MAT_REDEMPTION
var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock.
/obj/item/mecha_parts/mecha_equipment/rcd/Initialize()
. = ..()
GLOB.rcd_list += src
/obj/item/mecha_parts/mecha_equipment/rcd/Destroy()
GLOB.rcd_list -= src
return ..()
/obj/item/mecha_parts/mecha_equipment/rcd/action(mob/source, atom/target, params)
if(istype(target, /turf/open/space/transit))//>implying these are ever made -Sieve
return
if(!isturf(target) && !istype(target, /obj/machinery/door/airlock))
target = get_turf(target)
if(!action_checks(target) || get_dist(chassis, target)>3)
return
playsound(chassis, 'sound/machines/click.ogg', 50, TRUE)
switch(mode)
if(0)
if(iswallturf(target))
var/turf/closed/wall/W = target
to_chat(source, "[icon2html(src, source)]<span class='notice'>Deconstructing [W]...</span>")
if(do_after_cooldown(W, source))
chassis.spark_system.start()
W.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
playsound(W, 'sound/items/deconstruct.ogg', 50, TRUE)
else if(isfloorturf(target))
var/turf/open/floor/F = target
to_chat(source, "[icon2html(src, source)]<span class='notice'>Deconstructing [F]...</span>")
if(do_after_cooldown(target, source))
chassis.spark_system.start()
F.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
playsound(F, 'sound/items/deconstruct.ogg', 50, TRUE)
else if (istype(target, /obj/machinery/door/airlock))
to_chat(source, "[icon2html(src, source)]<span class='notice'>Deconstructing [target]...</span>")
if(do_after_cooldown(target, source))
chassis.spark_system.start()
qdel(target)
playsound(target, 'sound/items/deconstruct.ogg', 50, TRUE)
if(1)
if(isspaceturf(target))
var/turf/open/space/S = target
to_chat(source, "[icon2html(src, source)]<span class='notice'>Building Floor...</span>")
if(do_after_cooldown(S, source))
S.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
playsound(S, 'sound/items/deconstruct.ogg', 50, TRUE)
chassis.spark_system.start()
else if(isfloorturf(target))
var/turf/open/floor/F = target
to_chat(source, "[icon2html(src, source)]<span class='notice'>Building Wall...</span>")
if(do_after_cooldown(F, source))
F.PlaceOnTop(/turf/closed/wall)
playsound(F, 'sound/items/deconstruct.ogg', 50, TRUE)
chassis.spark_system.start()
if(2)
if(isfloorturf(target))
to_chat(source, "[icon2html(src, source)]<span class='notice'>Building Airlock...</span>")
if(do_after_cooldown(target, source))
chassis.spark_system.start()
var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target)
T.autoclose = TRUE
playsound(target, 'sound/items/deconstruct.ogg', 50, TRUE)
playsound(target, 'sound/effects/sparks2.ogg', 50, TRUE)
return ..()
/obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list)
..()
if(href_list["mode"])
mode = text2num(href_list["mode"])
switch(mode)
if(0)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>Switched RCD to Deconstruct.</span>")
energy_drain = initial(energy_drain)
if(1)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>Switched RCD to Construct.</span>")
energy_drain = 2*initial(energy_drain)
if(2)
to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)]<span class='notice'>Switched RCD to Construct Airlock.</span>")
energy_drain = 2*initial(energy_drain)
return
/obj/item/mecha_parts/mecha_equipment/rcd/get_equip_info()
return "[..()] \[<a href='?src=[REF(src)];mode=0'>D</a>|<a href='?src=[REF(src)];mode=1'>C</a>|<a href='?src=[REF(src)];mode=2'>A</a>\]"
//Dunno where else to put this so shrug
/obj/item/mecha_parts/mecha_equipment/ripleyupgrade
name = "Ripley MK-II Conversion Kit"
desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I mecha, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied."
icon_state = "tesla"
mech_flags = EXOSUIT_MODULE_RIPLEY
/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/vehicle/sealed/mecha/working/ripley/M)
if(M.type != /obj/vehicle/sealed/mecha/working/ripley)
to_chat(loc, "<span class='warning'>This conversion kit can only be applied to APLU MK-I models.</span>")
return FALSE
if(M.cargo.len)
to_chat(loc, "<span class='warning'>[M]'s cargo hold must be empty before this conversion kit can be applied.</span>")
return FALSE
if(!(M.mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)) //non-removable upgrade, so lets make sure the pilot or owner has their say.
to_chat(loc, "<span class='warning'>[M] must have maintenance protocols active in order to allow this conversion kit.</span>")
return FALSE
if(LAZYLEN(M.occupants)) //We're actualy making a new mech and swapping things over, it might get weird if players are involved
to_chat(loc, "<span class='warning'>[M] must be unoccupied before this conversion kit can be applied.</span>")
return FALSE
if(!M.cell) //Turns out things break if the cell is missing
to_chat(loc, "<span class='warning'>The conversion process requires a cell installed.</span>")
return FALSE
return TRUE
/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/vehicle/sealed/mecha/M)
var/obj/vehicle/sealed/mecha/working/ripley/mkii/N = new /obj/vehicle/sealed/mecha/working/ripley/mkii(get_turf(M),1)
if(!N)
return
QDEL_NULL(N.cell)
if (M.cell)
N.cell = M.cell
M.cell.forceMove(N)
M.cell = null
QDEL_NULL(N.scanmod)
if (M.scanmod)
N.scanmod = M.scanmod
M.scanmod.forceMove(N)
M.scanmod = null
QDEL_NULL(N.capacitor)
if (M.capacitor)
N.capacitor = M.capacitor
M.capacitor.forceMove(N)
M.capacitor = null
N.update_part_values()
for(var/obj/item/mecha_parts/E in M.contents)
if(istype(E, /obj/item/mecha_parts/concealed_weapon_bay)) //why is the bay not just a variable change who did this
E.forceMove(N)
for(var/obj/item/mecha_parts/mecha_equipment/E in M.equipment) //Move the equipment over...
E.detach(M)
E.attach(N)
N.dna_lock = M.dna_lock
N.mecha_flags = M.mecha_flags
N.strafe = M.strafe
N.obj_integrity = M.obj_integrity //This is not a repair tool
if (M.name != "\improper APLU MK-I \"Ripley\"")
N.name = M.name
M.wreckage = 0
qdel(M)
playsound(get_turf(N),'sound/items/ratchet.ogg',50,TRUE)
return
@@ -0,0 +1,94 @@
/obj/item/mecha_ammo
name = "generic ammo box"
desc = "A box of ammo for an unknown weapon."
w_class = WEIGHT_CLASS_BULKY
icon = 'icons/mecha/mecha_ammo.dmi'
icon_state = "empty"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
var/rounds = 0
var/round_term = "round"
var/direct_load //For weapons where we re-load the weapon itself rather than adding to the ammo storage.
var/load_audio = 'sound/weapons/bulletinsert.ogg'
var/ammo_type
/obj/item/mecha_ammo/update_name()
if(!rounds)
name = "empty ammo box"
desc = "An exosuit ammuniton box that has since been emptied. Please recycle."
icon_state = "empty"
/obj/item/mecha_ammo/attack_self(mob/user)
..()
if(rounds)
to_chat(user, "<span class='warning'>You cannot flatten the ammo box until it's empty!</span>")
return
to_chat(user, "<span class='notice'>You fold [src] flat.</span>")
var/I = new /obj/item/stack/sheet/metal(user.loc)
qdel(src)
user.put_in_hands(I)
/obj/item/mecha_ammo/examine(mob/user)
. = ..()
if(rounds)
. += "There [rounds > 1?"are":"is"] [rounds] [round_term][rounds > 1?"s":""] left."
/obj/item/mecha_ammo/incendiary
name = "incendiary ammo"
desc = "A box of incendiary ammunition for use with exosuit weapons."
icon_state = "incendiary"
rounds = 24
ammo_type = "incendiary"
/obj/item/mecha_ammo/scattershot
name = "scattershot ammo"
desc = "A box of scaled-up buckshot, for use in exosuit shotguns."
icon_state = "scattershot"
rounds = 40
ammo_type = "scattershot"
/obj/item/mecha_ammo/lmg
name = "machine gun ammo"
desc = "A box of linked ammunition, designed for the Ultra AC 2 exosuit weapon."
icon_state = "lmg"
rounds = 300
ammo_type = "lmg"
/obj/item/mecha_ammo/missiles_br
name = "breaching missiles"
desc = "A box of large missiles, ready for loading into a BRM-6 exosuit missile rack."
icon_state = "missile_br"
rounds = 6
round_term = "missile"
direct_load = TRUE
load_audio = 'sound/weapons/bulletinsert.ogg'
ammo_type = "missiles_br"
/obj/item/mecha_ammo/missiles_he
name = "anti-armor missiles"
desc = "A box of large missiles, ready for loading into an SRM-8 exosuit missile rack."
icon_state = "missile_he"
rounds = 8
round_term = "missile"
direct_load = TRUE
load_audio = 'sound/weapons/bulletinsert.ogg'
ammo_type = "missiles_he"
/obj/item/mecha_ammo/flashbang
name = "launchable flashbangs"
desc = "A box of smooth flashbangs, for use with a large exosuit launcher. Cannot be primed by hand."
icon_state = "flashbang"
rounds = 6
round_term = "grenade"
ammo_type = "flashbang"
/obj/item/mecha_ammo/clusterbang
name = "launchable flashbang clusters"
desc = "A box of clustered flashbangs, for use with a specialized exosuit cluster launcher. Cannot be primed by hand."
icon_state = "clusterbang"
rounds = 3
round_term = "cluster"
direct_load = TRUE
ammo_type = "clusterbang"
@@ -0,0 +1,524 @@
/obj/item/mecha_parts/mecha_equipment/weapon
name = "mecha weapon"
range = MECHA_RANGED
destroy_sound = 'sound/mecha/weapdestr.ogg'
var/projectile
var/fire_sound
var/projectiles_per_shot = 1
var/variance = 0
var/randomspread = FALSE //use random spread for machineguns, instead of shotgun scatter
var/projectile_delay = 0
var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the weapon is fired.
var/kickback = TRUE //Will using this weapon in no grav push mecha back.
mech_flags = EXOSUIT_MODULE_COMBAT
/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/vehicle/sealed/mecha/M)
if(!..())
return FALSE
if(istype(M, /obj/vehicle/sealed/mecha/combat))
return TRUE
if((locate(/obj/item/mecha_parts/concealed_weapon_bay) in M.contents) && !(locate(/obj/item/mecha_parts/mecha_equipment/weapon) in M.equipment))
return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/action(mob/source, atom/target, params)
if(!action_checks(target))
return FALSE
var/newtonian_target = turn(chassis.dir,180)
. = ..()//start the cooldown early because of sleeps
for(var/i in 1 to projectiles_per_shot)
if(energy_drain && !chassis.has_charge(energy_drain))//in case we run out of energy mid-burst, such as emp
break
var/spread = 0
if(variance)
if(randomspread)
spread = round((rand() - 0.5) * variance)
else
spread = round((i / projectiles_per_shot - 0.5) * variance)
var/obj/item/projectile/A = new projectile(get_turf(src))
A.preparePixelProjectile(target, source, params, spread)
A.fire()
if(!A.suppressed && firing_effect_type)
new firing_effect_type(get_turf(src), chassis.dir)
playsound(chassis, fire_sound, 50, TRUE)
sleep(max(0, projectile_delay))
if(kickback)
chassis.newtonian_move(newtonian_target)
chassis.log_message("Fired from [src.name], targeting [target].", LOG_MECHA)
return ..()
//Base energy weapon type
/obj/item/mecha_parts/mecha_equipment/weapon/energy
name = "general energy weapon"
firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/energy
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
equip_cooldown = 8
name = "\improper CH-PS \"Immolator\" laser"
desc = "A weapon for combat exosuits. Shoots basic lasers."
icon_state = "mecha_laser"
energy_drain = 30
projectile = /obj/item/projectile/beam/laser
fire_sound = 'sound/weapons/laser.ogg'
harmful = TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/disabler
equip_cooldown = 8
name = "\improper CH-DS \"Peacemaker\" disabler"
desc = "A weapon for combat exosuits. Shoots basic disablers."
icon_state = "mecha_disabler"
energy_drain = 30
projectile = /obj/item/projectile/beam/disabler
fire_sound = 'sound/weapons/taser2.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
equip_cooldown = 15
name = "\improper CH-LC \"Solaris\" laser cannon"
desc = "A weapon for combat exosuits. Shoots heavy lasers."
icon_state = "mecha_laser"
energy_drain = 60
projectile = /obj/item/projectile/beam/laser/heavylaser
fire_sound = 'sound/weapons/lasercannonfire.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion
equip_cooldown = 20
name = "\improper MKIV ion heavy cannon"
desc = "A weapon for combat exosuits. Shoots technology-disabling ion beams. Don't catch yourself in the blast!"
icon_state = "mecha_ion"
energy_drain = 120
projectile = /obj/item/projectile/ion
fire_sound = 'sound/weapons/laser.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla
equip_cooldown = 35
name = "\improper MKI Tesla Cannon"
desc = "A weapon for combat exosuits. Fires bolts of electricity similar to the experimental tesla engine."
icon_state = "mecha_ion"
energy_drain = 500
projectile = /obj/item/projectile/energy/tesla/cannon
fire_sound = 'sound/magic/lightningbolt.ogg'
harmful = TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse
equip_cooldown = 30
name = "eZ-13 MK2 heavy pulse rifle"
desc = "A weapon for combat exosuits. Shoots powerful destructive blasts capable of demolishing obstacles."
icon_state = "mecha_pulse"
energy_drain = 120
projectile = /obj/item/projectile/beam/pulse/heavy
fire_sound = 'sound/weapons/marauder.ogg'
harmful = TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma
equip_cooldown = 10
name = "217-D Heavy Plasma Cutter"
desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles."
icon_state = "mecha_plasmacutter"
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
energy_drain = 30
projectile = /obj/item/projectile/plasma/adv/mech
fire_sound = 'sound/weapons/plasma_cutter.ogg'
harmful = TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/vehicle/sealed/mecha/M)
if(..()) //combat mech
return TRUE
else if(LAZYLEN(M.equipment) < M.max_equip)
return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
name = "\improper PBT \"Pacifier\" mounted taser"
desc = "A weapon for combat exosuits. Shoots non-lethal stunning electrodes."
icon_state = "mecha_taser"
energy_drain = 20
equip_cooldown = 8
projectile = /obj/item/projectile/energy/electrode
fire_sound = 'sound/weapons/taser.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/honker
name = "\improper HoNkER BlAsT 5000"
desc = "Equipment for clown exosuits. Spreads fun and joy to everyone around. Honk!"
icon_state = "mecha_honker"
energy_drain = 200
equip_cooldown = 150
range = MECHA_MELEE|MECHA_RANGED
kickback = FALSE
mech_flags = EXOSUIT_MODULE_HONK
/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/vehicle/sealed/mecha/mecha)
. = ..()
if(!.)
return
if(!istype(mecha, /obj/vehicle/sealed/mecha/combat/honker))
return FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(mob/source, atom/target, params)
if(!action_checks(target))
return
playsound(chassis, 'sound/items/airhorn.ogg', 100, TRUE)
to_chat(source, "[icon2html(src, source)]<font color='red' size='5'>HONK</font>")
for(var/mob/living/carbon/M in ohearers(6, chassis))
if(!M.can_hear())
continue
var/turf/turf_check = get_turf(M)
if(isspaceturf(turf_check) && !turf_check.Adjacent(src)) //in space nobody can hear you honk.
continue
to_chat(M, "<font color='red' size='7'>HONK</font>")
M.SetSleeping(0)
M.stuttering += 20
var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
if(ears)
ears.adjustEarDamage(0, 30)
M.Paralyze(60)
if(prob(30))
M.Stun(200)
M.Unconscious(80)
else
M.Jitter(500)
log_message("Honked from [src.name]. HONK!", LOG_MECHA)
var/turf/T = get_turf(src)
message_admins("[ADMIN_LOOKUPFLW(source)] used a Mecha Honker in [ADMIN_VERBOSEJMP(T)]")
log_game("[key_name(source)] used a Mecha Honker in [AREACOORD(T)]")
return ..()
//Base ballistic weapon type
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic
name = "general ballistic weapon"
fire_sound = 'sound/weapons/shot.ogg'
var/projectiles
var/projectiles_cache //ammo to be loaded in, if possible.
var/projectiles_cache_max
var/projectile_energy_cost
var/disabledreload //For weapons with no cache (like the rockets) which are reloaded by hand
var/ammo_type
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action_checks(target)
if(!..())
return FALSE
if(projectiles <= 0)
return FALSE
return TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info()
return "[..()] \[[src.projectiles][projectiles_cache_max &&!projectile_energy_cost?"/[projectiles_cache]":""]\][!disabledreload &&(src.projectiles < initial(src.projectiles))?" - <a href='?src=[REF(src)];rearm=1'>Rearm</a>":null]"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/rearm()
if(projectiles < initial(projectiles))
var/projectiles_to_add = initial(projectiles) - projectiles
if(projectile_energy_cost)
while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add)
projectiles++
projectiles_to_add--
chassis.use_power(projectile_energy_cost)
else
if(!projectiles_cache)
return FALSE
if(projectiles_to_add <= projectiles_cache)
projectiles = projectiles + projectiles_to_add
projectiles_cache = projectiles_cache - projectiles_to_add
else
projectiles = projectiles + projectiles_cache
projectiles_cache = 0
send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
log_message("Rearmed [src.name].", LOG_MECHA)
return TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/needs_rearm()
. = !(projectiles > 0)
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list)
..()
if (href_list["rearm"])
src.rearm()
return
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(mob/source, atom/target, params)
if(..())
projectiles -= projectiles_per_shot
send_byjax(chassis.occupants,"exosuit.browser","[REF(src)]",src.get_equip_info())
return ..()
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine
name = "\improper FNX-99 \"Hades\" Carbine"
desc = "A weapon for combat exosuits. Shoots incendiary bullets."
icon_state = "mecha_carbine"
equip_cooldown = 10
projectile = /obj/item/projectile/bullet/incendiary/fnx99
projectiles = 24
projectiles_cache = 24
projectiles_cache_max = 96
harmful = TRUE
ammo_type = "incendiary"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced
name = "\improper S.H.H. \"Quietus\" Carbine"
desc = "A weapon for combat exosuits. A mime invention, field tests have shown that targets cannot even scream before going down."
fire_sound = 'sound/weapons/Gunshot_silenced.ogg'
icon_state = "mecha_mime"
equip_cooldown = 30
projectile = /obj/item/projectile/bullet/mime
projectiles = 6
projectile_energy_cost = 50
harmful = TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
name = "\improper LBX AC 10 \"Scattershot\""
desc = "A weapon for combat exosuits. Shoots a spread of pellets."
icon_state = "mecha_scatter"
equip_cooldown = 20
projectile = /obj/item/projectile/bullet/scattershot
projectiles = 40
projectiles_cache = 40
projectiles_cache_max = 160
projectiles_per_shot = 4
variance = 25
harmful = TRUE
ammo_type = "scattershot"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/seedscatter
name = "\improper Melon Seed \"Scattershot\""
desc = "A weapon for combat exosuits. Shoots a spread of pellets, shaped as seed."
fire_sound = 'sound/weapons/gunshotshotgunshot.ogg'
icon_state = "mecha_scatter"
equip_cooldown = 20
projectile = /obj/item/projectile/bullet/seed
projectiles = 20
projectiles_cache = 20
projectiles_cache_max = 160
projectiles_per_shot = 10
variance = 25
harmful = TRUE
ammo_type = "scattershot"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg
name = "\improper Ultra AC 2"
desc = "A weapon for combat exosuits. Shoots a rapid, three shot burst."
icon_state = "mecha_uac2"
equip_cooldown = 10
projectile = /obj/item/projectile/bullet/lmg
projectiles = 300
projectiles_cache = 300
projectiles_cache_max = 1200
projectiles_per_shot = 3
variance = 6
randomspread = 1
projectile_delay = 2
harmful = TRUE
ammo_type = "lmg"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack
name = "\improper SRM-8 missile rack"
desc = "A weapon for combat exosuits. Launches light explosive missiles."
icon_state = "mecha_missilerack"
projectile = /obj/item/projectile/bullet/a84mm_he
fire_sound = 'sound/weapons/rocketlaunch.ogg'
projectiles = 8
projectiles_cache = 0
projectiles_cache_max = 0
disabledreload = TRUE
equip_cooldown = 60
harmful = TRUE
ammo_type = "missiles_he"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/spacecops
projectiles = 420
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/breaching
name = "\improper BRM-6 missile rack"
desc = "A weapon for combat exosuits. Launches high-explosive breaching missiles with a safety fuze designed to explode only when striking a sturdy target."
icon_state = "mecha_missilerack_six"
projectile = /obj/item/projectile/bullet/a84mm_br
fire_sound = 'sound/weapons/rocketlaunch.ogg'
projectiles = 6
projectiles_cache = 0
projectiles_cache_max = 0
disabledreload = TRUE
equip_cooldown = 60
harmful = TRUE
ammo_type = "missiles_br"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher
var/missile_speed = 2
var/missile_range = 30
var/diags_first = FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/action(mob/source, atom/target, params)
if(!action_checks(target))
return
var/obj/O = new projectile(chassis.loc)
playsound(chassis, fire_sound, 50, TRUE)
log_message("Launched a [O.name] from [name], targeting [target].", LOG_MECHA)
projectiles--
proj_init(O, source)
O.throw_at(target, missile_range, missile_speed, source, FALSE, diagonals_first = diags_first)
return TRUE
//used for projectile initilisation (priming flashbang) and additional logging
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/proc/proj_init(obj/O, mob/user)
return
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang
name = "\improper SGL-6 grenade launcher"
desc = "A weapon for combat exosuits. Launches primed flashbangs."
icon_state = "mecha_grenadelnchr"
projectile = /obj/item/grenade/flashbang
fire_sound = 'sound/weapons/grenadelaunch.ogg'
projectiles = 6
projectiles_cache = 6
projectiles_cache_max = 24
missile_speed = 1.5
equip_cooldown = 60
var/det_time = 20
ammo_type = "flashbang"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(obj/item/grenade/flashbang/F, mob/user)
var/turf/T = get_turf(src)
message_admins("[ADMIN_LOOKUPFLW(user)] fired a [F] in [ADMIN_VERBOSEJMP(T)]")
log_game("[key_name(user)] fired a [F] in [AREACOORD(T)]")
addtimer(CALLBACK(F, /obj/item/grenade/flashbang.proc/prime), det_time)
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze
name = "\improper SOB-3 grenade launcher"
desc = "A weapon for combat exosuits. Launches primed clusterbangs. You monster."
projectiles = 3
projectiles_cache = 0
projectiles_cache_max = 0
disabledreload = TRUE
projectile = /obj/item/grenade/clusterbuster
equip_cooldown = 90
ammo_type = "clusterbang"
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar
name = "banana mortar"
desc = "Equipment for clown exosuits. Launches banana peels."
icon_state = "mecha_bananamrtr"
projectile = /obj/item/grown/bananapeel
fire_sound = 'sound/items/bikehorn.ogg'
projectiles = 15
missile_speed = 1.5
projectile_energy_cost = 100
equip_cooldown = 20
mech_flags = EXOSUIT_MODULE_HONK
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
if(..())
if(istype(M))
return 1
return 0
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar
name = "mousetrap mortar"
desc = "Equipment for clown exosuits. Launches armed mousetraps."
icon_state = "mecha_mousetrapmrtr"
projectile = /obj/item/assembly/mousetrap/armed
fire_sound = 'sound/items/bikehorn.ogg'
projectiles = 15
missile_speed = 1.5
projectile_energy_cost = 100
equip_cooldown = 10
mech_flags = EXOSUIT_MODULE_HONK
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
if(..())
if(istype(M))
return 1
return 0
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/proj_init(obj/item/assembly/mousetrap/armed/M)
M.secured = 1
//Classic extending punching glove, but weaponised!
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove
name = "\improper Oingo Boingo Punch-face"
desc = "Equipment for clown exosuits. Delivers fun right to your face!"
icon_state = "mecha_punching_glove"
energy_drain = 250
equip_cooldown = 20
range = MECHA_MELEE|MECHA_RANGED
missile_range = 5
projectile = /obj/item/punching_glove
fire_sound = 'sound/items/bikehorn.ogg'
projectiles = 10
projectile_energy_cost = 500
harmful = TRUE
diags_first = TRUE
/// Damage done by the glove on contact. Also used to determine throw distance (damage / 5)
var/punch_damage = 35
/// TRUE - Can toggle between lethal and non-lethal || FALSE - Cannot toggle
var/can_toggle_lethal = TRUE
mech_flags = EXOSUIT_MODULE_HONK
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/vehicle/sealed/mecha/combat/honker/M)
if(..())
if(istype(M))
return 1
return 0
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/get_equip_info()
if(!chassis)
return
if(can_toggle_lethal)
return "[..()] &nbsp; <a href='?src=[REF(src)];lethalPunch=1'>[harmful?"Punch":"Pat"] mode</a>"
else
return ..()
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/Topic(href, href_list)
..()
if(href_list["lethalPunch"])
harmful = !harmful
if(harmful)
to_chat(usr, "[icon2html(src, usr)]<span class='warning'>Lethal Fisting Enabled.</span>")
else
to_chat(usr, "[icon2html(src, usr)]<span class='warning'>Lethal Fisting Disabled.</span>")
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(mob/source, atom/target, params)
. = ..()
if(.)
to_chat(usr, "[icon2html(src, usr)]<font color='red' size='5'>HONK</font>")
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/proj_init(obj/item/punching_glove/PG)
if(!istype(PG))
return
if(harmful)
PG.throwforce = punch_damage
else
PG.throwforce = 0
//has to be low sleep or it looks weird, the beam doesn't exist for very long so it's a non-issue
chassis.Beam(PG, icon_state = "chain", time = missile_range * 20, maxdistance = missile_range + 2, beam_sleep_time = 1)
/obj/item/punching_glove
name = "punching glove"
desc = "INCOMING HONKS"
throwforce = 35
icon_state = "punching_glove"
/obj/item/punching_glove/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..())
if(ismovable(hit_atom))
var/atom/movable/AM = hit_atom
AM.safe_throw_at(get_edge_target_turf(AM,get_dir(src, AM)), clamp(round(throwforce/5), 2, 20), 2) //Throws them equal to damage/5, with a min range of 2 and max range of 20
qdel(src)
+151
View File
@@ -0,0 +1,151 @@
/turf/open/floor/mech_bay_recharge_floor // Whos idea it was
name = "mech bay recharge station" // Recharging turfs
desc = "Parking a mech on this station will recharge its internal power cell."
icon = 'icons/turf/floors.dmi' // That are set in stone to check the west turf for recharge port
icon_state = "recharge_floor" // Some people just want to watch the world burn i guess
/turf/open/floor/mech_bay_recharge_floor/break_tile()
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
/turf/open/floor/mech_bay_recharge_floor/airless
icon_state = "recharge_floor_asteroid"
initial_gas_mix = AIRLESS_ATMOS
/obj/machinery/mech_bay_recharge_port
name = "mech bay power port"
desc = "This port recharges a mech's internal power cell."
density = TRUE
dir = EAST
icon = 'icons/mecha/mech_bay.dmi'
icon_state = "recharge_port"
circuit = /obj/item/circuitboard/machine/mech_recharger
var/obj/vehicle/sealed/mecha/recharging_mech
var/obj/machinery/computer/mech_bay_power_console/recharge_console
var/max_charge = 50
var/on = FALSE
var/turf/recharging_turf = null
/obj/machinery/mech_bay_recharge_port/Initialize()
. = ..()
recharging_turf = get_step(loc, dir)
/obj/machinery/mech_bay_recharge_port/Destroy()
if (recharge_console && recharge_console.recharge_port == src)
recharge_console.recharge_port = null
return ..()
/obj/machinery/mech_bay_recharge_port/setDir(new_dir)
. = ..()
recharging_turf = get_step(loc, dir)
/obj/machinery/mech_bay_recharge_port/RefreshParts()
var/MC
for(var/obj/item/stock_parts/capacitor/C in component_parts)
MC += C.rating
max_charge = MC * 25
/obj/machinery/mech_bay_recharge_port/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Base recharge rate at <b>[max_charge]J</b> per cycle.</span>"
/obj/machinery/mech_bay_recharge_port/process()
if(stat & NOPOWER || !recharge_console)
return
if(!recharging_mech)
recharging_mech = locate(/obj/vehicle/sealed/mecha) in recharging_turf
if(recharging_mech)
recharge_console.update_icon()
if(recharging_mech && recharging_mech.cell)
if(recharging_mech.cell.charge < recharging_mech.cell.maxcharge)
var/delta = min(max_charge, recharging_mech.cell.maxcharge - recharging_mech.cell.charge)
recharging_mech.give_power(delta)
use_power(delta*150)
else
recharge_console.update_icon()
if(recharging_mech.loc != recharging_turf)
recharging_mech = null
recharge_console.update_icon()
/obj/machinery/mech_bay_recharge_port/attackby(obj/item/I, mob/user, params)
if(default_deconstruction_screwdriver(user, "recharge_port-o", "recharge_port", I))
return
if(default_change_direction_wrench(user, I))
recharging_turf = get_step(loc, dir)
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/computer/mech_bay_power_console
name = "mech bay power control console"
desc = "Displays the status of mechs connected to the recharge station."
icon_screen = "recharge_comp"
icon_keyboard = "rd_key"
circuit = /obj/item/circuitboard/computer/mech_bay_power_console
light_color = LIGHT_COLOR_PINK
var/obj/machinery/mech_bay_recharge_port/recharge_port
/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "MechBayPowerConsole", name)
ui.open()
/obj/machinery/computer/mech_bay_power_console/ui_act(action, params)
if(..())
return
switch(action)
if("reconnect")
reconnect()
. = TRUE
update_icon()
/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user)
var/list/data = list()
if(recharge_port && !QDELETED(recharge_port))
data["recharge_port"] = list("mech" = null)
if(recharge_port.recharging_mech && !QDELETED(recharge_port.recharging_mech))
data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.obj_integrity, "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null, "name" = recharge_port.recharging_mech.name,)
if(recharge_port.recharging_mech.cell && !QDELETED(recharge_port.recharging_mech.cell))
data["recharge_port"]["mech"]["cell"] = list(
"charge" = recharge_port.recharging_mech.cell.charge,
"maxcharge" = recharge_port.recharging_mech.cell.maxcharge
)
return data
/obj/machinery/computer/mech_bay_power_console/proc/reconnect()
if(recharge_port)
return
recharge_port = locate(/obj/machinery/mech_bay_recharge_port) in range(1)
if(!recharge_port )
for(var/D in GLOB.cardinals)
var/turf/A = get_step(src, D)
A = get_step(A, D)
recharge_port = locate(/obj/machinery/mech_bay_recharge_port) in A
if(recharge_port)
break
if(recharge_port)
if(!recharge_port.recharge_console)
recharge_port.recharge_console = src
else
recharge_port = null
/obj/machinery/computer/mech_bay_power_console/update_overlays()
. = ..()
if(!recharge_port || !recharge_port.recharging_mech || !recharge_port.recharging_mech.cell || !(recharge_port.recharging_mech.cell.charge < recharge_port.recharging_mech.cell.maxcharge) || stat & (NOPOWER|BROKEN))
return
. += "recharge_comp_on"
/obj/machinery/computer/mech_bay_power_console/Initialize()
. = ..()
reconnect()
/obj/machinery/computer/mech_bay_power_console/Destroy()
if (recharge_port && recharge_port.recharge_console == src)
recharge_port.recharge_console = null
return ..()
@@ -0,0 +1,678 @@
/obj/machinery/mecha_part_fabricator
icon = 'icons/obj/robotics.dmi'
icon_state = "fab-idle"
name = "exosuit fabricator"
desc = "Nothing is being built."
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 20
active_power_usage = 5000
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/machine/mechfab
// processing_flags = START_PROCESSING_MANUALLY
// subsystem_type = /datum/controller/subsystem/processing/fastprocess
/// Current items in the build queue.
var/list/queue = list()
/// Whether or not the machine is building the entire queue automagically.
var/process_queue = FALSE
/// The current design datum that the machine is building.
var/datum/design/being_built
/// World time when the build will finish.
var/build_finish = 0
/// World time when the build started.
var/build_start = 0
/// Reference to all materials used in the creation of the item being_built.
var/list/build_materials
/// Part currently stored in the Exofab.
var/obj/item/stored_part
/// Coefficient for the speed of item building. Based on the installed parts.
var/time_coeff = 1
/// Coefficient for the efficiency of material usage in item building. Based on the installed parts.
var/component_coeff = 1
/// Copy of the currently synced techweb.
var/datum/techweb/specialized/autounlocking/exofab/stored_research
/// Whether the Exofab links to the ore silo on init. Special derelict or maintanance variants should set this to FALSE.
var/link_on_init = TRUE
/// Reference to a remote material inventory, such as an ore silo.
var/datum/component/remote_materials/rmat
/// A list of categories that valid MECHFAB design datums will broadly categorise themselves under.
var/list/part_sets = list(
"Cyborg",
"Ripley",
"Firefighter",
"Odysseus",
"Gygax",
"Medical-Spec Gygax",
"Durand",
"H.O.N.K",
"Phazon",
"Exosuit Equipment",
"Exosuit Ammunition",
"Cyborg Upgrade Modules",
"Cybernetics",
"Implants",
"Control Interfaces",
"Misc"
)
/obj/machinery/mecha_part_fabricator/Initialize(mapload)
stored_research = new
rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
RefreshParts() //Recalculating local material sizes if the fab isn't linked
return ..()
/obj/machinery/mecha_part_fabricator/RefreshParts()
var/T = 0
//maximum stocking amount (default 300000, 600000 at T4)
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
T += M.rating
rmat.set_local_size((200000 + (T*50000)))
//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
T = 1.15
for(var/obj/item/stock_parts/micro_laser/Ma in component_parts)
T -= Ma.rating*0.15
component_coeff = T
//building time adjustment coefficient (1 -> 0.8 -> 0.6)
T = -1
for(var/obj/item/stock_parts/manipulator/Ml in component_parts)
T += Ml.rating
time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01)
// Adjust the build time of any item currently being built.
if(being_built)
var/last_const_time = build_finish - build_start
var/new_const_time = get_construction_time_w_coeff(initial(being_built.construction_time))
var/const_time_left = build_finish - world.time
var/new_build_time = (new_const_time / last_const_time) * const_time_left
build_finish = world.time + new_build_time
update_static_data(usr)
/obj/machinery/mecha_part_fabricator/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Storing up to <b>[rmat.local_size]</b> material units.<br>Material consumption at <b>[component_coeff*100]%</b>.<br>Build time reduced by <b>[100-time_coeff*100]%</b>.</span>"
/**
* Generates an info list for a given part.
*
* Returns a list of part information.
* * D - Design datum to get information on.
* * categories - Boolean, whether or not to parse snowflake categories into the part information list.
*/
/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, categories = FALSE)
var/cost = list()
for(var/c in D.materials)
var/datum/material/M = c
cost[M.name] = get_resource_cost_w_coeff(D, M)
var/obj/built_item = D.build_path
var/list/category_override = null
var/list/sub_category = null
if(categories)
// Handle some special cases to build up sub-categories for the fab interface.
// Start with checking if this design builds a cyborg module.
if(built_item in typesof(/obj/item/borg/upgrade))
var/obj/item/borg/upgrade/U = built_item
var/module_types = initial(U.module_flags)
sub_category = list()
if(module_types)
if(module_types & BORG_MODULE_SECURITY)
sub_category += "Security"
if(module_types & BORG_MODULE_MINER)
sub_category += "Mining"
if(module_types & BORG_MODULE_JANITOR)
sub_category += "Janitor"
if(module_types & BORG_MODULE_MEDICAL)
sub_category += "Medical"
if(module_types & BORG_MODULE_ENGINEERING)
sub_category += "Engineering"
else
sub_category += "All Cyborgs"
// Else check if this design builds a piece of exosuit equipment.
else if(built_item in typesof(/obj/item/mecha_parts/mecha_equipment))
var/obj/item/mecha_parts/mecha_equipment/E = built_item
var/mech_types = initial(E.mech_flags)
sub_category = "Equipment"
if(mech_types)
category_override = list()
if(mech_types & EXOSUIT_MODULE_RIPLEY)
category_override += "Ripley"
if(mech_types & EXOSUIT_MODULE_FIREFIGHTER)
category_override += "Firefighter"
if(mech_types & EXOSUIT_MODULE_ODYSSEUS)
category_override += "Odysseus"
// if(mech_types & EXOSUIT_MODULE_CLARKE)
// category_override += "Clarke"
if(mech_types & EXOSUIT_MODULE_GYGAX_MED)
category_override += "Medical-Spec Gygax"
if(mech_types & EXOSUIT_MODULE_GYGAX)
category_override += "Gygax"
if(mech_types & EXOSUIT_MODULE_DURAND)
category_override += "Durand"
if(mech_types & EXOSUIT_MODULE_HONK)
category_override += "H.O.N.K"
if(mech_types & EXOSUIT_MODULE_PHAZON)
category_override += "Phazon"
var/list/part = list(
"name" = D.name,
"desc" = initial(built_item.desc),
"printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10,
"cost" = cost,
"id" = D.id,
"subCategory" = sub_category,
"categoryOverride" = category_override,
"searchMeta" = "UNKNOWN"//D.search_metadata
)
return part
/**
* Generates a list of resources / materials available to this Exosuit Fab
*
* Returns null if there is no material container available.
* List format is list(material_name = list(amount = ..., ref = ..., etc.))
*/
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
var/datum/component/material_container/materials = rmat.mat_container
var/list/material_data = list()
if(materials)
for(var/mat_id in materials.materials)
var/datum/material/M = mat_id
var/list/material_info = list()
var/amount = materials.materials[mat_id]
material_info = list(
"name" = M.name,
"ref" = REF(M),
"amount" = amount,
"sheets" = round(amount / MINERAL_MATERIAL_AMOUNT),
"removable" = amount >= MINERAL_MATERIAL_AMOUNT
)
material_data += list(material_info)
return material_data
return null
/**
* Intended to be called when an item starts printing.
*
* Adds the overlay to show the fab working and sets active power usage settings.
*/
/obj/machinery/mecha_part_fabricator/proc/on_start_printing()
add_overlay("fab-active")
use_power = ACTIVE_POWER_USE
/**
* Intended to be called when the exofab has stopped working and is no longer printing items.
*
* Removes the overlay to show the fab working and sets idle power usage settings. Additionally resets the description and turns off queue processing.
*/
/obj/machinery/mecha_part_fabricator/proc/on_finish_printing()
cut_overlay("fab-active")
use_power = IDLE_POWER_USE
desc = initial(desc)
process_queue = FALSE
/**
* Calculates resource/material costs for printing an item based on the machine's resource coefficient.
*
* Returns a list of k,v resources with their amounts.
* * D - Design datum to calculate the modified resource cost of.
*/
/obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D)
var/list/resources = list()
for(var/R in D.materials)
var/datum/material/M = R
resources[M] = get_resource_cost_w_coeff(D, M)
return resources
/**
* Checks if the Exofab has enough resources to print a given item.
*
* Returns FALSE if the design has no reagents used in its construction (?) or if there are insufficient resources.
* Returns TRUE if there are sufficient resources to print the item.
* * D - Design datum to calculate the modified resource cost of.
*/
/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D)
if(length(D.reagents_list)) // No reagents storage - no reagent designs.
return FALSE
var/datum/component/material_container/materials = rmat.mat_container
if(materials.has_materials(get_resources_w_coeff(D)))
return TRUE
return FALSE
/**
* Attempts to build the next item in the build queue.
*
* Returns FALSE if either there are no more parts to build or the next part is not buildable.
* Returns TRUE if the next part has started building.
* * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build.
*/
/obj/machinery/mecha_part_fabricator/proc/build_next_in_queue(verbose = TRUE)
if(!length(queue))
return FALSE
var/datum/design/D = queue[1]
if(build_part(D, verbose))
remove_from_queue(1)
return TRUE
return FALSE
/**
* Starts the build process for a given design datum.
*
* Returns FALSE if the procedure fails. Returns TRUE when being_built is set.
* Uses materials.
* * D - Design datum to attempt to print.
* * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build.
*/
/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D, verbose = TRUE)
if(!D)
return FALSE
var/datum/component/material_container/materials = rmat.mat_container
if (!materials)
if(verbose)
say("No access to material storage, please contact the quartermaster.")
return FALSE
if (rmat.on_hold())
if(verbose)
say("Mineral access is on hold, please contact the quartermaster.")
return FALSE
if(!check_resources(D))
if(verbose)
say("Not enough resources. Processing stopped.")
return FALSE
build_materials = get_resources_w_coeff(D)
materials.use_materials(build_materials)
being_built = D
build_finish = world.time + get_construction_time_w_coeff(initial(D.construction_time))
build_start = world.time
desc = "It's building \a [D.name]."
rmat.silo_log(src, "built", -1, "[D.name]", build_materials)
return TRUE
/obj/machinery/mecha_part_fabricator/process()
// If there's a stored part to dispense due to an obstruction, try to dispense it.
if(stored_part)
var/turf/exit = get_step(src,(dir))
if(exit.density)
return TRUE
say("Obstruction cleared. \The [stored_part] is complete.")
stored_part.forceMove(exit)
stored_part = null
// If there's nothing being built, try to build something
if(!being_built)
// If we're not processing the queue anymore or there's nothing to build, end processing.
if(!process_queue || !build_next_in_queue())
on_finish_printing()
STOP_PROCESSING(SSfastprocess, src)
//end_processing()
return TRUE
on_start_printing()
// If there's an item being built, check if it is complete.
if(being_built && (build_finish < world.time))
// Then attempt to dispense it and if appropriate build the next item.
dispense_built_part(being_built)
if(process_queue)
build_next_in_queue(FALSE)
return TRUE
/**
* Dispenses a part to the tile infront of the Exosuit Fab.
*
* Returns FALSE is the machine cannot dispense the part on the appropriate turf.
* Return TRUE if the part was successfully dispensed.
* * D - Design datum to attempt to dispense.
*/
/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/D)
var/obj/item/I = new D.build_path(src)
// I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this.
I.set_custom_materials(build_materials)
being_built = null
var/turf/exit = get_step(src,(dir))
if(exit.density)
say("Error! Part outlet is obstructed.")
desc = "It's trying to dispense \a [D.name], but the part outlet is obstructed."
stored_part = I
return FALSE
say("\The [I] is complete.")
I.forceMove(exit)
return TRUE
/**
* Adds a list of datum designs to the build queue.
*
* Will only add designs that are in this machine's stored techweb.
* Does final checks for datum IDs and makes sure this machine can build the designs.
* * part_list - List of datum design ids for designs to add to the queue.
*/
/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(list/part_list)
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if((D.build_type & MECHFAB) && (D.id in part_list))
add_to_queue(D)
/**
* Adds a datum design to the build queue.
*
* Returns TRUE if successful and FALSE if the design was not added to the queue.
* * D - Datum design to add to the queue.
*/
/obj/machinery/mecha_part_fabricator/proc/add_to_queue(datum/design/D)
if(!istype(queue))
queue = list()
if(D)
queue[++queue.len] = D
return TRUE
return FALSE
/**
* Removes datum design from the build queue based on index.
*
* Returns TRUE if successful and FALSE if a design was not removed from the queue.
* * index - Index in the build queue of the element to remove.
*/
/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index)
if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>length(queue)))
return FALSE
queue.Cut(index,++index)
return TRUE
/**
* Generates a list of parts formatted for tgui based on the current build queue.
*
* Returns a formatted list of lists containing formatted part information for every part in the build queue.
*/
/obj/machinery/mecha_part_fabricator/proc/list_queue()
if(!istype(queue) || !length(queue))
return null
var/list/queued_parts = list()
for(var/datum/design/D in queue)
var/list/part = output_part_info(D)
queued_parts += list(part)
return queued_parts
/**
* Syncs machine with R&D servers.
*
* Requires an R&D Console visible within 7 tiles. Copies techweb research. Updates tgui's state data.
*/
/obj/machinery/mecha_part_fabricator/proc/sync()
for(var/obj/machinery/computer/rdconsole/RDC in orange(7,src))
RDC.stored_research.copy_research_to(stored_research)
update_static_data(usr)
say("Successfully synchronized with R&D server.")
return
say("Unable to connect to local R&D server.")
return
/**
* Calculates the coefficient-modified resource cost of a single material component of a design's recipe.
*
* Returns coefficient-modified resource cost for the given material component.
* * D - Design datum to pull the resource cost from.
* * resource - Material datum reference to the resource to calculate the cost of.
* * roundto - Rounding value for round() proc
*/
/obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(datum/design/D, var/datum/material/resource, roundto = 1)
return round(D.materials[resource]*component_coeff, roundto)
/**
* Calculates the coefficient-modified build time of a design.
*
* Returns coefficient-modified build time of a given design.
* * D - Design datum to calculate the modified build time of.
* * roundto - Rounding value for round() proc
*/
/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(construction_time, roundto = 1) //aran
return round(construction_time*time_coeff, roundto)
/obj/machinery/mecha_part_fabricator/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/sheetmaterials)
)
/obj/machinery/mecha_part_fabricator/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ExosuitFabricator")
ui.open()
/obj/machinery/mecha_part_fabricator/ui_static_data(mob/user)
var/list/data = list()
var/list/final_sets = list()
var/list/buildable_parts = list()
for(var/part_set in part_sets)
final_sets += part_set
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
// This is for us.
var/list/part = output_part_info(D, TRUE)
if(part["category_override"])
for(var/cat in part["category_override"])
buildable_parts[cat] += list(part)
if(!(cat in part_sets))
final_sets += cat
continue
for(var/cat in part_sets)
// Find all matching categories.
if(!(cat in D.category))
continue
buildable_parts[cat] += list(part)
data["partSets"] = final_sets
data["buildableParts"] = buildable_parts
return data
/obj/machinery/mecha_part_fabricator/ui_data(mob/user)
var/list/data = list()
data["materials"] = output_available_resources()
if(being_built)
var/list/part = list(
"name" = being_built.name,
"duration" = build_finish - world.time,
"printTime" = get_construction_time_w_coeff(initial(being_built.construction_time))
)
data["buildingPart"] = part
else
data["buildingPart"] = null
data["queue"] = list_queue()
if(stored_part)
data["storedPart"] = stored_part.name
else
data["storedPart"] = null
data["isProcessingQueue"] = process_queue
return data
/obj/machinery/mecha_part_fabricator/ui_act(action, var/list/params)
if(..())
return TRUE
. = TRUE
add_fingerprint(usr)
usr.set_machine(src)
switch(action)
if("sync_rnd")
// Sync with R&D Servers
sync()
return
if("add_queue_set")
// Add all parts of a set to queue
var/part_list = params["part_list"]
add_part_set_to_queue(part_list)
return
if("add_queue_part")
// Add a specific part to queue
var/T = params["id"]
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if((D.build_type & MECHFAB) && (D.id == T))
add_to_queue(D)
break
return
if("del_queue_part")
// Delete a specific from from the queue
var/index = text2num(params["index"])
remove_from_queue(index)
return
if("clear_queue")
// Delete everything from queue
queue.Cut()
return
if("build_queue")
// Build everything in queue
if(process_queue)
return
process_queue = TRUE
if(!being_built)
START_PROCESSING(SSfastprocess, src)
//begin_processing()
return
if("stop_queue")
// Pause queue building. Also known as stop.
process_queue = FALSE
return
if("build_part")
// Build a single part
if(being_built || process_queue)
return
var/id = params["id"]
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if(!(D.build_type & MECHFAB) || !(D.id == id))
return
if(build_part(D))
on_start_printing()
START_PROCESSING(SSfastprocess, src)
//begin_processing() teege has this as a helper proc. please port it!
return
if("move_queue_part")
// Moves a part up or down in the queue.
var/index = text2num(params["index"])
var/new_index = index + text2num(params["newindex"])
if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index))
if(ISINRANGE(new_index,1,length(queue)))
queue.Swap(index,new_index)
return
if("remove_mat")
// Remove a material from the fab
var/mat_ref = params["ref"]
var/amount = text2num(params["amount"])
var/datum/material/mat = locate(mat_ref)
eject_sheets(mat, amount)
return
return FALSE
/**
* Eject material sheets.
*
* Returns the number of sheets successfully ejected.
* eject_sheet - Byond REF of the material to eject.
* eject_amt - Number of sheets to attempt to eject.
*/
/obj/machinery/mecha_part_fabricator/proc/eject_sheets(eject_sheet, eject_amt)
var/datum/component/material_container/mat_container = rmat.mat_container
if (!mat_container)
say("No access to material storage, please contact the quartermaster.")
return 0
if (rmat.on_hold())
say("Mineral access is on hold, please contact the quartermaster.")
return 0
var/count = mat_container.retrieve_sheets(text2num(eject_amt), eject_sheet, drop_location())
var/list/matlist = list()
matlist[eject_sheet] = text2num(eject_amt)
rmat.silo_log(src, "ejected", -count, "sheets", matlist)
return count
/obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted)
var/datum/material/M = id_inserted
add_overlay("fab-load-[M.name]")
addtimer(CALLBACK(src, /atom/proc/cut_overlay, "fab-load-[M.name]"), 10)
/obj/machinery/mecha_part_fabricator/screwdriver_act(mob/living/user, obj/item/I)
if(..())
return TRUE
if(being_built)
to_chat(user, "<span class='warning'>\The [src] is currently processing! Please wait until completion.</span>")
return FALSE
return default_deconstruction_screwdriver(user, "fab-o", "fab-idle", I)
/obj/machinery/mecha_part_fabricator/crowbar_act(mob/living/user, obj/item/I)
if(..())
return TRUE
if(being_built)
to_chat(user, "<span class='warning'>\The [src] is currently processing! Please wait until completion.</span>")
return FALSE
return default_deconstruction_crowbar(I)
/obj/machinery/mecha_part_fabricator/proc/is_insertion_ready(mob/user)
if(panel_open)
to_chat(user, "<span class='warning'>You can't load [src] while it's opened!</span>")
return FALSE
if(being_built)
to_chat(user, "<span class='warning'>\The [src] is currently processing! Please wait until completion.</span>")
return FALSE
return TRUE
/obj/machinery/mecha_part_fabricator/maint
link_on_init = FALSE
/obj/machinery/mecha_part_fabricator/offstation
link_on_init = FALSE
@@ -0,0 +1,117 @@
///Called when a mech melee attacks an atom
/atom/proc/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker)
return
/turf/closed/wall/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker)
mecha_attacker.do_attack_animation(src)
switch(mecha_attacker.damtype)
if(BRUTE)
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
mecha_attacker.visible_message("<span class='danger'>[mecha_attacker.name] hits [src]!</span>", \
"<span class='danger'>You hit [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if(prob(hardness + mecha_attacker.force) && mecha_attacker.force > 20)
dismantle_wall(1)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
else
add_dent(WALL_DENT_HIT)
if(BURN)
playsound(src, 'sound/items/welder.ogg', 100, TRUE)
if(TOX)
playsound(src, 'sound/effects/spray2.ogg', 100, TRUE)
return FALSE
/obj/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker)
mecha_attacker.do_attack_animation(src)
var/play_soundeffect = 0
var/mech_damtype = mecha_attacker.damtype
if(mecha_attacker.selected)
mech_damtype = mecha_attacker.selected.damtype
play_soundeffect = 1
else
switch(mecha_attacker.damtype)
if(BRUTE)
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
if(BURN)
playsound(src, 'sound/items/welder.ogg', 50, TRUE)
if(TOX)
playsound(src, 'sound/effects/spray2.ogg', 50, TRUE)
return 0
else
return 0
mecha_attacker.visible_message("<span class='danger'>[mecha_attacker.name] hits [src]!</span>", "<span class='danger'>You hit [src]!</span>", null, COMBAT_MESSAGE_RANGE)
return take_damage(mecha_attacker.force * 3, mech_damtype, MELEE, play_soundeffect, get_dir(src, mecha_attacker)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs.
/obj/structure/window/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker)
if(!can_be_reached())
return
return ..()
/mob/living/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/user)
if(user.a_intent == INTENT_HARM)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
return
mecha_attacker.do_attack_animation(src)
if(mecha_attacker.damtype == "brute")
step_away(src, mecha_attacker, 15)
switch(mecha_attacker.damtype)
if(BRUTE)
Unconscious(20)
take_overall_damage(rand(mecha_attacker.force/2, mecha_attacker.force))
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
if(BURN)
take_overall_damage(0, rand(mecha_attacker.force * 0.5, mecha_attacker.force))
playsound(src, 'sound/items/welder.ogg', 50, TRUE)
if(TOX)
mecha_attacker.mech_toxin_damage(src)
else
return
updatehealth()
visible_message("<span class='danger'>[mecha_attacker.name] hits [src]!</span>", \
"<span class='userdanger'>[mecha_attacker.name] hits you!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, mecha_attacker)
to_chat(mecha_attacker, "<span class='danger'>You hit [src]!</span>")
log_combat(user, src, "attacked", mecha_attacker, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(mecha_attacker.damtype)])")
else
step_away(src, mecha_attacker)
log_combat(user, src, "pushed", mecha_attacker)
visible_message("<span class='warning'>[mecha_attacker] pushes [src] out of the way.</span>", \
"<span class='warning'>[mecha_attacker] pushes you out of the way.</span>", "<span class='hear'>You hear aggressive shuffling!</span>", 5, list(mecha_attacker))
to_chat(mecha_attacker, "<span class='danger'>You push [src] out of the way.</span>")
/mob/living/carbon/human/mech_melee_attack(obj/vehicle/sealed/mecha/mecha_attacker, mob/user)
if(user.a_intent == INTENT_HARM)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
return
mecha_attacker.do_attack_animation(src)
if(mecha_attacker.damtype == BRUTE)
step_away(src, mecha_attacker, 15)
var/obj/item/bodypart/temp = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD))
if(temp)
var/update = 0
var/dmg = rand(mecha_attacker.force * 0.5, mecha_attacker.force)
switch(mecha_attacker.damtype)
if(BRUTE)
if(mecha_attacker.force > 35) // durand and other heavy mechas
Unconscious(20)
else if(mecha_attacker.force > 20 && !IsKnockdown()) // lightweight mechas like gygax
Knockdown(40)
update |= temp.receive_damage(dmg, 0)
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
if(BURN)
update |= temp.receive_damage(0, dmg)
playsound(src, 'sound/items/welder.ogg', 50, TRUE)
if(TOX)
mecha_attacker.mech_toxin_damage(src)
else
return
if(update)
update_damage_overlays()
updatehealth()
visible_message("<span class='danger'>[mecha_attacker.name] hits [src]!</span>", \
"<span class='userdanger'>[mecha_attacker.name] hits you!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, list(mecha_attacker))
to_chat(mecha_attacker, "<span class='danger'>You hit [src]!</span>")
log_combat(user, src, "attacked", mecha_attacker, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(mecha_attacker.damtype)])")
else
return ..()
@@ -0,0 +1,279 @@
/***************** MECHA ACTIONS *****************/
/obj/vehicle/sealed/mecha/generate_action_type()
. = ..()
if(istype(., /datum/action/vehicle/sealed/mecha))
var/datum/action/vehicle/sealed/mecha/mecha = .
mecha.chassis = src
/datum/action/vehicle/sealed/mecha
icon_icon = 'icons/mob/actions/actions_mecha.dmi'
var/obj/vehicle/sealed/mecha/chassis
/datum/action/vehicle/sealed/mecha/Destroy()
chassis = null
return ..()
/datum/action/vehicle/sealed/mecha/mech_eject
name = "Eject From Mech"
button_icon_state = "mech_eject"
/datum/action/vehicle/sealed/mecha/mech_eject/Trigger()
if(!owner)
return
if(!chassis || !(owner in chassis.occupants))
return
chassis.container_resist(owner)
/datum/action/vehicle/sealed/mecha/mech_toggle_internals
name = "Toggle Internal Airtank Usage"
button_icon_state = "mech_internals_off"
/datum/action/vehicle/sealed/mecha/mech_toggle_internals/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
chassis.use_internal_tank = !chassis.use_internal_tank
button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]"
to_chat(chassis.occupants, "[icon2html(chassis, owner)]<span class='notice'>Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].</span>")
chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA)
UpdateButtonIcon()
/datum/action/vehicle/sealed/mecha/mech_cycle_equip
name = "Cycle Equipment"
button_icon_state = "mech_cycle_equip_off"
/datum/action/vehicle/sealed/mecha/mech_cycle_equip/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
var/list/available_equipment = list()
for(var/e in chassis.equipment)
var/obj/item/mecha_parts/mecha_equipment/equipment = e
if(equipment.selectable)
available_equipment += equipment
if(available_equipment.len == 0)
to_chat(owner, "[icon2html(chassis, owner)]<span class='warning'>No equipment available!</span>")
return
if(!chassis.selected)
chassis.selected = available_equipment[1]
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>You select [chassis.selected].</span>")
send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
button_icon_state = "mech_cycle_equip_on"
UpdateButtonIcon()
return
var/number = 0
for(var/equipment in available_equipment)
number++
if(equipment != chassis.selected)
continue
if(available_equipment.len == number)
chassis.selected = null
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>You switch to no equipment.</span>")
button_icon_state = "mech_cycle_equip_off"
else
chassis.selected = available_equipment[number+1]
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>You switch to [chassis.selected].</span>")
button_icon_state = "mech_cycle_equip_on"
send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
UpdateButtonIcon()
return
/datum/action/vehicle/sealed/mecha/mech_toggle_lights
name = "Toggle Lights"
button_icon_state = "mech_lights_off"
/datum/action/vehicle/sealed/mecha/mech_toggle_lights/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
if(!(chassis.mecha_flags & HAS_LIGHTS))
to_chat(owner, "<span class='warning'>This mechs lights are destroyed!</span>")
return
chassis.mecha_flags ^= LIGHTS_ON
if(chassis.mecha_flags & LIGHTS_ON)
button_icon_state = "mech_lights_on"
chassis.set_light(5, 5)
else
button_icon_state = "mech_lights_off"
chassis.set_light(0)
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].</span>")
chassis.log_message("Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].", LOG_MECHA)
UpdateButtonIcon()
/datum/action/vehicle/sealed/mecha/mech_view_stats
name = "View Stats"
button_icon_state = "mech_view_stats"
/datum/action/vehicle/sealed/mecha/mech_view_stats/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
var/datum/browser/popup = new(owner , "exosuit")
popup.set_content(chassis.get_stats_html(owner))
popup.open()
/datum/action/vehicle/sealed/mecha/strafe
name = "Toggle Strafing. Disabled when Alt is held."
button_icon_state = "strafe"
/datum/action/vehicle/sealed/mecha/strafe/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
chassis.toggle_strafe()
/obj/vehicle/sealed/mecha/AltClick(mob/living/user)
if(!(user in occupants) || !user.canUseTopic(src))
return
if(!(user in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE)))
to_chat(user, "<span class='warning'>You're in the wrong seat to control movement.</span>")
return
toggle_strafe()
/obj/vehicle/sealed/mecha/proc/toggle_strafe()
strafe = !strafe
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>Toggled strafing mode [strafe?"on":"off"].</span>")
log_message("Toggled strafing mode [strafe?"on":"off"].", LOG_MECHA)
for(var/occupant in occupants)
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/strafe)
action?.UpdateButtonIcon()
//////////////////////////////////////// Specific Ability Actions ///////////////////////////////////////////////
//Need to be granted by the mech type, Not default abilities.
/datum/action/vehicle/sealed/mecha/mech_defense_mode
name = "Toggle an energy shield that blocks all attacks from the faced direction at a heavy power cost."
button_icon_state = "mech_defense_mode_off"
/datum/action/vehicle/sealed/mecha/mech_defense_mode/Trigger(forced_state = FALSE)
SEND_SIGNAL(chassis, COMSIG_MECHA_ACTION_TRIGGER, owner, args) //Signal sent to the mech, to be handed to the shield. See durand.dm for more details
/datum/action/vehicle/sealed/mecha/mech_overload_mode
name = "Toggle leg actuators overload"
button_icon_state = "mech_overload_off"
/datum/action/vehicle/sealed/mecha/mech_overload_mode/Trigger(forced_state = null)
if(!owner || !chassis || !(owner in chassis.occupants))
return
if(!isnull(forced_state))
chassis.leg_overload_mode = forced_state
else
chassis.leg_overload_mode = !chassis.leg_overload_mode
chassis.log_message("Toggled leg actuators overload.", LOG_MECHA)
if(!chassis.leg_overload_mode)
button_icon_state = "mech_overload_on"
chassis.bumpsmash = TRUE
chassis.movedelay = min(1, round(chassis.movedelay * 0.5))
chassis.step_energy_drain = max(chassis.overload_step_energy_drain_min,chassis.step_energy_drain*chassis.leg_overload_coeff)
to_chat(owner, "[icon2html(chassis, owner)]<span class='danger'>You enable leg actuators overload.</span>")
else
button_icon_state = "mech_overload_off"
chassis.bumpsmash = FALSE
chassis.movedelay = initial(chassis.movedelay)
chassis.step_energy_drain = chassis.normal_step_energy_drain
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>You disable leg actuators overload.</span>")
UpdateButtonIcon()
/datum/action/vehicle/sealed/mecha/mech_smoke
name = "Smoke"
button_icon_state = "mech_smoke"
/datum/action/vehicle/sealed/mecha/mech_smoke/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_SMOKE) && chassis.smoke_charges>0)
chassis.smoke_system.start()
chassis.smoke_charges--
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_SMOKE, chassis.smoke_cooldown)
/datum/action/vehicle/sealed/mecha/mech_zoom
name = "Zoom"
button_icon_state = "mech_zoom_off"
/datum/action/vehicle/sealed/mecha/mech_zoom/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
if(owner.client)
chassis.zoom_mode = !chassis.zoom_mode
button_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]"
chassis.log_message("Toggled zoom mode.", LOG_MECHA)
to_chat(owner, "[icon2html(chassis, owner)]<font color='[chassis.zoom_mode?"blue":"red"]'>Zoom mode [chassis.zoom_mode?"en":"dis"]abled.</font>")
if(chassis.zoom_mode)
owner.client.view_size.setTo(4.5)
SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50))
else
owner.client.view_size.resetToDefault() //Let's not let this stack shall we?
UpdateButtonIcon()
/datum/action/vehicle/sealed/mecha/mech_switch_damtype
name = "Reconfigure arm microtool arrays"
button_icon_state = "mech_damtype_brute"
/datum/action/vehicle/sealed/mecha/mech_switch_damtype/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
var/new_damtype
switch(chassis.damtype)
if("tox")
new_damtype = "brute"
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>Your exosuit's hands form into fists.</span>")
if("brute")
new_damtype = "fire"
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>A torch tip extends from your exosuit's hand, glowing red.</span>")
if("fire")
new_damtype = "tox"
to_chat(owner, "[icon2html(chassis, owner)]<span class='notice'>A bone-chillingly thick plasteel needle protracts from the exosuit's palm.</span>")
chassis.damtype = new_damtype
button_icon_state = "mech_damtype_[new_damtype]"
playsound(chassis, 'sound/mecha/mechmove01.ogg', 50, TRUE)
UpdateButtonIcon()
///swap seats, for two person mecha
/datum/action/vehicle/sealed/mecha/swap_seat
name = "Switch Seats"
button_icon_state = "mech_seat_swap"
/datum/action/vehicle/sealed/mecha/swap_seat/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
if(chassis.occupants.len == chassis.max_occupants)
to_chat(owner, "The other seat is occupied!")
return
var/list/drivers = chassis.return_drivers()
to_chat(owner, "Switching seats...")
chassis.is_currently_ejecting = TRUE
if(!do_after(owner, chassis.has_gravity() ? chassis.exit_delay : 0 , target = chassis))
chassis.is_currently_ejecting = FALSE
return
chassis.is_currently_ejecting = FALSE
if(owner in drivers)
to_chat(owner, "You shift to the gunner seat!")
chassis.remove_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
chassis.add_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
else
to_chat(owner, "You shift to the pilot seat!")
chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
chassis.update_icon_state()
/datum/action/vehicle/sealed/mecha/mech_toggle_phasing
name = "Toggle Phasing"
button_icon_state = "mech_phasing_off"
/datum/action/vehicle/sealed/mecha/mech_toggle_phasing/Trigger()
if(!owner || !chassis || !(owner in chassis.occupants))
return
chassis.phasing = !chassis.phasing
button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]"
to_chat(owner, "[icon2html(chassis, owner)]<font color=\"[chassis.phasing?"#00f\">En":"#f00\">Dis"]abled phasing.</font>")
UpdateButtonIcon()
/datum/action/vehicle/sealed/mecha/climb_out
name = "Eject From Mech"
button_icon_state = "mech_eject"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,160 @@
/obj/machinery/computer/mecha
name = "exosuit control console"
desc = "Used to remotely locate or lockdown exosuits."
icon_screen = "mecha"
icon_keyboard = "tech_key"
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/computer/mecha_control
/obj/machinery/computer/mecha/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ExosuitControlConsole", name)
ui.open()
/obj/machinery/computer/mecha/ui_data(mob/user)
var/list/data = list()
var/list/trackerlist = list()
for(var/obj/vehicle/sealed/mecha/MC in GLOB.mechas_list)
trackerlist += MC.trackers
data["mechs"] = list()
for(var/obj/item/mecha_parts/mecha_tracking/MT in trackerlist)
if(!MT.chassis)
continue
var/obj/vehicle/sealed/mecha/M = MT.chassis
var/list/mech_data = list(
name = M.name,
integrity = round((M.obj_integrity / M.max_integrity) * 100),
charge = M.cell ? round(M.cell.percent()) : null,
airtank = M.internal_tank ? M.return_pressure() : null,
pilot = M.return_drivers(),
location = get_area_name(M, TRUE),
active_equipment = M.selected,
emp_recharging = MT.recharging,
tracker_ref = REF(MT)
)
if(istype(M, /obj/vehicle/sealed/mecha/working/ripley))
var/obj/vehicle/sealed/mecha/working/ripley/RM = M
mech_data += list(
cargo_space = round((RM.cargo.len / RM.cargo_capacity) * 100)
)
data["mechs"] += list(mech_data)
return data
/obj/machinery/computer/mecha/ui_act(action, params)
if(..())
return
switch(action)
if("send_message")
var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"])
if(!istype(MT))
return
var/message = stripped_input(usr, "Input message", "Transmit message")
var/obj/vehicle/sealed/mecha/M = MT.chassis
if(trim(message) && M)
to_chat(M.occupants, message)
to_chat(usr, "<span class='notice'>Message sent.</span>")
. = TRUE
if("shock")
var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"])
if(!istype(MT))
return
var/obj/vehicle/sealed/mecha/M = MT.chassis
if(M)
MT.shock()
log_game("[key_name(usr)] has activated remote EMP on exosuit [M], located at [loc_name(M)], which [M.occupants ? "has the occupants [M.occupants]." : "without a pilot."] ")
message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [M.occupants ? "occupied by [M.occupants][ADMIN_FLW(M)]." : "without a pilot."] ")
. = TRUE
/obj/item/mecha_parts/mecha_tracking
name = "exosuit tracking beacon"
desc = "Device used to transmit exosuit data."
icon = 'icons/obj/device.dmi'
icon_state = "motion2"
w_class = WEIGHT_CLASS_SMALL
/// If this beacon allows for AI control. Exists to avoid using istype() on checking
var/ai_beacon = FALSE
/// Cooldown variable for EMP pulsing
var/recharging = FALSE
/// The Mecha that this tracking beacon is attached to
var/obj/vehicle/sealed/mecha/chassis
/**
* Returns a html formatted string describing attached mech status
*/
/obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info()
if(!chassis)
return FALSE
var/cell_charge = chassis.get_charge()
var/answer = {"<b>Name:</b> [chassis.name]<br>
<b>Integrity:</b> [round((chassis.obj_integrity/chassis.max_integrity * 100), 0.01)]%<br>
<b>Cell Charge:</b> [isnull(cell_charge) ? "Not Found":"[chassis.cell.percent()]%"]<br>
<b>Airtank:</b> [chassis.internal_tank ? "[round(chassis.return_pressure(), 0.01)]" : "Not Equipped"] kPa<br>
<b>Pilot:</b> [chassis.return_drivers() || "None"]<br>
<b>Location:</b> [get_area_name(chassis, TRUE) || "Unknown"]<br>
<b>Active Equipment:</b> [chassis.selected || "None"]"}
if(istype(chassis, /obj/vehicle/sealed/mecha/working/ripley))
var/obj/vehicle/sealed/mecha/working/ripley/RM = chassis
answer += "<br><b>Used Cargo Space:</b> [round((RM.cargo.len / RM.cargo_capacity * 100), 0.01)]%"
return answer
/obj/item/mecha_parts/mecha_tracking/emp_act()
. = ..()
if(!(. & EMP_PROTECT_SELF))
qdel(src)
/obj/item/mecha_parts/mecha_tracking/Destroy()
if(chassis)
if(src in chassis.trackers)
chassis.trackers -= src
chassis = null
return ..()
/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
if(!..())
return
M.trackers += src
M.diag_hud_set_mechtracking()
chassis = M
/**
* Attempts to EMP mech that the tracker is attached to, if there is one and tracker is not on cooldown
*/
/obj/item/mecha_parts/mecha_tracking/proc/shock()
if(recharging)
return
if(chassis)
chassis.emp_act(80)
addtimer(CALLBACK(src, /obj/item/mecha_parts/mecha_tracking/proc/recharge), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
recharging = TRUE
/**
* Resets recharge variable, allowing tracker to be EMP pulsed again
*/
/obj/item/mecha_parts/mecha_tracking/proc/recharge()
recharging = FALSE
/obj/item/mecha_parts/mecha_tracking/ai_control
name = "exosuit AI control beacon"
desc = "A device used to transmit exosuit data. Also allows active AI units to take control of said exosuit."
ai_beacon = TRUE
/obj/item/storage/box/mechabeacons
name = "exosuit tracking beacons"
/obj/item/storage/box/mechabeacons/PopulateContents()
..()
new /obj/item/mecha_parts/mecha_tracking(src)
new /obj/item/mecha_parts/mecha_tracking(src)
new /obj/item/mecha_parts/mecha_tracking(src)
new /obj/item/mecha_parts/mecha_tracking(src)
new /obj/item/mecha_parts/mecha_tracking(src)
new /obj/item/mecha_parts/mecha_tracking(src)
new /obj/item/mecha_parts/mecha_tracking(src)
@@ -0,0 +1,390 @@
/obj/vehicle/sealed/mecha/proc/get_armour_facing(relative_dir)
switch(relative_dir)
if(180) // BACKSTAB!
return facing_modifiers[MECHA_BACK_ARMOUR]
if(0, 45) // direct or 45 degrees off
return facing_modifiers[MECHA_FRONT_ARMOUR]
return facing_modifiers[MECHA_SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
/obj/vehicle/sealed/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(. && obj_integrity > 0)
spark_system.start()
switch(damage_flag)
if(FIRE)
check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL))
if(MELEE)
check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
else
check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT))
if(. >= 5 || prob(33))
to_chat(occupants, "[icon2html(src, occupants)]<span class='userdanger'>Taking damage!</span>")
log_message("Took [damage_amount] points of damage. Damage type: [damage_type]", LOG_MECHA)
/obj/vehicle/sealed/mecha/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
. = ..()
if(!damage_amount)
return 0
var/booster_deflection_modifier = 1
var/booster_damage_modifier = 1
if(damage_flag == BULLET || damage_flag == LASER || damage_flag == ENERGY)
for(var/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/B in equipment)
if(B.projectile_react())
booster_deflection_modifier = B.deflect_coeff
booster_damage_modifier = B.damage_coeff
break
else if(damage_flag == MELEE)
for(var/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/B in equipment)
if(B.attack_react())
booster_deflection_modifier *= B.deflect_coeff
booster_damage_modifier *= B.damage_coeff
break
if(attack_dir)
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
booster_damage_modifier /= facing_modifier
booster_deflection_modifier *= facing_modifier
if(prob(deflect_chance * booster_deflection_modifier))
visible_message("<span class='danger'>[src]'s armour deflects the attack!</span>")
log_message("Armor saved.", LOG_MECHA)
return 0
if(.)
. *= booster_damage_modifier
/obj/vehicle/sealed/mecha/attack_hand(mob/living/user)
. = ..()
if(.)
return
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
playsound(loc, 'sound/weapons/tap.ogg', 40, TRUE, -1)
user.visible_message("<span class='danger'>[user] hits [name]. Nothing happens.</span>", null, null, COMBAT_MESSAGE_RANGE)
log_message("Attack by hand/paw. Attacker - [user].", LOG_MECHA, color="red")
/obj/vehicle/sealed/mecha/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/vehicle/sealed/mecha/attack_alien(mob/living/user)
log_message("Attack by alien. Attacker - [user].", LOG_MECHA, color="red")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, TRUE)
attack_generic(user, 15, BRUTE, MELEE, 0)
/obj/vehicle/sealed/mecha/attack_animal(mob/living/simple_animal/user)
log_message("Attack by simple animal. Attacker - [user].", LOG_MECHA, color="red")
if(!user.melee_damage_upper && !user.obj_damage)
user.emote("custom", message = "[user.friendly_verb_continuous] [src].")
return 0
else
var/play_soundeffect = 1
if(user.environment_smash)
play_soundeffect = 0
playsound(src, 'sound/effects/bang.ogg', 50, TRUE)
var/animal_damage = rand(user.melee_damage_lower,user.melee_damage_upper)
if(user.obj_damage)
animal_damage = user.obj_damage
animal_damage = min(animal_damage, 20*user.environment_smash)
log_combat(user, src, "attacked")
attack_generic(user, animal_damage, user.melee_damage_type, MELEE, play_soundeffect)
return 1
/obj/vehicle/sealed/mecha/hulk_damage()
return 15
/obj/vehicle/sealed/mecha/attack_hulk(mob/living/carbon/human/user)
. = ..()
if(.)
log_message("Attack by hulk. Attacker - [user].", LOG_MECHA, color="red")
log_combat(user, src, "punched", "hulk powers")
/obj/vehicle/sealed/mecha/blob_act(obj/structure/blob/B)
log_message("Attack by blob. Attacker - [B].", LOG_MECHA, color="red")
take_damage(30, BRUTE, MELEE, 0, get_dir(src, B))
/obj/vehicle/sealed/mecha/attack_tk()
return
/obj/vehicle/sealed/mecha/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) //wrapper
log_message("Hit by [AM].", LOG_MECHA, color="red")
. = ..()
/obj/vehicle/sealed/mecha/bullet_act(obj/item/projectile/Proj) //wrapper
if(!enclosed && LAZYLEN(occupants) && !(mecha_flags & SILICON_PILOT) && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs
for(var/m in occupants)
var/mob/living/hitmob = m
hitmob.bullet_act(Proj) //If the sides are open, the occupant can be hit
return BULLET_ACT_HIT
log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).", LOG_MECHA, color="red")
. = ..()
/obj/vehicle/sealed/mecha/ex_act(severity, target)
log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red")
if(prob(deflect_chance))
severity++
log_message("Armor saved, changing severity to [severity]", LOG_MECHA)
. = ..()
/obj/vehicle/sealed/mecha/contents_explosion(severity, target, origin)
severity++
for(var/X in equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = X
ME.ex_act(severity, target, origin)
for(var/Y in trackers)
var/obj/item/mecha_parts/mecha_tracking/MT = Y
MT.ex_act(severity, target, origin)
for(var/Z in occupants)
var/mob/living/occupant = Z
occupant.ex_act(severity, target, origin)
/obj/vehicle/sealed/mecha/handle_atom_del(atom/A)
if(A in occupants)
LAZYREMOVE(occupants, A)
icon_state = initial(icon_state)+"-open"
setDir(dir_in)
/obj/vehicle/sealed/mecha/emp_act(severity)
. = ..()
if (. & EMP_PROTECT_SELF)
return
if(get_charge())
use_power((cell.charge/3)*(severity*0.005))
take_damage(severity/3, BURN, ENERGY, 1)
log_message("EMP detected", LOG_MECHA, color="red")
if(istype(src, /obj/vehicle/sealed/mecha/combat))
mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse-disable.dmi'
for(var/occus in occupants)
var/mob/living/occupant = occus
occupant.update_mouse_pointer()
if(!equipment_disabled && occupants) //prevent spamming this message with back-to-back EMPs
to_chat(occupants, "<span=danger>Error -- Connection to equipment control unit has been lost.</span>")
addtimer(CALLBACK(src, /obj/vehicle/sealed/mecha/proc/restore_equipment), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
equipment_disabled = 1
/obj/vehicle/sealed/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature>max_temperature)
log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red")
take_damage(5, BURN, 0, 1)
/obj/vehicle/sealed/mecha/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/mmi))
if(mmi_move_inside(W,user))
to_chat(user, "<span class='notice'>[src]-[W] interface initialized successfully.</span>")
else
to_chat(user, "<span class='warning'>[src]-[W] interface initialization failed.</span>")
return
if(istype(W, /obj/item/mecha_ammo))
ammo_resupply(W, user)
return
if(W.GetID())
if((mecha_flags & ADDING_ACCESS_POSSIBLE) || (mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE))
if(internals_access_allowed(user))
var/obj/item/card/id/id_card
if(istype(W, /obj/item/card/id))
id_card = W
else
var/obj/item/pda/pda = W
id_card = pda.id
output_maintenance_dialog(id_card, user)
return
to_chat(user, "<span class='warning'>Invalid ID: Access denied.</span>")
return
to_chat(user, "<span class='warning'>Maintenance protocols disabled by operator.</span>")
return
if(istype(W, /obj/item/stock_parts/cell))
if(construction_state == MECHA_OPEN_HATCH)
if(!cell)
if(!user.transferItemToLoc(W, src, silent = FALSE))
return
var/obj/item/stock_parts/cell/C = W
to_chat(user, "<span class='notice'>You install the power cell.</span>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, FALSE)
cell = C
log_message("Power cell installed", LOG_MECHA)
else
to_chat(user, "<span class='warning'>There's already a power cell installed!</span>")
return
if(istype(W, /obj/item/stock_parts/scanning_module))
if(construction_state == MECHA_OPEN_HATCH)
if(!scanmod)
if(!user.transferItemToLoc(W, src))
return
to_chat(user, "<span class='notice'>You install the scanning module.</span>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, FALSE)
scanmod = W
log_message("[W] installed", LOG_MECHA)
update_part_values()
else
to_chat(user, "<span class='warning'>There's already a scanning module installed!</span>")
return
if(istype(W, /obj/item/stock_parts/capacitor))
if(construction_state == MECHA_OPEN_HATCH)
if(!capacitor)
if(!user.transferItemToLoc(W, src))
return
to_chat(user, "<span class='notice'>You install the capacitor.</span>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, FALSE)
capacitor = W
log_message("[W] installed", LOG_MECHA)
update_part_values()
else
to_chat(user, "<span class='warning'>There's already a capacitor installed!</span>")
return
if(istype(W, /obj/item/stack/cable_coil))
if(construction_state == MECHA_OPEN_HATCH && (internal_damage & MECHA_INT_SHORT_CIRCUIT))
var/obj/item/stack/cable_coil/CC = W
if(CC.use(2))
clearInternalDamage(MECHA_INT_SHORT_CIRCUIT)
to_chat(user, "<span class='notice'>You replace the fused wires.</span>")
else
to_chat(user, "<span class='warning'>You need two lengths of cable to fix this mech!</span>")
return
if(istype(W, /obj/item/mecha_parts))
var/obj/item/mecha_parts/P = W
P.try_attach_part(user, src)
return
if(istype(W, /obj/item/analyzer))
if(construction_state)
var/datum/gas_mixture/GasNux = internal_tank.return_air()
atmosanalyzer_scan(GasNux,user,src,TRUE)
else
atmosanalyzer_scan(cabin_air,user,src,TRUE)
return
log_message("Attacked by [W]. Attacker - [user]", LOG_MECHA)
return ..()
/obj/vehicle/sealed/mecha/wrench_act(mob/living/user, obj/item/I)
..()
. = TRUE
if(construction_state == MECHA_SECURE_BOLTS)
construction_state = MECHA_LOOSE_BOLTS
to_chat(user, "<span class='notice'>You undo the securing bolts.</span>")
return
if(construction_state == MECHA_LOOSE_BOLTS)
construction_state = MECHA_SECURE_BOLTS
to_chat(user, "<span class='notice'>You tighten the securing bolts.</span>")
/obj/vehicle/sealed/mecha/crowbar_act(mob/living/user, obj/item/I)
..()
. = TRUE
if(construction_state == MECHA_LOOSE_BOLTS)
construction_state = MECHA_OPEN_HATCH
to_chat(user, "<span class='notice'>You open the hatch to the power unit.</span>")
return
if(construction_state == MECHA_OPEN_HATCH)
construction_state = MECHA_LOOSE_BOLTS
to_chat(user, "<span class='notice'>You close the hatch to the power unit.</span>")
/obj/vehicle/sealed/mecha/screwdriver_act(mob/living/user, obj/item/I)
..()
. = TRUE
if(internal_damage & MECHA_INT_TEMP_CONTROL)
clearInternalDamage(MECHA_INT_TEMP_CONTROL)
to_chat(user, "<span class='notice'>You repair the damaged temperature controller.</span>")
return
/obj/vehicle/sealed/mecha/welder_act(mob/living/user, obj/item/W)
. = ..()
if(user.a_intent == INTENT_HARM)
return
. = TRUE
if(internal_damage & MECHA_INT_TANK_BREACH)
if(!W.use_tool(src, user, 0, volume=50, amount=1))
return
clearInternalDamage(MECHA_INT_TANK_BREACH)
to_chat(user, "<span class='notice'>You repair the damaged gas tank.</span>")
return
if(obj_integrity < max_integrity)
if(!W.use_tool(src, user, 0, volume=50, amount=1))
return
user.visible_message("<span class='notice'>[user] repairs some damage to [name].</span>", "<span class='notice'>You repair some damage to [src].</span>")
obj_integrity += min(10, max_integrity-obj_integrity)
if(obj_integrity == max_integrity)
to_chat(user, "<span class='notice'>It looks to be fully repaired now.</span>")
return
to_chat(user, "<span class='warning'>The [name] is at full integrity!</span>")
/obj/vehicle/sealed/mecha/proc/mech_toxin_damage(mob/living/target)
playsound(src, 'sound/effects/spray2.ogg', 50, TRUE)
if(target.reagents)
if(target.reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + force < force*2)
target.reagents.add_reagent(/datum/reagent/cryptobiolin, force/2)
if(target.reagents.get_reagent_amount(/datum/reagent/toxin) + force < force*2)
target.reagents.add_reagent(/datum/reagent/toxin, force/2.5)
/obj/vehicle/sealed/mecha/mech_melee_attack(obj/vehicle/sealed/mecha/M, mob/user)
if(!has_charge(melee_energy_drain))
return NONE
use_power(melee_energy_drain)
if(M.damtype == BRUTE || M.damtype == BURN)
log_combat(user, src, "attacked", M, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
. = ..()
/obj/vehicle/sealed/mecha/proc/full_repair(charge_cell)
obj_integrity = max_integrity
if(cell && charge_cell)
cell.charge = cell.maxcharge
if(internal_damage & MECHA_INT_FIRE)
clearInternalDamage(MECHA_INT_FIRE)
if(internal_damage & MECHA_INT_TEMP_CONTROL)
clearInternalDamage(MECHA_INT_TEMP_CONTROL)
if(internal_damage & MECHA_INT_SHORT_CIRCUIT)
clearInternalDamage(MECHA_INT_SHORT_CIRCUIT)
if(internal_damage & MECHA_INT_TANK_BREACH)
clearInternalDamage(MECHA_INT_TANK_BREACH)
if(internal_damage & MECHA_INT_CONTROL_LOST)
clearInternalDamage(MECHA_INT_CONTROL_LOST)
/obj/vehicle/sealed/mecha/narsie_act()
emp_act(80)
/obj/vehicle/sealed/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect)
if(selected)
used_item = selected
else if(!visual_effect_icon)
visual_effect_icon = ATTACK_EFFECT_SMASH
if(damtype == BURN)
visual_effect_icon = ATTACK_EFFECT_MECHFIRE
else if(damtype == TOX)
visual_effect_icon = ATTACK_EFFECT_MECHTOXIN
..()
/obj/vehicle/sealed/mecha/obj_destruction()
if(wreckage)
var/mob/living/silicon/ai/AI
for(var/crew in occupants)
if(isAI(crew))
if(AI)
var/mob/living/silicon/ai/unlucky_ais = crew
unlucky_ais.gib()
continue
AI = crew
var/obj/structure/mecha_wreckage/WR = new wreckage(loc, AI)
for(var/obj/item/mecha_parts/mecha_equipment/E in equipment)
if(E.salvageable && prob(30))
WR.crowbar_salvage += E
E.detach(WR) //detaches from src into WR
E.equip_ready = 1
else
E.detach(loc)
qdel(E)
if(cell)
WR.crowbar_salvage += cell
cell.forceMove(WR)
cell.charge = rand(0, cell.charge)
cell = null
if(internal_tank)
WR.crowbar_salvage += internal_tank
internal_tank.forceMove(WR)
cell = null
. = ..()
+402
View File
@@ -0,0 +1,402 @@
/////////////////////////
////// Mecha Parts //////
/////////////////////////
/obj/item/mecha_parts
name = "mecha part"
icon = 'icons/mecha/mech_construct.dmi'
icon_state = "blank"
w_class = WEIGHT_CLASS_GIGANTIC
flags_1 = CONDUCT_1
/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M) //For attaching parts to a finished mech
if(!user.transferItemToLoc(src, M))
to_chat(user, "<span class='warning'>\The [src] is stuck to your hand, you cannot put it in \the [M]!</span>")
return FALSE
user.visible_message("<span class='notice'>[user] attaches [src] to [M].</span>", "<span class='notice'>You attach [src] to [M].</span>")
return TRUE
/obj/item/mecha_parts/part/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M)
return
/obj/item/mecha_parts/chassis
name = "Mecha Chassis"
icon_state = "backbone"
interaction_flags_item = NONE //Don't pick us up!!
var/construct_type
/obj/item/mecha_parts/chassis/Initialize()
. = ..()
if(construct_type)
AddComponent(construct_type)
/////////// Ripley
/obj/item/mecha_parts/chassis/ripley
name = "\improper Ripley chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/ripley
/obj/item/mecha_parts/part/ripley_torso
name = "\improper Ripley torso"
desc = "A torso part of Ripley APLU. Contains power unit, processing core and life support systems."
icon_state = "ripley_harness"
/obj/item/mecha_parts/part/ripley_left_arm
name = "\improper Ripley left arm"
desc = "A Ripley APLU left arm. Data and power sockets are compatible with most exosuit tools."
icon_state = "ripley_l_arm"
/obj/item/mecha_parts/part/ripley_right_arm
name = "\improper Ripley right arm"
desc = "A Ripley APLU right arm. Data and power sockets are compatible with most exosuit tools."
icon_state = "ripley_r_arm"
/obj/item/mecha_parts/part/ripley_left_leg
name = "\improper Ripley left leg"
desc = "A Ripley APLU left leg. Contains somewhat complex servodrives and balance maintaining systems."
icon_state = "ripley_l_leg"
/obj/item/mecha_parts/part/ripley_right_leg
name = "\improper Ripley right leg"
desc = "A Ripley APLU right leg. Contains somewhat complex servodrives and balance maintaining systems."
icon_state = "ripley_r_leg"
//Firefighter
/obj/item/mecha_parts/chassis/firefighter
name = "\improper Firefighter chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/firefighter
///////// Odysseus
/obj/item/mecha_parts/chassis/odysseus
name = "\improper Odysseus chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/odysseus
/obj/item/mecha_parts/part/odysseus_head
name = "\improper Odysseus head"
desc = "An Odysseus head. Contains an integrated medical HUD scanner."
icon_state = "odysseus_head"
/obj/item/mecha_parts/part/odysseus_torso
name = "\improper Odysseus torso"
desc="A torso part of Odysseus. Contains power unit, processing core and life support systems along with an attachment port for a mounted sleeper."
icon_state = "odysseus_torso"
/obj/item/mecha_parts/part/odysseus_left_arm
name = "\improper Odysseus left arm"
desc = "An Odysseus left arm. Data and power sockets are compatible with specialized medical equipment."
icon_state = "odysseus_l_arm"
/obj/item/mecha_parts/part/odysseus_right_arm
name = "\improper Odysseus right arm"
desc = "An Odysseus right arm. Data and power sockets are compatible with specialized medical equipment."
icon_state = "odysseus_r_arm"
/obj/item/mecha_parts/part/odysseus_left_leg
name = "\improper Odysseus left leg"
desc = "An Odysseus left leg. Contains complex servodrives and balance maintaining systems to maintain stability for critical patients."
icon_state = "odysseus_l_leg"
/obj/item/mecha_parts/part/odysseus_right_leg
name = "\improper Odysseus right leg"
desc = "An odysseus right leg. Contains complex servodrives and balance maintaining systems to maintain stability for critical patients."
icon_state = "odysseus_r_leg"
///////// Gygax
/obj/item/mecha_parts/chassis/gygax
name = "\improper Gygax chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/gygax
/obj/item/mecha_parts/part/gygax_torso
name = "\improper Gygax torso"
desc = "A torso part of Gygax. Contains power unit, processing core and life support systems."
icon_state = "gygax_harness"
/obj/item/mecha_parts/part/gygax_head
name = "\improper Gygax head"
desc = "A Gygax head. Houses advanced surveillance and targeting sensors."
icon_state = "gygax_head"
/obj/item/mecha_parts/part/gygax_left_arm
name = "\improper Gygax left arm"
desc = "A Gygax left arm. Data and power sockets are compatible with most exosuit tools and weapons."
icon_state = "gygax_l_arm"
/obj/item/mecha_parts/part/gygax_right_arm
name = "\improper Gygax right arm"
desc = "A Gygax right arm. Data and power sockets are compatible with most exosuit tools and weapons."
icon_state = "gygax_r_arm"
/obj/item/mecha_parts/part/gygax_left_leg
name = "\improper Gygax left leg"
desc = "A Gygax left leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
icon_state = "gygax_l_leg"
/obj/item/mecha_parts/part/gygax_right_leg
name = "\improper Gygax right leg"
desc = "A Gygax right leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
icon_state = "gygax_r_leg"
/obj/item/mecha_parts/part/gygax_armor
gender = PLURAL
name = "\improper Gygax armor plates"
desc = "A set of armor plates designed for the Gygax. Designed to effectively deflect damage with a lightweight construction."
icon_state = "gygax_armor"
///////// Medical Gygax
/obj/item/mecha_parts/chassis/medigax
name = "\improper Medical Gygax chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/medigax
/obj/item/mecha_parts/part/medigax_torso
name = "\improper Medical Gygax torso"
desc = "A torso part of Gygax. Contains power unit, processing core and life support systems."
icon_state = "medigax_harness"
/obj/item/mecha_parts/part/medigax_head
name = "\improper Medical Gygax head"
desc = "A Gygax head. Houses advanced surveillance and targeting sensors."
icon_state = "medigax_head"
/obj/item/mecha_parts/part/medigax_left_arm
name = "\improper Medical Gygax left arm"
desc = "A Gygax left arm. Data and power sockets are compatible with most exosuit tools and weapons."
icon_state = "medigax_l_arm"
/obj/item/mecha_parts/part/medigax_right_arm
name = "\improper Medical Gygax right arm"
desc = "A Gygax right arm. Data and power sockets are compatible with most exosuit tools and weapons."
icon_state = "medigax_r_arm"
/obj/item/mecha_parts/part/medigax_left_leg
name = "\improper Medical Gygax left leg"
desc = "A Gygax left leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
icon_state = "medigax_l_leg"
/obj/item/mecha_parts/part/medigax_right_leg
name = "\improper Medical Gygax right leg"
desc = "A Gygax right leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
icon_state = "medigax_r_leg"
/obj/item/mecha_parts/part/medigax_armor
gender = PLURAL
name = "\improper Medical Gygax armor plates"
desc = "A set of armor plates designed for the Gygax. Designed to effectively deflect damage with a lightweight construction."
icon_state = "medigax_armor"
//////////// Durand
/obj/item/mecha_parts/chassis/durand
name = "\improper Durand chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/durand
/obj/item/mecha_parts/part/durand_torso
name = "\improper Durand torso"
desc = "A torso part of Durand. Contains power unit, processing core and life support systems within a robust protective frame."
icon_state = "durand_harness"
/obj/item/mecha_parts/part/durand_head
name = "\improper Durand head"
desc = "A Durand head. Houses advanced surveillance and targeting sensors."
icon_state = "durand_head"
/obj/item/mecha_parts/part/durand_left_arm
name = "\improper Durand left arm"
desc = "A Durand left arm. Data and power sockets are compatible with most exosuit tools and weapons. Packs a really mean punch as well."
icon_state = "durand_l_arm"
/obj/item/mecha_parts/part/durand_right_arm
name = "\improper Durand right arm"
desc = "A Durand right arm. Data and power sockets are compatible with most exosuit tools and weapons. Packs a really mean punch as well."
icon_state = "durand_r_arm"
/obj/item/mecha_parts/part/durand_left_leg
name = "\improper Durand left leg"
desc = "A Durand left leg. Built particularly sturdy to support the Durand's heavy weight and defensive needs."
icon_state = "durand_l_leg"
/obj/item/mecha_parts/part/durand_right_leg
name = "\improper Durand right leg"
desc = "A Durand right leg. Built particularly sturdy to support the Durand's heavy weight and defensive needs."
icon_state = "durand_r_leg"
/obj/item/mecha_parts/part/durand_armor
gender = PLURAL
name = "\improper Durand armor plates"
desc = "A set of armor plates for the Durand. Built heavy to resist an incredible amount of brute force."
icon_state = "durand_armor"
////////// HONK
/obj/item/mecha_parts/chassis/honker
name = "\improper H.O.N.K chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/honker
/obj/item/mecha_parts/part/honker_torso
name = "\improper H.O.N.K torso"
desc = "A torso part of H.O.N.K. Contains chuckle unit, bananium core and honk support systems."
icon_state = "honker_harness"
/obj/item/mecha_parts/part/honker_head
name = "\improper H.O.N.K head"
desc = "A H.O.N.K head. Appears to lack a face plate."
icon_state = "honker_head"
/obj/item/mecha_parts/part/honker_left_arm
name = "\improper H.O.N.K left arm"
desc = "A H.O.N.K left arm. With unique sockets that accept odd weaponry designed by clown scientists."
icon_state = "honker_l_arm"
/obj/item/mecha_parts/part/honker_right_arm
name = "\improper H.O.N.K right arm"
desc = "A H.O.N.K right arm. With unique sockets that accept odd weaponry designed by clown scientists."
icon_state = "honker_r_arm"
/obj/item/mecha_parts/part/honker_left_leg
name = "\improper H.O.N.K left leg"
desc = "A H.O.N.K left leg. The foot appears just large enough to fully accommodate a clown shoe."
icon_state = "honker_l_leg"
/obj/item/mecha_parts/part/honker_right_leg
name = "\improper H.O.N.K right leg"
desc = "A H.O.N.K right leg. The foot appears just large enough to fully accommodate a clown shoe."
icon_state = "honker_r_leg"
////////// Phazon
/obj/item/mecha_parts/chassis/phazon
name = "\improper Phazon chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/phazon
/obj/item/mecha_parts/chassis/phazon/attackby(obj/item/I, mob/user, params)
. = ..()
if(istype(I, /obj/item/assembly/signaler/anomaly) && !istype(I, /obj/item/assembly/signaler/anomaly/bluespace))
to_chat(user, "The anomaly core socket only accepts bluespace anomaly cores!")
/obj/item/mecha_parts/part/phazon_torso
name="\improper Phazon torso"
desc="A Phazon torso part. The socket for the bluespace core that powers the exosuit's unique phase drives is located in the middle."
icon_state = "phazon_harness"
/obj/item/mecha_parts/part/phazon_head
name="\improper Phazon head"
desc="A Phazon head. Its sensors are carefully calibrated to provide vision and data even when the exosuit is phasing."
icon_state = "phazon_head"
/obj/item/mecha_parts/part/phazon_left_arm
name="\improper Phazon left arm"
desc="A Phazon left arm. Several microtool arrays are located under the armor plating, which can be adjusted to the situation at hand."
icon_state = "phazon_l_arm"
/obj/item/mecha_parts/part/phazon_right_arm
name="\improper Phazon right arm"
desc="A Phazon right arm. Several microtool arrays are located under the armor plating, which can be adjusted to the situation at hand."
icon_state = "phazon_r_arm"
/obj/item/mecha_parts/part/phazon_left_leg
name="\improper Phazon left leg"
desc="A Phazon left leg. It contains the unique phase drives that allow the exosuit to phase through solid matter when engaged."
icon_state = "phazon_l_leg"
/obj/item/mecha_parts/part/phazon_right_leg
name="\improper Phazon right leg"
desc="A Phazon right leg. It contains the unique phase drives that allow the exosuit to phase through solid matter when engaged."
icon_state = "phazon_r_leg"
/obj/item/mecha_parts/part/phazon_armor
name="Phazon armor"
desc="Phazon armor plates. They are layered with plasma to protect the pilot from the stress of phasing and have unusual properties."
icon_state = "phazon_armor"
///////// Circuitboards
/obj/item/circuitboard/mecha
name = "exosuit circuit board"
icon = 'icons/obj/module.dmi'
icon_state = "std_mod"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
flags_1 = CONDUCT_1
force = 5
w_class = WEIGHT_CLASS_SMALL
throwforce = 0
throw_speed = 3
throw_range = 7
/obj/item/circuitboard/mecha/ripley/peripherals
name = "Ripley Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/ripley/main
name = "Ripley Central Control module (Exosuit Board)"
icon_state = "mainboard"
/obj/item/circuitboard/mecha/gygax/peripherals
name = "Gygax Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/gygax/targeting
name = "Gygax Weapon Control and Targeting module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/gygax/main
name = "Gygax Central Control module (Exosuit Board)"
icon_state = "mainboard"
/obj/item/circuitboard/mecha/durand/peripherals
name = "Durand Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/durand/targeting
name = "Durand Weapon Control and Targeting module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/durand/main
name = "Durand Central Control module (Exosuit Board)"
icon_state = "mainboard"
/obj/item/circuitboard/mecha/honker/peripherals
name = "H.O.N.K Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/honker/targeting
name = "H.O.N.K Weapon Control and Targeting module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/honker/main
name = "H.O.N.K Central Control module (Exosuit Board)"
icon_state = "mainboard"
/obj/item/circuitboard/mecha/odysseus/peripherals
name = "Odysseus Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/odysseus/main
name = "Odysseus Central Control module (Exosuit Board)"
icon_state = "mainboard"
/obj/item/circuitboard/mecha/phazon/peripherals
name = "Phazon Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/phazon/targeting
name = "Phazon Weapon Control and Targeting module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/phazon/main
name = "Phazon Central Control module (Exosuit Board)"
/obj/item/circuitboard/mecha/clarke/peripherals
name = "Clarke Peripherals Control module (Exosuit Board)"
icon_state = "mcontroller"
/obj/item/circuitboard/mecha/clarke/main
name = "Clarke Central Control module (Exosuit Board)"
icon_state = "mainboard"
+421
View File
@@ -0,0 +1,421 @@
////////////////////////////////////
///// Rendering stats window ///////
////////////////////////////////////
/obj/vehicle/sealed/mecha/proc/get_stats_html(mob/user)
. = {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[name] data</title>
<style>
body {color: #00ff00; background: #000000; font-family:"Lucida Console",monospace; font-size: 12px;}
hr {border: 1px solid #0f0; color: #0f0; background-color: #0f0;}
a {padding:2px 5px;;color:#0f0;}
.wr {margin-bottom: 5px;}
.header {cursor:pointer;}
.open, .closed {background: #32CD32; color:#000; padding:1px 2px;}
.links a {margin-bottom: 2px;padding-top:3px;}
.visible {display: block;}
.hidden {display: none;}
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
[js_dropdowns]
function SSticker() {
setInterval(function(){
window.location='byond://?src=[REF(src)]&update_content=1';
}, 1000);
}
window.onload = function() {
dropdowns();
SSticker();
}
</script>
</head>
<body>
<div id='content'>
[get_stats_part(user)]
</div></div>
<div id='eq_list'>
[get_equipment_list()]
</div>
<hr>
<div id='commands'>
[get_commands()]
</div>
<div id='equipment_menu'>
[get_equipment_menu()]
</div>
</body>
</html>"}
///Returns the status of the mech.
/obj/vehicle/sealed/mecha/proc/get_stats_part(mob/user)
var/integrity = obj_integrity/max_integrity*100
var/cell_charge = get_charge()
var/datum/gas_mixture/int_tank_air = 0
var/tank_pressure = 0
var/tank_temperature = 0
var/cabin_pressure = 0
if (internal_tank)
int_tank_air = internal_tank.return_air()
tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
tank_temperature = internal_tank ? int_tank_air.return_temperature() : "Unknown"
cabin_pressure = round(return_pressure(),0.01)
. = {"[report_internal_damage()]
[integrity<30?"<span class='userdanger'>DAMAGE LEVEL CRITICAL</span><br>":null]
<b>Integrity: </b> [integrity]%<br>
<b>Power cell charge: </b>[isnull(cell_charge)?"No power cell installed":"[cell.percent()]%"]<br>
<b>Air source: </b>[internal_tank?"[use_internal_tank?"Internal Airtank":"Environment"]":"Environment"]<br>
<b>Airtank pressure: </b>[internal_tank?"[tank_pressure]kPa":"N/A"]<br>
<b>Airtank temperature: </b>[internal_tank?"[tank_temperature]&deg;K|[tank_temperature - T0C]&deg;C":"N/A"]<br>
<b>Cabin pressure: </b>[internal_tank?"[cabin_pressure>WARNING_HIGH_PRESSURE ? "<span class='danger'>[cabin_pressure]</span>": cabin_pressure]kPa":"N/A"]<br>
<b>Cabin temperature: </b> [internal_tank?"[return_temperature()]&deg;K|[return_temperature() - T0C]&deg;C":"N/A"]<br>
[dna_lock?"<b>DNA-locked:</b><br> <span style='font-size:10px;letter-spacing:-1px;'>[dna_lock]</span> \[<a href='?src=[REF(src)];reset_dna=1'>Reset</a>\]<br>":""]<br>"}
. += "[get_actions(user)]<br>"
///Returns HTML for mech actions. Ideally, this proc would be empty for the base mecha. Segmented for easy refactoring.
/obj/vehicle/sealed/mecha/proc/get_actions(mob/user)
. = ""
. += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_defense_mode) ? "<b>Defense Mode: </b> [defense_mode ? "Enabled" : "Disabled"]<br>" : ""]"
. += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_overload_mode) ? "<b>Leg Actuators Overload: </b> [leg_overload_mode ? "Enabled" : "Disabled"]<br>" : ""]"
. += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_smoke) ? "<b>Smoke Charges remaining: </b> [smoke_charges]<br>" : ""]"
. += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_zoom) ? "<b>Zoom: </b> [zoom_mode ? "Enabled" : "Disabled"]<br>" : ""]"
. += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_switch_damtype) ? "<b>Damtype: </b> [damtype]<br>" : ""]"
. += "[LAZYACCESSASSOC(occupant_actions, user, /datum/action/vehicle/sealed/mecha/mech_toggle_phasing) ? "<b>Phase Modulator: </b> [phasing ? "Enabled" : "Disabled"]<br>" : ""]"
///HTML for internal damage.
/obj/vehicle/sealed/mecha/proc/report_internal_damage()
. = ""
var/list/dam_reports = list(
"[MECHA_INT_FIRE]" = "<span class='userdanger'>INTERNAL FIRE</span>",
"[MECHA_INT_TEMP_CONTROL]" = "<span class='userdanger'>LIFE SUPPORT SYSTEM MALFUNCTION</span>",
"[MECHA_INT_TANK_BREACH]" = "<span class='userdanger'>GAS TANK BREACH</span>",
"[MECHA_INT_CONTROL_LOST]" = "<span class='userdanger'>COORDINATION SYSTEM CALIBRATION FAILURE</span> - <a href='?src=[REF(src)];repair_int_control_lost=1'>Recalibrate</a>",
"[MECHA_INT_SHORT_CIRCUIT]" = "<span class='userdanger'>SHORT CIRCUIT</span>"
)
for(var/tflag in dam_reports)
var/intdamflag = text2num(tflag)
if(internal_damage & intdamflag)
. += dam_reports[tflag]
. += "<br />"
if(return_pressure() > WARNING_HIGH_PRESSURE)
. += "<span class='userdanger'>DANGEROUSLY HIGH CABIN PRESSURE</span><br />"
///HTML for list of equipment.
/obj/vehicle/sealed/mecha/proc/get_equipment_list() //outputs mecha equipment list in html
if(!LAZYLEN(equipment))
return
. = "<b>Equipment:</b><div style=\"margin-left: 15px;\">"
for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment)
. += "<div id='[REF(MT)]'>[MT.get_equip_info()]</div>"
. += "</div>"
///HTML for commands.
/obj/vehicle/sealed/mecha/proc/get_commands()
. = {"
<div class='wr'>
<div class='header'>Electronics</div>
<div class='links'>
<b>Radio settings:</b><br>
Microphone:
[radio? "<a href='?src=[REF(src)];rmictoggle=1'>\
<span id=\"rmicstate\">[radio.broadcasting?"Engaged":"Disengaged"]</span></a>":"Error"]<br>
Speaker:
[radio? "<a href='?src=[REF(src)];rspktoggle=1'><span id=\"rspkstate\">\
[radio.listening?"Engaged":"Disengaged"]</span></a>":"Error"]<br>
Frequency:
[radio? "<a href='?src=[REF(src)];rfreq=-10'>-</a>":"-"]
[radio? "<a href='?src=[REF(src)];rfreq=-2'>-</a>":"-"]
<span id=\"rfreq\">[radio?"[format_frequency(radio.frequency)]":"Error"]</span>
[radio? "<a href='?src=[REF(src)];rfreq=2'>+</a>":"+"]
[radio? "<a href='?src=[REF(src)];rfreq=10'>+</a>":"+"]<br>
</div>
</div>
<div class='wr'>
<div class='header'>Permissions & Logging</div>
<div class='links'>
<a href='?src=[REF(src)];toggle_id_upload=1'><span id='t_id_upload'>[(mecha_flags & ADDING_ACCESS_POSSIBLE)?"L":"Unl"]ock ID upload panel</span></a><br>
<a href='?src=[REF(src)];toggle_maint_access=1'><span id='t_maint_access'>[(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"Forbid":"Permit"] maintenance protocols</span></a><br>
[internal_tank?"<a href='?src=[REF(src)];toggle_port_connection=1'><span id='t_port_connection'>[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port</span></a><br>":""]
<a href='?src=[REF(src)];dna_lock=1'>DNA-lock</a><br>
<a href='?src=[REF(src)];change_name=1'>Change exosuit name</a>
</div>
</div>"}
/obj/vehicle/sealed/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu
. = {"
<div class='wr'>
<div class='header'>Equipment</div>
<div class='links'>"}
for(var/e in equipment)
var/obj/item/mecha_parts/mecha_equipment/equipment = e
. += "[equipment.name] [equipment.detachable ? "<a href='?src=[REF(equipment)];detach=1'>Detach</a><br>" : "\[Non-removable\]<br>"]"
. += {"<b>Available equipment slots:</b> [max_equip-LAZYLEN(equipment)]
</div>
</div>"}
/obj/vehicle/sealed/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user)
if(!id_card || !user)
return
. = {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<style>
h1 {font-size:15px;margin-bottom:4px;}
body {color: #00ff00; background: #000000; font-family:"Courier New", Courier, monospace; font-size: 12px;}
a {color:#0f0;}
</style>
</head>
<body>
<h1>Following keycodes are present in this system:</h1>"}
for(var/a in operation_req_access)
. += "[get_access_desc(a)] - <a href='?src=[REF(src)];del_req_access=[a];user=[REF(user)];id_card=[REF(id_card)]'>Delete</a><br>"
. += "<hr><h1>Following keycodes were detected on portable device:</h1>"
for(var/a in id_card.access)
if(a in operation_req_access)
continue
var/a_name = get_access_desc(a)
if(!a_name)
continue //there's some strange access without a name
. += "[a_name] - <a href='?src=[REF(src)];add_req_access=[a];user=[REF(user)];id_card=[REF(id_card)]'>Add</a><br>"
. +={"<hr><a href='?src=[REF(src)];finish_req_access=1;user=[REF(user)]'>Lock ID panel</a><br>
<span class='danger'>(Warning! The ID upload panel can be unlocked only through Exosuit Interface.)</span>
</body>
</html>"}
user << browse(., "window=exosuit_add_access")
onclose(user, "exosuit_add_access")
/obj/vehicle/sealed/mecha/proc/output_maintenance_dialog(obj/item/card/id/id_card,mob/user)
if(!id_card || !user)
return
. = {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<style>
body {color: #00ff00; background: #000000; font-family:"Courier New", Courier, monospace; font-size: 12px;}
a {padding:2px 5px; background:#32CD32;color:#000;display:block;margin:2px;text-align:center;text-decoration:none;}
</style>
</head>
<body>
[(mecha_flags & ADDING_ACCESS_POSSIBLE)?"<a href='?src=[REF(src)];req_access=1;id_card=[REF(id_card)];user=[REF(user)]'>Edit operation keycodes</a>":null]
[(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"<a href='?src=[REF(src)];maint_access=1;id_card=[REF(id_card)];user=[REF(user)]'>[(construction_state > MECHA_LOCKED) ? "Terminate" : "Initiate"] maintenance protocol</a>":null]
[(construction_state == MECHA_OPEN_HATCH) ?"--------------------</br>":null]
[(construction_state == MECHA_OPEN_HATCH) ?"[cell?"<a href='?src=[REF(src)];drop_cell=1;id_card=[REF(id_card)];user=[REF(user)]'>Drop power cell</a>":"No cell installed</br>"]":null]
[(construction_state == MECHA_OPEN_HATCH) ?"[scanmod?"<a href='?src=[REF(src)];drop_scanmod=1;id_card=[REF(id_card)];user=[REF(user)]'>Drop scanning module</a>":"No scanning module installed</br>"]":null]
[(construction_state == MECHA_OPEN_HATCH) ?"[capacitor?"<a href='?src=[REF(src)];drop_cap=1;id_card=[REF(id_card)];user=[REF(user)]'>Drop capacitor</a>":"No capacitor installed</br>"]":null]
[(construction_state == MECHA_OPEN_HATCH) ?"--------------------</br>":null]
[(construction_state > MECHA_LOCKED) ?"<a href='?src=[REF(src)];set_internal_tank_valve=1;user=[REF(user)]'>Set Cabin Air Pressure</a>":null]
</body>
</html>"}
user << browse(., "window=exosuit_maint_console")
onclose(user, "exosuit_maint_console")
/////////////////
///// Topic /////
/////////////////
/obj/vehicle/sealed/mecha/Topic(href, href_list)
..()
if(!usr)
return
if(href_list["close"])
return
if(usr.incapacitated())
return
if(in_range(src, usr))
//Start of ID requirements.
if(href_list["id_card"])
var/obj/item/card/id/id_card
id_card = locate(href_list["id_card"])
if(!istype(id_card))
return
if(href_list["req_access"])
if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
return
output_access_dialog(id_card,usr)
return
if(href_list["maint_access"])
if(!(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE))
return
if(construction_state == MECHA_LOCKED)
construction_state = MECHA_SECURE_BOLTS
to_chat(usr, "<span class='notice'>The securing bolts are now exposed.</span>")
else if(construction_state == MECHA_SECURE_BOLTS)
construction_state = MECHA_LOCKED
to_chat(usr, "<span class='notice'>The securing bolts are now hidden.</span>")
output_maintenance_dialog(id_card,usr)
return
if(href_list["drop_cell"])
if(construction_state == MECHA_OPEN_HATCH)
cell.forceMove(get_turf(src))
cell = null
output_maintenance_dialog(id_card,usr)
return
if(href_list["drop_scanmod"])
if(construction_state == MECHA_OPEN_HATCH)
scanmod.forceMove(get_turf(src))
scanmod = null
output_maintenance_dialog(id_card,usr)
return
if(href_list["drop_cap"])
if(construction_state == MECHA_OPEN_HATCH)
capacitor.forceMove(get_turf(src))
capacitor = null
output_maintenance_dialog(id_card,usr)
return
if(href_list["add_req_access"])
if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
return
operation_req_access += text2num(href_list["add_req_access"])
output_access_dialog(id_card,usr)
return
if(href_list["del_req_access"])
if(!(mecha_flags & ADDING_ACCESS_POSSIBLE))
return
operation_req_access -= text2num(href_list["del_req_access"])
output_access_dialog(id_card, usr)
return
return //Here end everything requiring an ID.
//Here ID access stuff goes to die.
if(href_list["finish_req_access"])
mecha_flags &= ~ADDING_ACCESS_POSSIBLE
usr << browse(null,"window=exosuit_add_access")
return
//Set pressure.
if(href_list["set_internal_tank_valve"] && construction_state)
var/new_pressure = input(usr,"Input new output pressure","Pressure setting",internal_tank_valve) as num|null
if(isnull(new_pressure) || usr.incapacitated() || !construction_state)
return
internal_tank_valve = new_pressure
to_chat(usr, "<span class='notice'>The internal pressure valve has been set to [internal_tank_valve]kPa.</span>")
return
//Start of all internal topic stuff.
if(!locate(usr) in occupants)
return
if(href_list["update_content"])
send_byjax(usr,"exosuit.browser","content", get_stats_part())
return
//Selects the mech equipment/weapon.
if(href_list["select_equip"])
var/obj/item/mecha_parts/mecha_equipment/equip = locate(href_list["select_equip"]) in src
if(!equip || !equip.selectable)
return
selected = equip
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>You switch to [equip].</span>")
visible_message("<span class='notice'>[src] raises [equip].</span>")
send_byjax(usr, "exosuit.browser", "eq_list", get_equipment_list())
return
//Toggles radio broadcasting
if(href_list["rmictoggle"])
radio.broadcasting = !radio.broadcasting
send_byjax(usr,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged"))
return
//Toggles radio listening
if(href_list["rspktoggle"])
radio.listening = !radio.listening
send_byjax(usr,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged"))
return
//Changes radio freqency.
if(href_list["rfreq"])
var/new_frequency = radio.frequency + text2num(href_list["rfreq"])
radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange))
send_byjax(usr,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]")
return
//Changes the exosuit name.
if(href_list["change_name"])
var/userinput = stripped_input(usr, "Choose a new exosuit name.", "Rename exosuit", "", MAX_NAME_LEN)
if(!userinput || !locate(usr) in occupants || usr.incapacitated())
return
name = userinput
return
//Toggles ID upload.
if (href_list["toggle_id_upload"])
mecha_flags ^= ADDING_ACCESS_POSSIBLE
send_byjax(usr,"exosuit.browser","t_id_upload","[(mecha_flags & ADDING_ACCESS_POSSIBLE)?"L":"Unl"]ock ID upload panel")
return
//Toggles main access.
if(href_list["toggle_maint_access"])
if(construction_state)
to_chat(occupants, "[icon2html(src, occupants)]<span class='danger'>Maintenance protocols in effect</span>")
return
mecha_flags ^= ADDING_MAINT_ACCESS_POSSIBLE
send_byjax(usr,"exosuit.browser","t_maint_access","[(mecha_flags & ADDING_MAINT_ACCESS_POSSIBLE)?"Forbid":"Permit"] maintenance protocols")
return
//Toggles connection port.
if (href_list["toggle_port_connection"])
if(internal_tank.connected_port)
if(internal_tank.disconnect())
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>Disconnected from the air system port.</span>")
log_message("Disconnected from gas port.", LOG_MECHA)
else
to_chat(occupants, "[icon2html(src, occupants)]<span class='warning'>Unable to disconnect from the air system port!</span>")
return
else
var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate() in loc
if(internal_tank.connect(possible_port))
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>Connected to the air system port.</span>")
log_message("Connected to gas port.", LOG_MECHA)
else
to_chat(occupants, "[icon2html(src, occupants)]<span class='warning'>Unable to connect with air system port!</span>")
return
send_byjax(occupants,"exosuit.browser","t_port_connection","[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port")
return
//Turns on the DNA lock
if(href_list["dna_lock"])
var/mob/living/carbon/user = usr
if(!istype(user) || !user.dna)
to_chat(user, "[icon2html(src, occupants)]<span class='notice'>You can't create a DNA lock with no DNA!.</span>")
return
dna_lock = user.dna.unique_enzymes
to_chat(user, "[icon2html(src, occupants)]<span class='notice'>You feel a prick as the needle takes your DNA sample.</span>")
return
//Resets the DNA lock
if(href_list["reset_dna"])
dna_lock = null
return
//Repairs internal damage
if(href_list["repair_int_control_lost"])
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>Recalibrating coordination system...</span>")
log_message("Recalibration of coordination system started.", LOG_MECHA)
addtimer(CALLBACK(src, .proc/stationary_repair, loc), 100, TIMER_UNIQUE)
///Repairs internal damage if the mech hasn't moved.
/obj/vehicle/sealed/mecha/proc/stationary_repair(location)
if(location == loc)
clearInternalDamage(MECHA_INT_CONTROL_LOST)
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>Recalibration successful.</span>")
log_message("Recalibration of coordination system finished with 0 errors.", LOG_MECHA)
else
to_chat(occupants, "[icon2html(src, occupants)]<span class='warning'>Recalibration failed!</span>")
log_message("Recalibration of coordination system failed with 1 error.", LOG_MECHA, color="red")
@@ -0,0 +1,222 @@
///////////////////////////////////
//////// Mecha wreckage ////////
///////////////////////////////////
/obj/structure/mecha_wreckage
name = "exosuit wreckage"
desc = "Remains of some unfortunate mecha. Completely irreparable, but perhaps something can be salvaged."
icon = 'icons/mecha/mecha.dmi'
density = TRUE
anchored = FALSE
opacity = FALSE
var/list/welder_salvage = list(/obj/item/stack/sheet/plasteel, /obj/item/stack/sheet/metal, /obj/item/stack/rods)
var/salvage_num = 5
var/list/crowbar_salvage = list()
var/wires_removed = FALSE
var/mob/living/silicon/ai/AI //AIs to be salvaged
var/list/parts
/obj/structure/mecha_wreckage/Initialize(mapload, mob/living/silicon/ai/AI_pilot)
. = ..()
if(parts)
for(var/i in 1 to 2)
if(!parts.len)
break
if(prob(60))
continue
var/part = pick(parts)
welder_salvage += part
parts = null
if(!AI_pilot) //Type-checking for this is already done in mecha/Destroy()
return
AI = AI_pilot
AI.apply_damage(150, BURN) //Give the AI a bit of damage from the "shock" of being suddenly shut down
AI.death() //The damage is not enough to kill the AI, but to be 'corrupted files' in need of repair.
AI.forceMove(src) //Put the dead AI inside the wreckage for recovery
add_overlay(mutable_appearance('icons/obj/projectiles.dmi', "green_laser")) //Overlay for the recovery beacon
AI.controlled_mech = null
AI.remote_control = null
/obj/structure/mecha_wreckage/Destroy()
if(AI)
QDEL_NULL(AI)
QDEL_LIST(crowbar_salvage)
return ..()
/obj/structure/mecha_wreckage/examine(mob/user)
. = ..()
if(!AI)
return
. += "<span class='notice'>The AI recovery beacon is active.</span>"
/obj/structure/mecha_wreckage/welder_act(mob/living/user, obj/item/I)
..()
. = TRUE
if(salvage_num <= 0 || !length(welder_salvage))
to_chat(user, "<span class='notice'>You don't see anything that can be cut with [I]!</span>")
return
if(!I.use_tool(src, user, 0, volume=50))
return
if(prob(30))
to_chat(user, "<span class='notice'>You fail to salvage anything valuable from [src]!</span>")
return
var/type = pick(welder_salvage)
var/N = new type(get_turf(user))
user.visible_message("<span class='notice'>[user] cuts [N] from [src].</span>", "<span class='notice'>You cut [N] from [src].</span>")
if(!istype(N, /obj/item/stack))
welder_salvage -= type
salvage_num--
/obj/structure/mecha_wreckage/wirecutter_act(mob/living/user, obj/item/I)
..()
. = TRUE
if(wires_removed)
to_chat(user, "<span class='notice'>You don't see anything that can be cut with [I]!</span>")
return
var/N = new /obj/item/stack/cable_coil(get_turf(user), rand(1,3))
user.visible_message("<span class='notice'>[user] cuts [N] from [src].</span>", "<span class='notice'>You cut [N] from [src].</span>")
wires_removed = TRUE
/obj/structure/mecha_wreckage/crowbar_act(mob/living/user, obj/item/I)
..()
. = TRUE
if(crowbar_salvage.len)
var/obj/S = pick(crowbar_salvage)
S.forceMove(user.drop_location())
user.visible_message("<span class='notice'>[user] pries [S] from [src].</span>", "<span class='notice'>You pry [S] from [src].</span>")
crowbar_salvage -= S
return
to_chat(user, "<span class='notice'>You don't see anything that can be cut with [I]!</span>")
/obj/structure/mecha_wreckage/transfer_ai(interaction, mob/user, null, obj/item/aicard/card)
if(!..())
return
//Proc called on the wreck by the AI card.
if(interaction != AI_TRANS_TO_CARD) //AIs can only be transferred in one direction, from the wreck to the card.
return
if(!AI) //No AI in the wreck
to_chat(user, "<span class='warning'>No AI backups found.</span>")
return
cut_overlays() //Remove the recovery beacon overlay
AI.forceMove(card) //Move the dead AI to the card.
card.AI = AI
if(AI.client) //AI player is still in the dead AI and is connected
to_chat(AI, "<span class='notice'>The remains of your file system have been recovered on a mobile storage device.</span>")
else //Give the AI a heads-up that it is probably going to get fixed.
AI.notify_ghost_cloning("You have been recovered from the wreckage!", source = card)
to_chat(user, "<span class='boldnotice'>Backup files recovered</span>: [AI.name] ([rand(1000,9999)].exe) salvaged from [name] and stored within local memory.")
AI = null
/obj/structure/mecha_wreckage/gygax
name = "\improper Gygax wreckage"
icon_state = "gygax-broken"
parts = list(
/obj/item/mecha_parts/part/gygax_torso,
/obj/item/mecha_parts/part/gygax_head,
/obj/item/mecha_parts/part/gygax_left_arm,
/obj/item/mecha_parts/part/gygax_right_arm,
/obj/item/mecha_parts/part/gygax_left_leg,
/obj/item/mecha_parts/part/gygax_right_leg
)
/obj/structure/mecha_wreckage/gygax/dark
name = "\improper Dark Gygax wreckage"
icon_state = "darkgygax-broken"
/obj/structure/mecha_wreckage/marauder
name = "\improper Marauder wreckage"
icon_state = "marauder-broken"
/obj/structure/mecha_wreckage/mauler
name = "\improper Mauler wreckage"
icon_state = "mauler-broken"
desc = "The syndicate won't be very happy about this..."
/obj/structure/mecha_wreckage/seraph
name = "\improper Seraph wreckage"
icon_state = "seraph-broken"
/obj/structure/mecha_wreckage/reticence
name = "\improper Reticence wreckage"
icon_state = "reticence-broken"
color = "#87878715"
desc = "..."
/obj/structure/mecha_wreckage/ripley
name = "\improper Ripley wreckage"
icon_state = "ripley-broken"
parts = list(
/obj/item/mecha_parts/part/ripley_torso,
/obj/item/mecha_parts/part/ripley_left_arm,
/obj/item/mecha_parts/part/ripley_right_arm,
/obj/item/mecha_parts/part/ripley_left_leg,
/obj/item/mecha_parts/part/ripley_right_leg)
/obj/structure/mecha_wreckage/ripley/mkii
name = "\improper Ripley MK-II wreckage"
icon_state = "ripleymkii-broken"
/obj/structure/mecha_wreckage/ripley/deathripley
name = "\improper Death-Ripley wreckage"
icon_state = "deathripley-broken"
parts = null
/obj/structure/mecha_wreckage/ripley/firefighter
name = "\improper Firefighter wreckage"
icon_state = "firefighter-broken"
parts = list(
/obj/item/mecha_parts/part/ripley_torso,
/obj/item/mecha_parts/part/ripley_left_arm,
/obj/item/mecha_parts/part/ripley_right_arm,
/obj/item/mecha_parts/part/ripley_left_leg,
/obj/item/mecha_parts/part/ripley_right_leg)
/obj/structure/mecha_wreckage/honker
name = "\improper H.O.N.K wreckage"
icon_state = "honker-broken"
desc = "All is right in the universe."
parts = list(
/obj/item/mecha_parts/part/honker_torso,
/obj/item/mecha_parts/part/honker_head,
/obj/item/mecha_parts/part/honker_left_arm,
/obj/item/mecha_parts/part/honker_right_arm,
/obj/item/mecha_parts/part/honker_left_leg,
/obj/item/mecha_parts/part/honker_right_leg)
/obj/structure/mecha_wreckage/durand
name = "\improper Durand wreckage"
icon_state = "durand-broken"
parts = list(
/obj/item/mecha_parts/part/durand_torso,
/obj/item/mecha_parts/part/durand_head,
/obj/item/mecha_parts/part/durand_left_arm,
/obj/item/mecha_parts/part/durand_right_arm,
/obj/item/mecha_parts/part/durand_left_leg,
/obj/item/mecha_parts/part/durand_right_leg)
/obj/structure/mecha_wreckage/phazon
name = "\improper Phazon wreckage"
icon_state = "phazon-broken"
parts = list(
/obj/item/mecha_parts/part/phazon_torso,
/obj/item/mecha_parts/part/phazon_head,
/obj/item/mecha_parts/part/phazon_left_arm,
/obj/item/mecha_parts/part/phazon_right_arm,
/obj/item/mecha_parts/part/phazon_left_leg,
/obj/item/mecha_parts/part/phazon_right_leg)
/obj/structure/mecha_wreckage/odysseus
name = "\improper Odysseus wreckage"
icon_state = "odysseus-broken"
parts = list(
/obj/item/mecha_parts/part/odysseus_torso,
/obj/item/mecha_parts/part/odysseus_head,
/obj/item/mecha_parts/part/odysseus_left_arm,
/obj/item/mecha_parts/part/odysseus_right_arm,
/obj/item/mecha_parts/part/odysseus_left_leg,
/obj/item/mecha_parts/part/odysseus_right_leg)
@@ -0,0 +1,33 @@
/obj/vehicle/sealed/mecha/medical/odysseus
desc = "These exosuits are developed and produced by Vey-Med. (&copy; All rights reserved)."
name = "\improper Odysseus"
icon_state = "odysseus"
allow_diagonal_movement = TRUE
movedelay = 2
max_temperature = 15000
max_integrity = 120
wreckage = /obj/structure/mecha_wreckage/odysseus
internal_damage_threshold = 35
deflect_chance = 15
step_energy_drain = 6
internals_req_access = list(ACCESS_ROBOTICS, ACCESS_MEDICAL)
/obj/vehicle/sealed/mecha/medical/odysseus/moved_inside(mob/living/carbon/human/H)
. = ..()
if(.)
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.add_hud_to(H)
/obj/vehicle/sealed/mecha/medical/odysseus/remove_occupant(mob/M)
if(isliving(M))
var/mob/living/L = M
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.remove_hud_from(L)
return ..()
/obj/vehicle/sealed/mecha/medical/odysseus/mmi_moved_inside(obj/item/mmi/M, mob/user)
. = ..()
if(.)
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
var/mob/living/brain/B = M.brainmob
hud.add_hud_to(B)
@@ -0,0 +1,218 @@
/obj/vehicle/sealed/mecha/working/ripley
desc = "Autonomous Power Loader Unit MK-I. Designed primarily around heavy lifting, the Ripley can be outfitted with utility equipment to fill a number of roles."
name = "\improper APLU MK-I \"Ripley\""
icon_state = "ripley"
silicon_icon_state = "ripley-empty"
movedelay = 1.5 //Move speed, lower is faster.
/// How fast the mech is in low pressure
var/fast_pressure_step_in = 1.5
/// How fast the mech is in normal pressure
var/slow_pressure_step_in = 2
max_temperature = 20000
max_integrity = 200
lights_power = 7
deflect_chance = 15
armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 20, FIRE = 100, ACID = 100)
max_equip = 6
wreckage = /obj/structure/mecha_wreckage/ripley
internals_req_access = list(ACCESS_ENGINE, ACCESS_ROBOTICS, ACCESS_MINING)
enclosed = FALSE //Normal ripley has an open cockpit design
enter_delay = 10 //can enter in a quarter of the time of other mechs
exit_delay = 10
/// Amount of Goliath hides attached to the mech
var/hides = 0
/// List of all things in Ripley's Cargo Compartment
var/list/cargo = new
/// How much things Ripley can carry in their Cargo Compartment
var/cargo_capacity = 15
/obj/vehicle/sealed/mecha/working/ripley/Move()
. = ..()
update_pressure()
/obj/vehicle/sealed/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage, ignore_threshold = FALSE)
if (!enclosed)
possible_int_damage -= (MECHA_INT_TEMP_CONTROL + MECHA_INT_TANK_BREACH) //if we don't even have an air tank, these two doesn't make a ton of sense.
. = ..()
/obj/vehicle/sealed/mecha/working/ripley/Initialize()
. = ..()
AddComponent(/datum/component/armor_plate,3,/obj/item/stack/sheet/animalhide/goliath_hide,list(MELEE = 10, BULLET = 5, LASER = 5))
/obj/vehicle/sealed/mecha/working/ripley/generate_actions()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/climb_out)
if(enclosed)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_internals, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_cycle_equip, VEHICLE_CONTROL_EQUIPMENT)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/strafe, VEHICLE_CONTROL_DRIVE)
if(max_occupants > 1)
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/swap_seat)
/obj/vehicle/sealed/mecha/working/ripley/Destroy()
for(var/atom/movable/A in cargo)
A.forceMove(drop_location())
step_rand(A)
cargo.Cut()
return ..()
/obj/vehicle/sealed/mecha/working/ripley/mkii
desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection and armor."
name = "\improper APLU MK-II \"Ripley\""
icon_state = "ripleymkii"
fast_pressure_step_in = 2 //step_in while in low pressure conditions
slow_pressure_step_in = 4 //step_in while in normal pressure conditions
movedelay = 4
max_temperature = 30000
max_integrity = 250
armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100)
wreckage = /obj/structure/mecha_wreckage/ripley/mkii
enclosed = TRUE
enter_delay = 40
silicon_icon_state = null
/obj/vehicle/sealed/mecha/working/ripley/firefighter
desc = "Autonomous Power Loader Unit MK-II-F. This model is refitted with additional thermal protection."
name = "\improper APLU \"Firefighter\""
icon_state = "firefighter"
movedelay = 4
fast_pressure_step_in = 2
slow_pressure_step_in = 4
max_temperature = 65000
max_integrity = 250
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100)
max_equip = 5 // More armor, less tools
enclosed = TRUE
enter_delay = 40
/obj/vehicle/sealed/mecha/working/ripley/deathripley
desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE"
name = "\improper DEATH-RIPLEY"
icon_state = "deathripley"
fast_pressure_step_in = 2 //step_in while in low pressure conditions
slow_pressure_step_in = 3 //step_in while in normal pressure conditions
movedelay = 4
lights_power = 7
wreckage = /obj/structure/mecha_wreckage/ripley/deathripley
step_energy_drain = 0
enclosed = TRUE
enter_delay = 40
silicon_icon_state = null
/obj/vehicle/sealed/mecha/working/ripley/deathripley/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill
ME.attach(src)
/obj/vehicle/sealed/mecha/working/ripley/deathripley/real
desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE. FOR REAL"
/obj/vehicle/sealed/mecha/working/ripley/deathripley/real/Initialize()
. = ..()
for(var/obj/item/mecha_parts/mecha_equipment/E in equipment)
E.detach()
qdel(E)
LAZYCLEARLIST(equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/real
ME.attach(src)
/obj/vehicle/sealed/mecha/working/ripley/mining
desc = "An old, dusty mining Ripley."
name = "\improper APLU \"Miner\""
obj_integrity = 75 //Low starting health
/obj/vehicle/sealed/mecha/working/ripley/mining/Initialize()
. = ..()
if(cell)
cell.charge = FLOOR(cell.charge * 0.25, 1) //Starts at very low charge
if(prob(70)) //Maybe add a drill
if(prob(15)) //Possible diamond drill... Feeling lucky?
var/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill/D = new
D.attach(src)
else
var/obj/item/mecha_parts/mecha_equipment/drill/D = new
D.attach(src)
else //Add plasma cutter if no drill
var/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/P = new
P.attach(src)
//Add ore box to cargo
cargo.Add(new /obj/structure/ore_box(src))
//Attach hydraulic clamp
var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new
HC.attach(src)
for(var/obj/item/mecha_parts/mecha_tracking/B in trackers)//Deletes the beacon so it can't be found easily
qdel(B)
var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new
scanner.attach(src)
/obj/vehicle/sealed/mecha/working/ripley/Exit(atom/movable/O)
if(O in cargo)
return 0
return ..()
/obj/vehicle/sealed/mecha/working/ripley/Topic(href, href_list)
..()
if(href_list["drop_from_cargo"])
var/obj/O = locate(href_list["drop_from_cargo"]) in cargo
if(O)
to_chat(occupants, "[icon2html(src, occupants)]<span class='notice'>You unload [O].</span>")
O.forceMove(drop_location())
cargo -= O
log_message("Unloaded [O]. Cargo compartment capacity: [cargo_capacity - src.cargo.len]", LOG_MECHA)
return
/obj/vehicle/sealed/mecha/working/ripley/contents_explosion(severity, target, origin)
for(var/X in cargo)
var/obj/O = X
if(prob(30/severity))
cargo -= O
O.forceMove(drop_location())
. = ..()
/obj/vehicle/sealed/mecha/working/ripley/get_stats_part()
var/output = ..()
output += "<b>Cargo Compartment Contents:</b><div style=\"margin-left: 15px;\">"
if(cargo.len)
for(var/obj/O in cargo)
output += "<a href='?src=[REF(src)];drop_from_cargo=[REF(O)]'>Unload</a> : [O]<br>"
else
output += "Nothing"
output += "</div>"
return output
/obj/vehicle/sealed/mecha/working/ripley/relay_container_resist(mob/living/user, obj/O)
to_chat(user, "<span class='notice'>You lean on the back of [O] and start pushing so it falls out of [src].</span>")
if(do_after(user, 300, target = O))
if(!user || user.stat != CONSCIOUS || user.loc != src || O.loc != src )
return
to_chat(user, "<span class='notice'>You successfully pushed [O] out of [src]!</span>")
O.forceMove(drop_location())
cargo -= O
else
if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
to_chat(user, "<span class='warning'>You fail to push [O] out of [src]!</span>")
/**
* Makes the mecha go faster and halves the mecha drill cooldown if in Lavaland pressure.
*
* Checks for Lavaland pressure, if that works out the mech's speed is equal to fast_pressure_step_in and the cooldown for the mecha drill is halved. If not it uses slow_pressure_step_in and drill cooldown is normal.
*/
/obj/vehicle/sealed/mecha/working/ripley/proc/update_pressure()
var/turf/T = get_turf(loc)
if(lavaland_equipment_pressure_check(T))
movedelay = fast_pressure_step_in
for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment)
drill.equip_cooldown = initial(drill.equip_cooldown) * 0.5
else
movedelay = slow_pressure_step_in
for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment)
drill.equip_cooldown = initial(drill.equip_cooldown)
@@ -0,0 +1,28 @@
/obj/vehicle/sealed/mecha/working
internal_damage_threshold = 60
/obj/vehicle/sealed/mecha/working/Move()
. = ..()
if(.)
collect_ore()
/**
* Handles collecting ore.
*
* Checks for a hydraulic clamp or ore box manager and if it finds an ore box inside them puts ore in the ore box.
*/
/obj/vehicle/sealed/mecha/working/proc/collect_ore()
if((locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in equipment))
var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in contents
if(ore_box)
for(var/obj/item/stack/ore/ore in range(1, src))
if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) //we can reach it and it's in front of us? grab it!
ore.forceMove(ore_box)
/obj/vehicle/sealed/mecha/working/Bump(atom/obstacle)
if(istype(selected, /obj/item/mecha_parts/mecha_equipment/drill) && istype(obstacle, /turf/closed/mineral))
var/obj/item/mecha_parts/mecha_equipment/drill/thedrill = selected
for(var/mob/M in occupants)
thedrill.action(M, obstacle)
break
..()
+3 -1
View File
@@ -47,10 +47,12 @@
mob_exit(M, silent, randomstep)
/obj/vehicle/sealed/proc/mob_exit(mob/M, silent = FALSE, randomstep = FALSE)
SIGNAL_HANDLER
if(!istype(M))
return FALSE
remove_occupant(M)
M.forceMove(exit_location(M))
if(!isAI(M))//This is the ONE mob we dont want to be moved to the vehicle that should be handeled when used
M.forceMove(exit_location(M))
if(randomstep)
var/turf/target_turf = get_step(exit_location(M), pick(GLOB.cardinals))
M.throw_at(target_turf, 5, 10)
+1 -1
View File
@@ -5,7 +5,7 @@
icon_state = "wheelchair"
layer = OBJ_LAYER
max_integrity = 100
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 30) //Wheelchairs aren't super tough yo
armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 20, ACID = 30) //Wheelchairs aren't super tough yo
legs_required = 0 //You'll probably be using this if you don't have legs
canmove = TRUE
density = FALSE //Thought I couldn't fix this one easily, phew