Merge branch 'master' into Projectile_Rework
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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]°K|[tank_temperature - T0C]°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()]°K|[return_temperature() - T0C]°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. (© 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> "
|
||||
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]°C ([patient.bodytemperature*1.8-459.67]°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> [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> [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 "[..()] <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)
|
||||
@@ -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
|
||||
. = ..()
|
||||
@@ -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"
|
||||
@@ -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]°K|[tank_temperature - T0C]°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()]°K|[return_temperature() - T0C]°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. (© 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
|
||||
..()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user