From c20bab52d4a523be55aa99eae116eaae0121ca66 Mon Sep 17 00:00:00 2001 From: Mechoid Date: Wed, 5 Aug 2020 16:20:46 -0700 Subject: [PATCH] Exosuit Modular Internals, The Squeakening --- code/__defines/objects.dm | 10 +- code/datums/autolathe/arms.dm | 24 + code/datums/autolathe/autolathe.dm | 1 + code/datums/autolathe/general.dm | 25 + code/game/machinery/autolathe.dm | 20 +- code/game/mecha/combat/combat.dm | 8 + code/game/mecha/combat/durand.dm | 14 +- code/game/mecha/combat/gygax.dm | 37 +- code/game/mecha/combat/marauder.dm | 76 ++- code/game/mecha/combat/phazon.dm | 26 +- code/game/mecha/components/_component.dm | 155 ++++++ code/game/mecha/components/actuators.dm | 37 ++ code/game/mecha/components/armor.dm | 238 +++++++++ code/game/mecha/components/electrical.dm | 31 ++ code/game/mecha/components/hull.dm | 33 ++ code/game/mecha/components/lifesupport.dm | 28 + code/game/mecha/equipment/mecha_equipment.dm | 5 + .../game/mecha/equipment/tools/armor_melee.dm | 2 + .../mecha/equipment/tools/armor_ranged.dm | 2 + .../mecha/equipment/tools/repair_droid.dm | 19 +- code/game/mecha/equipment/tools/shield.dm | 4 + .../game/mecha/equipment/tools/shield_omni.dm | 4 + code/game/mecha/equipment/tools/speedboost.dm | 10 + .../equipment/weapons/ballistic/mortar.dm | 2 + .../equipment/weapons/ballistic/shotgun.dm | 2 + .../mecha/equipment/weapons/energy/laser.dm | 2 + .../equipment/weapons/explosive/missile.dm | 4 + .../equipment/weapons/fire/flamethrower.dm | 2 + .../equipment/weapons/fire/incendiary.dm | 2 + code/game/mecha/equipment/weapons/weapons.dm | 2 + code/game/mecha/mecha.dm | 484 +++++++++++++++--- code/game/mecha/mecha_actions.dm | 43 +- code/game/mecha/medical/medical.dm | 8 + code/game/mecha/medical/odysseus.dm | 8 +- code/game/mecha/working/ripley.dm | 8 + .../objects/items/weapons/storage/boxes.dm | 10 + .../mob/living/silicon/robot/analyzer.dm | 34 ++ .../projectiles/ammunition/magazines.dm | 9 + code/modules/projectiles/ammunition/rounds.dm | 10 + .../modules/projectiles/projectile/scatter.dm | 26 + code/modules/research/circuitprinter.dm | 2 +- .../research/designs/circuits/circuits.dm | 6 + code/modules/research/designs/weapons.dm | 13 +- code/modules/research/mechfab_designs.dm | 171 ++++++- html/changelogs/mechoid - exointernals.yml | 39 ++ icons/effects/actions_mecha.dmi | Bin 7707 -> 8185 bytes icons/mecha/mech_component.dmi | Bin 0 -> 2220 bytes vorestation.dme | 6 + 48 files changed, 1532 insertions(+), 170 deletions(-) create mode 100644 code/game/mecha/components/_component.dm create mode 100644 code/game/mecha/components/actuators.dm create mode 100644 code/game/mecha/components/armor.dm create mode 100644 code/game/mecha/components/electrical.dm create mode 100644 code/game/mecha/components/hull.dm create mode 100644 code/game/mecha/components/lifesupport.dm create mode 100644 html/changelogs/mechoid - exointernals.yml create mode 100644 icons/mecha/mech_component.dmi diff --git a/code/__defines/objects.dm b/code/__defines/objects.dm index 3d2891a3c5..d6530fecff 100644 --- a/code/__defines/objects.dm +++ b/code/__defines/objects.dm @@ -40,4 +40,12 @@ #define CATALOGUER_REWARD_SUPERHARD 2560 // Very difficult and dangerous, such as scanning the Advanced Dark Gygax. // 5 10 20 40 80 160 -// 10 40 160 640 2560 \ No newline at end of file +// 10 40 160 640 2560 + +// Defines for Exosuit components. + +#define MECH_HULL "Hull" +#define MECH_ACTUATOR "Actuator" +#define MECH_ARMOR "Plating" +#define MECH_GAS "Life Support" +#define MECH_ELECTRIC "Firmware" diff --git a/code/datums/autolathe/arms.dm b/code/datums/autolathe/arms.dm index e170d8c885..53a2f14fac 100644 --- a/code/datums/autolathe/arms.dm +++ b/code/datums/autolathe/arms.dm @@ -33,6 +33,12 @@ path =/obj/item/ammo_casing/a12g/stunshell hidden = 1 +/datum/category_item/autolathe/arms/flechetteshell + name = "ammunition (flechette cartridge, shotgun)" + path =/obj/item/ammo_casing/a12g/flechette + hidden = 1 + man_rating = 2 + ////////////////// /*Ammo magazines*/ ////////////////// @@ -64,6 +70,18 @@ name = "pistol magazine (.45 flash)" path =/obj/item/ammo_magazine/m45/flash +/datum/category_item/autolathe/arms/pistol_45ap + name = "pistol magazine (.45 armor piercing)" + path =/obj/item/ammo_magazine/m45/ap + hidden = 1 + resources = list(DEFAULT_WALL_MATERIAL = 500, MAT_PLASTEEL = 300) + +/datum/category_item/autolathe/arms/pistol_45hp + name = "pistol magazine (.45 hollowpoint)" + path =/obj/item/ammo_magazine/m45/hp + hidden = 1 + resources = list(DEFAULT_WALL_MATERIAL = 500, MAT_PLASTIC = 200) + /datum/category_item/autolathe/arms/pistol_45uzi name = "uzi magazine (.45)" path =/obj/item/ammo_magazine/m45uzi @@ -138,6 +156,12 @@ name = "top-mounted SMG magazine (9mm flash)" path =/obj/item/ammo_magazine/m9mmt/flash +/datum/category_item/autolathe/arms/smg_9mmap + name = "top-mounted SMG magazine (9mm armor piercing)" + path =/obj/item/ammo_magazine/m9mmt/ap + hidden = 1 + man_rating = 2 + /////// 10mm /datum/category_item/autolathe/arms/smg_10mm name = "SMG magazine (10mm)" diff --git a/code/datums/autolathe/autolathe.dm b/code/datums/autolathe/autolathe.dm index 91c9ec37b7..003212fe75 100644 --- a/code/datums/autolathe/autolathe.dm +++ b/code/datums/autolathe/autolathe.dm @@ -71,6 +71,7 @@ var/datum/category_collection/autolathe/autolathe_recipes var/is_stack // Creates multiple of an item if applied to non-stack items var/max_stack var/no_scale + var/man_rating = 0 /datum/category_item/autolathe/dd_SortValue() return name \ No newline at end of file diff --git a/code/datums/autolathe/general.dm b/code/datums/autolathe/general.dm index 891e73fb6b..5ad54b68bf 100644 --- a/code/datums/autolathe/general.dm +++ b/code/datums/autolathe/general.dm @@ -98,6 +98,18 @@ is_stack = TRUE no_scale = TRUE //prevents material duplication exploits +/datum/category_item/autolathe/general/plasteel + name = "plasteel sheets" + path =/obj/item/stack/material/plasteel + is_stack = TRUE + no_scale = TRUE //prevents material duplication exploits + +/datum/category_item/autolathe/general/plastic + name = "plastic sheets" + path =/obj/item/stack/material/plastic + is_stack = TRUE + no_scale = TRUE //prevents material duplication exploits + //TFF 24/12/19 - Let people print more spray bottles if needed. /datum/category_item/autolathe/general/spraybottle name = "spray bottle" @@ -133,6 +145,19 @@ name = "maglight" path =/obj/item/device/flashlight/maglight +<<<<<<< HEAD +======= +/datum/category_item/autolathe/general/ecigcartridge + name = "ecigarette cartridge" + path = /obj/item/weapon/reagent_containers/ecig_cartridge/blank + +/datum/category_item/autolathe/general/idcard + name = "ID Card" + path = /obj/item/weapon/card/id + resources = list(DEFAULT_WALL_MATERIAL = 100, MAT_GLASS = 100, MAT_PLASTIC = 300) + man_rating = 2 + +>>>>>>> 282b42d... Exosuit Modular Internals, The Squeakening (#7329) /datum/category_item/autolathe/general/handcuffs name = "handcuffs" path =/obj/item/weapon/handcuffs diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 1629b77bdd..3e1188198b 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -12,8 +12,8 @@ circuit = /obj/item/weapon/circuitboard/autolathe var/datum/category_collection/autolathe/machine_recipes - var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) - var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) + var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0) + var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0) var/datum/category_group/autolathe/current_category var/hacked = 0 @@ -26,6 +26,9 @@ var/datum/wires/autolathe/wires = null + var/mb_rating = 0 + var/man_rating = 0 + var/filtertext /obj/machinery/autolathe/Initialize() @@ -64,6 +67,9 @@ var/list/material_bottom = list("") for(var/material in stored_material) + if(material != DEFAULT_WALL_MATERIAL && material != MAT_GLASS) // Don't show the Extras unless people care enough to put them in. + if(stored_material[material] <= 0) + continue material_top += "[material]" material_bottom += "[stored_material[material]]/[storage_capacity[material]]" @@ -72,7 +78,9 @@ dat += "

Printable Designs

Showing: [current_category].

" for(var/datum/category_item/autolathe/R in current_category.items) - if(R.hidden && !hacked) + if(R.hidden && !hacked) // Illegal or nonstandard. + continue + if(R.man_rating > man_rating) // Advanced parts. continue if(filtertext && findtext(R.name, filtertext) == 0) continue @@ -311,14 +319,16 @@ //Updates overall lathe storage size. /obj/machinery/autolathe/RefreshParts() ..() - var/mb_rating = 0 - var/man_rating = 0 + mb_rating = 0 + man_rating = 0 for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts) mb_rating += MB.rating for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) man_rating += M.rating storage_capacity[DEFAULT_WALL_MATERIAL] = mb_rating * 25000 + storage_capacity[MAT_PLASTIC] = mb_rating * 20000 + storage_capacity[MAT_PLASTEEL] = mb_rating * 16250 storage_capacity["glass"] = mb_rating * 12500 build_time = 50 / man_rating mat_efficiency = 1.1 - man_rating * 0.1// Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.6. Maximum rating of parts is 5 diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index b5d3351b21..d618d276c3 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -17,6 +17,14 @@ max_special_equip = 1 cargo_capacity = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull/durable, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/reinforced, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + /* /obj/mecha/combat/range_action(target as obj|mob|turf) if(internal_damage&MECHA_INT_CONTROL_LOST) diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm index 5ab43a93ee..aa5a9e000c 100644 --- a/code/game/mecha/combat/durand.dm +++ b/code/game/mecha/combat/durand.dm @@ -5,8 +5,8 @@ initial_icon = "durand" step_in = 4 dir_in = 1 //Facing North. - health = 400 - maxhealth = 400 //Don't forget to update the /old variant if you change this number. + health = 300 + maxhealth = 300 //Don't forget to update the /old variant if you change this number. deflect_chance = 20 damage_absorption = list("brute"=0.5,"fire"=1.1,"bullet"=0.65,"laser"=0.85,"energy"=0.9,"bomb"=0.8) max_temperature = 30000 @@ -23,6 +23,14 @@ max_universal_equip = 1 max_special_equip = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull/durable, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/military, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + defence_mode_possible = 1 /* @@ -73,5 +81,5 @@ /obj/mecha/combat/durand/old/New() ..() health = 25 - maxhealth = 350 //Just slightly worse. + maxhealth = 250 //Just slightly worse. cell.charge = rand(0, (cell.charge/2)) \ No newline at end of file diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index d74b96cf99..0323124c47 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -5,8 +5,8 @@ initial_icon = "gygax" step_in = 3 dir_in = 1 //Facing North. - health = 300 - maxhealth = 300 //Don't forget to update the /old variant if you change this number. + health = 250 + maxhealth = 250 //Don't forget to update the /old variant if you change this number. deflect_chance = 15 damage_absorption = list("brute"=0.75,"fire"=1,"bullet"=0.8,"laser"=0.7,"energy"=0.85,"bomb"=1) max_temperature = 25000 @@ -21,6 +21,14 @@ max_universal_equip = 1 max_special_equip = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull/lightweight, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/marshal, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + overload_possible = 1 //Not quite sure how to move those yet. @@ -58,17 +66,12 @@ max_universal_equip = 1 max_special_equip = 2 -/obj/mecha/combat/gygax/dark/Initialize() - ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/teleporter - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay - ME.attach(src) - return + starting_equipment = list( + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot, + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang, + /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay, + /obj/item/mecha_parts/mecha_equipment/teleporter + ) /obj/mecha/combat/gygax/dark/add_cell(var/obj/item/weapon/cell/C=null) if(C) @@ -101,6 +104,14 @@ max_universal_equip = 1 max_special_equip = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/lightweight, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + var/obj/item/clothing/glasses/hud/health/mech/hud /obj/mecha/combat/gygax/serenity/New() diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index a79dc3fda2..e2c0b9467a 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -5,8 +5,8 @@ icon_state = "marauder" initial_icon = "marauder" step_in = 5 - health = 500 - maxhealth = 500 //Don't forget to update the /old variant if you change this number. + health = 350 + maxhealth = 350 //Don't forget to update the /old variant if you change this number. deflect_chance = 25 damage_absorption = list("brute"=0.5,"fire"=0.7,"bullet"=0.45,"laser"=0.6,"energy"=0.7,"bomb"=0.7) max_temperature = 60000 @@ -29,6 +29,21 @@ zoom_possible = 1 thrusters_possible = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull/durable, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/military, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + + starting_equipment = list( + /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse, + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive, + /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay, + /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster + ) + /obj/mecha/combat/marauder/seraph desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." name = "Seraph" @@ -37,12 +52,20 @@ initial_icon = "seraph" operation_req_access = list(access_cent_creed) step_in = 3 - health = 550 + health = 450 wreckage = /obj/effect/decal/mecha_wreckage/seraph internal_damage_threshold = 20 force = 55 max_equip = 5 + starting_equipment = list( + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot, + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive, + /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay, + /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster, + /obj/item/mecha_parts/mecha_equipment/teleporter + ) + //Note that is the Mauler /obj/mecha/combat/marauder/mauler desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." @@ -53,40 +76,6 @@ wreckage = /obj/effect/decal/mecha_wreckage/mauler mech_faction = MECH_FACTION_SYNDI -//Note that is the default Marauder -/obj/mecha/combat/marauder/Initialize() - ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive - 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) - return - -//Note that this is the seraph. -/obj/mecha/combat/marauder/seraph/Initialize() - ..()//Let it equip whatever is needed. - var/obj/item/mecha_parts/mecha_equipment/ME - if(equipment.len)//Now to remove it and equip anew. - for(ME in equipment) - ME.detach() - qdel(ME) - 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/explosive(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) - return - - //I'll break this down later /obj/mecha/combat/marauder/relaymove(mob/user,direction) if(user != src.occupant) //While not "realistic", this piece is player friendly. @@ -150,17 +139,10 @@ /obj/mecha/combat/marauder/old desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations. This one is particularly worn looking and likely isn't as sturdy." + starting_equipment = null + /obj/mecha/combat/marauder/old/New() ..() health = 25 - maxhealth = 400 //Just slightly worse. + maxhealth = 300 //Just slightly worse. cell.charge = rand(0, (cell.charge/2)) - -/obj/mecha/combat/marauder/old/Initialize() - ..() - var/obj/item/mecha_parts/mecha_equipment/ME - if(equipment.len) - for(ME in equipment) - ME.detach() - qdel(ME) - return \ No newline at end of file diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm index 121bab34f9..17aea92345 100644 --- a/code/game/mecha/combat/phazon.dm +++ b/code/game/mecha/combat/phazon.dm @@ -25,15 +25,24 @@ max_universal_equip = 3 max_special_equip = 4 - phasing_possible = 1 - switch_dmg_type_possible = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull/durable, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/alien, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + + cloak_possible = TRUE + phasing_possible = TRUE + switch_dmg_type_possible = TRUE /obj/mecha/combat/phazon/equipped/Initialize() ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/rcd - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/gravcatapult - ME.attach(src) + starting_equipment = list( + /obj/item/mecha_parts/mecha_equipment/tool/rcd, + /obj/item/mecha_parts/mecha_equipment/gravcatapult + ) return /* Leaving this until we are really sure we don't need it for reference. @@ -95,8 +104,9 @@ max_universal_equip = 2 max_special_equip = 2 - phasing_possible = 1 - switch_dmg_type_possible = 1 + phasing_possible = TRUE + switch_dmg_type_possible = TRUE + cloak_possible = FALSE /obj/mecha/combat/phazon/janus/take_damage(amount, type="brute") ..() diff --git a/code/game/mecha/components/_component.dm b/code/game/mecha/components/_component.dm new file mode 100644 index 0000000000..aadf390c61 --- /dev/null +++ b/code/game/mecha/components/_component.dm @@ -0,0 +1,155 @@ + +/obj/item/mecha_parts/component + name = "mecha component" + icon = 'icons/mecha/mech_component.dmi' + icon_state = "component" + w_class = ITEMSIZE_HUGE + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + + var/component_type = null + + var/obj/mecha/chassis = null + var/start_damaged = FALSE + + var/emp_resistance = 0 // Amount of emp 'levels' removed. + + var/list/required_type = null // List, if it exists. Exosuits meant to use the component (Unique var changes / effects) + + var/integrity + var/integrity_danger_mod = 0.5 // Multiplier for comparison to max_integrity before problems start. + var/max_integrity = 100 + + var/step_delay = 0 + + var/relative_size = 30 // Percent chance for the component to be hit. + + var/internal_damage_flag // If set, the component will toggle the flag on or off if it is destroyed / severely damaged. + +/obj/item/mecha_parts/component/examine(mob/user) + . = ..() + var/show_integrity = round(integrity/max_integrity*100, 0.1) + switch(show_integrity) + if(85 to 100) + . += "It's fully intact." + if(65 to 85) + . += "It's slightly damaged." + if(45 to 65) + . += "It's badly damaged." + if(25 to 45) + . += "It's heavily damaged." + if(2 to 25) + . += "It's falling apart." + if(0 to 1) + . += "It is completely destroyed." + +/obj/item/mecha_parts/component/Initialize() + ..() + integrity = max_integrity + + if(start_damaged) + integrity = round(integrity * integrity_danger_mod) + +/obj/item/mecha_parts/component/Destroy() + detach() + return ..() + +// Damage code. + +/obj/item/mecha_parts/component/emp_act(var/severity = 4) + if(severity + emp_resistance > 4) + return + + severity = clamp(severity + emp_resistance, 1, 4) + + take_damage((4 - severity) * round(integrity * 0.1, 0.1)) + +/obj/item/mecha_parts/component/proc/adjust_integrity(var/amt = 0) + integrity = clamp(integrity + amt, 0, max_integrity) + return + +/obj/item/mecha_parts/component/proc/damage_part(var/dam_amt = 0, var/type = BRUTE) + if(dam_amt <= 0) + return FALSE + + adjust_integrity(-1 * dam_amt) + + if(chassis && internal_damage_flag) + if(get_efficiency() < 0.5) + chassis.check_for_internal_damage(list(internal_damage_flag), TRUE) + + return TRUE + +/obj/item/mecha_parts/component/proc/get_efficiency() + var/integ_limit = round(max_integrity * integrity_danger_mod) + + if(integrity < integ_limit) + var/int_percent = round(integrity / integ_limit, 0.1) + + return int_percent + + return 1 + +// Attach/Detach code. + +/obj/item/mecha_parts/component/proc/attach(var/obj/mecha/target, var/mob/living/user) + if(target) + if(!(component_type in target.internal_components)) + if(user) + to_chat(user, "\The [target] doesn't seem to have anywhere to put \the [src].") + return FALSE + if(target.internal_components[component_type]) + if(user) + to_chat(user, "\The [target] already has a [component_type] installed!") + return FALSE + chassis = target + if(user) + user.drop_from_inventory(src) + forceMove(target) + + if(internal_damage_flag) + if(integrity > (max_integrity * integrity_danger_mod)) + if(chassis.hasInternalDamage(internal_damage_flag)) + chassis.clearInternalDamage(internal_damage_flag) + + else + chassis.check_for_internal_damage(list(internal_damage_flag)) + + chassis.internal_components[component_type] = src + + if(user) + chassis.visible_message("[user] installs \the [src] in \the [chassis].") + return TRUE + return FALSE + +/obj/item/mecha_parts/component/proc/detach() + if(chassis) + chassis.internal_components[component_type] = null + + if(internal_damage_flag && chassis.hasInternalDamage(internal_damage_flag)) // If the module has been removed, it's kind of unfair to keep it causing problems by being damaged. It's nonfunctional either way. + chassis.clearInternalDamage(internal_damage_flag) + + forceMove(get_turf(chassis)) + chassis = null + return TRUE + + +/obj/item/mecha_parts/component/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/stack/nanopaste)) + var/obj/item/stack/nanopaste/NP = W + + if(integrity < max_integrity) + while(integrity < max_integrity && NP) + if(do_after(user, 1 SECOND, src) && NP.use(1)) + adjust_integrity(10) + + return + + return ..() + +// Various procs to handle different calls by Exosuits. IE, movement actions, damage actions, etc. + +/obj/item/mecha_parts/component/proc/get_step_delay() + return step_delay + +/obj/item/mecha_parts/component/proc/handle_move() + return diff --git a/code/game/mecha/components/actuators.dm b/code/game/mecha/components/actuators.dm new file mode 100644 index 0000000000..d814518629 --- /dev/null +++ b/code/game/mecha/components/actuators.dm @@ -0,0 +1,37 @@ + +/obj/item/mecha_parts/component/actuator + name = "mecha actuator" + icon = 'icons/mecha/mech_component.dmi' + icon_state = "motor" + w_class = ITEMSIZE_HUGE + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + + component_type = MECH_ACTUATOR + + start_damaged = FALSE + + emp_resistance = 1 + + required_type = null // List, if it exists. Exosuits meant to use the component. + + integrity_danger_mod = 0.6 // Multiplier for comparison to max_integrity before problems start. + max_integrity = 50 + + internal_damage_flag = MECHA_INT_CONTROL_LOST + + var/strafing_multiplier = 1.5 + +/obj/item/mecha_parts/component/actuator/get_step_delay() + return step_delay + +/obj/item/mecha_parts/component/actuator/hispeed + name = "overclocked mecha actuator" + + step_delay = -1 + + emp_resistance = -1 + + integrity_danger_mod = 0.7 + max_integrity = 60 + + strafing_multiplier = 1.2 diff --git a/code/game/mecha/components/armor.dm b/code/game/mecha/components/armor.dm new file mode 100644 index 0000000000..b64c37bca5 --- /dev/null +++ b/code/game/mecha/components/armor.dm @@ -0,0 +1,238 @@ + +/obj/item/mecha_parts/component/armor + name = "mecha plating" + icon = 'icons/mecha/mech_component.dmi' + icon_state = "armor" + w_class = ITEMSIZE_HUGE + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 2) + + component_type = MECH_ARMOR + + start_damaged = FALSE + + emp_resistance = 4 + + required_type = null // List, if it exists. Exosuits meant to use the component. + + integrity_danger_mod = 0.4 // Multiplier for comparison to max_integrity before problems start. + max_integrity = 120 + + internal_damage_flag = MECHA_INT_TEMP_CONTROL + + step_delay = 1 + + var/deflect_chance = 10 + var/list/damage_absorption = list( + "brute"= 0.8, + "fire"= 1.2, + "bullet"= 0.9, + "laser"= 1, + "energy"= 1, + "bomb"= 1, + "bio"= 1, + "rad"= 1 + ) + + var/damage_minimum = 10 + var/minimum_penetration = 0 + var/fail_penetration_value = 0.66 + +/obj/item/mecha_parts/component/armor/mining + name = "blast-resistant mecha plating" + + step_delay = 2 + max_integrity = 80 + + damage_absorption = list( + "brute"=0.8, + "fire"=0.8, + "bullet"=1.2, + "laser"=1.2, + "energy"=1, + "bomb"=0.5, + "bio"=1, + "rad"=1 + ) + +/obj/item/mecha_parts/component/armor/lightweight + name = "lightweight mecha plating" + + max_integrity = 50 + step_delay = 0 + + damage_absorption = list( + "brute"=1, + "fire"=1.4, + "bullet"=1.1, + "laser"=1.2, + "energy"=1, + "bomb"=1, + "bio"=1, + "rad"=1 + ) + +/obj/item/mecha_parts/component/armor/reinforced + name = "reinforced mecha plating" + + step_delay = 4 + + max_integrity = 80 + + minimum_penetration = 10 + + damage_absorption = list( + "brute"=0.7, + "fire"=1, + "bullet"=0.7, + "laser"=0.85, + "energy"=1, + "bomb"=0.8 + ) + +/obj/item/mecha_parts/component/armor/military + name = "military grade mecha plating" + + step_delay = 6 + + max_integrity = 100 + + emp_resistance = 2 + + required_type = list(/obj/mecha/combat) + + damage_minimum = 15 + minimum_penetration = 25 + + damage_absorption = list( + "brute"=0.5, + "fire"=1.1, + "bullet"=0.65, + "laser"=0.85, + "energy"=0.9, + "bomb"=0.8 + ) + +/obj/item/mecha_parts/component/armor/military/attach(var/obj/mecha/target, var/mob/living/user) + . = ..() + if(.) + var/typepass = FALSE + for(var/type in required_type) + if(istype(chassis, type)) + typepass = TRUE + + if(typepass) + step_delay = 3 + else + step_delay = initial(step_delay) + +/obj/item/mecha_parts/component/armor/marshal + name = "marshal mecha plating" + + step_delay = 5 + + max_integrity = 100 + + emp_resistance = 3 + + deflect_chance = 15 + + minimum_penetration = 10 + + required_type = list(/obj/mecha/combat) + + damage_absorption = list( + "brute"=0.75, + "fire"=1, + "bullet"=0.8, + "laser"=0.7, + "energy"=0.85, + "bomb"=1 + ) + +/obj/item/mecha_parts/component/armor/marshal/attach(var/obj/mecha/target, var/mob/living/user) + . = ..() + if(.) + var/typepass = FALSE + for(var/type in required_type) + if(istype(chassis, type)) + typepass = TRUE + + if(typepass) + step_delay = 2 + else + step_delay = initial(step_delay) + +/obj/item/mecha_parts/component/armor/marshal/reinforced + name = "blackops mecha plating" + + step_delay = 5 + + damage_absorption = list( + "brute"=0.6, + "fire"=0.8, + "bullet"=0.6, + "laser"=0.5, + "energy"=0.65, + "bomb"=0.8 + ) + +/obj/item/mecha_parts/component/armor/military/marauder + name = "cutting edge mecha plating" + + step_delay = 4 + + max_integrity = 150 + + emp_resistance = 3 + + required_type = list(/obj/mecha/combat/marauder) + + deflect_chance = 25 + damage_minimum = 30 + minimum_penetration = 25 + + damage_absorption = list( + "brute"=0.5, + "fire"=0.7, + "bullet"=0.45, + "laser"=0.6, + "energy"=0.7, + "bomb"=0.7 + ) + +/obj/item/mecha_parts/component/armor/military/marauder/attach(var/obj/mecha/target, var/mob/living/user) + . = ..() + if(.) + var/typepass = FALSE + for(var/type in required_type) + if(istype(chassis, type)) + typepass = TRUE + + if(typepass) + step_delay = 1 + else + step_delay = initial(step_delay) + +/obj/item/mecha_parts/component/armor/alien + name = "strange mecha plating" + step_delay = 3 + damage_absorption = list( + "brute"=0.7, + "fire"=0.7, + "bullet"=0.7, + "laser"=0.7, + "energy"=0.7, + "bomb"=0.7 + ) + +/obj/item/mecha_parts/component/armor/alien/attach(var/obj/mecha/target, var/mob/living/user) + . = ..() + if(.) + if(istype(target, /obj/mecha/combat/phazon/janus)) + step_delay = -1 + + else if(istype(target, /obj/mecha/combat/phazon)) + step_delay = -3 + + else + step_delay = initial(step_delay) diff --git a/code/game/mecha/components/electrical.dm b/code/game/mecha/components/electrical.dm new file mode 100644 index 0000000000..de07c96c84 --- /dev/null +++ b/code/game/mecha/components/electrical.dm @@ -0,0 +1,31 @@ + +/obj/item/mecha_parts/component/electrical + name = "mecha electrical harness" + icon = 'icons/mecha/mech_component.dmi' + icon_state = "board" + w_class = ITEMSIZE_HUGE + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + + component_type = MECH_ELECTRIC + + emp_resistance = 1 + + integrity_danger_mod = 0.4 + max_integrity = 40 + + step_delay = 0 + + relative_size = 20 + + internal_damage_flag = MECHA_INT_SHORT_CIRCUIT + + var/charge_cost_mod = 1 + +/obj/item/mecha_parts/component/electrical/high_current + name = "efficient mecha electrical harness" + + emp_resistance = 0 + max_integrity = 30 + + relative_size = 10 + charge_cost_mod = 0.6 diff --git a/code/game/mecha/components/hull.dm b/code/game/mecha/components/hull.dm new file mode 100644 index 0000000000..16d01ad92c --- /dev/null +++ b/code/game/mecha/components/hull.dm @@ -0,0 +1,33 @@ + +/obj/item/mecha_parts/component/hull + name = "mecha hull" + icon = 'icons/mecha/mech_component.dmi' + icon_state = "hull" + w_class = ITEMSIZE_HUGE + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + + component_type = MECH_HULL + + emp_resistance = 0 // Amount of emp 'levels' removed. + + required_type = null // List, if it exists. Exosuits meant to use the component. + + integrity_danger_mod = 0.5 // Multiplier for comparison to max_integrity before problems start. + max_integrity = 50 + + internal_damage_flag = MECHA_INT_FIRE + + step_delay = 2 + +/obj/item/mecha_parts/component/hull/durable + name = "durable mecha hull" + + step_delay = 4 + integrity_danger_mod = 0.3 + max_integrity = 100 + +/obj/item/mecha_parts/component/hull/lightweight + name = "lightweight mecha hull" + + step_delay = 1 + integrity_danger_mod = 0.3 diff --git a/code/game/mecha/components/lifesupport.dm b/code/game/mecha/components/lifesupport.dm new file mode 100644 index 0000000000..d98cefda4d --- /dev/null +++ b/code/game/mecha/components/lifesupport.dm @@ -0,0 +1,28 @@ + +/obj/item/mecha_parts/component/gas + name = "mecha life-support" + icon = 'icons/mecha/mech_component.dmi' + icon_state = "lifesupport" + w_class = ITEMSIZE_HUGE + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + + component_type = MECH_GAS + + emp_resistance = 1 + + integrity_danger_mod = 0.4 + max_integrity = 40 + + step_delay = 0 + + relative_size = 20 + + internal_damage_flag = MECHA_INT_TANK_BREACH + +/obj/item/mecha_parts/component/gas/reinforced + name = "reinforced mecha life-support" + + emp_resistance = 2 + max_integrity = 80 + + relative_size = 40 diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 678ac64910..617af4849f 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -28,6 +28,8 @@ var/ready_sound = 'sound/mecha/mech_reload_default.ogg' //Sound to play once the fire delay passed. var/enable_special = FALSE // Will the tool do its special? + var/step_delay = 0 // Does the component slow/speed up the suit? + /obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(target=1) sleep(equip_cooldown) set_ready_state(1) @@ -273,3 +275,6 @@ /obj/item/mecha_parts/mecha_equipment/proc/MoveAction() //Allows mech equipment to do an action upon the mech moving return + +/obj/item/mecha_parts/mecha_equipment/proc/get_step_delay() // Equipment returns its slowdown or speedboost. + return step_delay diff --git a/code/game/mecha/equipment/tools/armor_melee.dm b/code/game/mecha/equipment/tools/armor_melee.dm index 8390a2cc52..085148d938 100644 --- a/code/game/mecha/equipment/tools/armor_melee.dm +++ b/code/game/mecha/equipment/tools/armor_melee.dm @@ -9,6 +9,8 @@ var/deflect_coeff = 1.15 var/damage_coeff = 0.8 + step_delay = 1 + equip_type = EQUIP_HULL /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/get_equip_info() diff --git a/code/game/mecha/equipment/tools/armor_ranged.dm b/code/game/mecha/equipment/tools/armor_ranged.dm index 4fb3aac32b..5b8d6d8172 100644 --- a/code/game/mecha/equipment/tools/armor_ranged.dm +++ b/code/game/mecha/equipment/tools/armor_ranged.dm @@ -9,6 +9,8 @@ var/deflect_coeff = 1.15 var/damage_coeff = 0.8 + step_delay = 2 + equip_type = EQUIP_HULL /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/handle_projectile_contact(var/obj/item/projectile/Proj, var/inc_damage) diff --git a/code/game/mecha/equipment/tools/repair_droid.dm b/code/game/mecha/equipment/tools/repair_droid.dm index f4f9696aa5..7cd8ebd9ab 100644 --- a/code/game/mecha/equipment/tools/repair_droid.dm +++ b/code/game/mecha/equipment/tools/repair_droid.dm @@ -11,6 +11,8 @@ var/icon/droid_overlay var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH) + step_delay = 1 + equip_type = EQUIP_HULL /obj/item/mecha_parts/mecha_equipment/repair_droid/New() @@ -79,8 +81,23 @@ RD.chassis.clearInternalDamage(int_dam_flag) repaired = 1 break - if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health)) + + var/obj/item/mecha_parts/component/AC = RD.chassis.internal_components[MECH_ARMOR] + var/obj/item/mecha_parts/component/HC = RD.chassis.internal_components[MECH_HULL] + + var/damaged_armor = AC.integrity < AC.max_integrity + + var/damaged_hull = HC.integrity < HC.max_integrity + + if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health) || damaged_armor || damaged_hull) RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health) + + if(AC) + AC.adjust_integrity(round(health_boost * 0.5, 0.5)) + + if(HC) + HC.adjust_integrity(round(health_boost * 0.5, 0.5)) + repaired = 1 if(repaired) if(RD.chassis.use_power(RD.energy_drain)) diff --git a/code/game/mecha/equipment/tools/shield.dm b/code/game/mecha/equipment/tools/shield.dm index 1ceab07945..453c2ba9da 100644 --- a/code/game/mecha/equipment/tools/shield.dm +++ b/code/game/mecha/equipment/tools/shield.dm @@ -7,6 +7,8 @@ energy_drain = 20 range = 0 + step_delay = 1 + var/obj/item/shield_projector/line/exosuit/my_shield = null var/my_shield_type = /obj/item/shield_projector/line/exosuit var/icon/drone_overlay @@ -66,9 +68,11 @@ my_shield.attack_self(chassis.occupant) if(my_shield.active) set_ready_state(0) + step_delay = 4 log_message("Activated.") else set_ready_state(1) + step_delay = 1 log_message("Deactivated.") /obj/item/mecha_parts/mecha_equipment/combat_shield/Topic(href, href_list) diff --git a/code/game/mecha/equipment/tools/shield_omni.dm b/code/game/mecha/equipment/tools/shield_omni.dm index 1d230c4deb..aae68ef4cd 100644 --- a/code/game/mecha/equipment/tools/shield_omni.dm +++ b/code/game/mecha/equipment/tools/shield_omni.dm @@ -9,6 +9,8 @@ energy_drain = OMNI_SHIELD_DRAIN range = 0 + step_delay = 1 + var/obj/item/shield_projector/shields = null var/shield_type = /obj/item/shield_projector/rectangle/mecha @@ -42,9 +44,11 @@ shields.set_on(!shields.active) if(shields.active) set_ready_state(0) + step_delay = 4 log_message("Activated.") else set_ready_state(1) + step_delay = 1 log_message("Deactivated.") /obj/item/mecha_parts/mecha_equipment/omni_shield/Topic(href, href_list) diff --git a/code/game/mecha/equipment/tools/speedboost.dm b/code/game/mecha/equipment/tools/speedboost.dm index 6e7ad06f69..7ffbeaee38 100644 --- a/code/game/mecha/equipment/tools/speedboost.dm +++ b/code/game/mecha/equipment/tools/speedboost.dm @@ -7,6 +7,9 @@ equip_type = EQUIP_HULL + var/slowdown_multiplier = 0.75 // How much does the exosuit multiply its slowdown by if it's the proper type? + +/* /obj/item/mecha_parts/mecha_equipment/speedboost/attach(obj/mecha/M as obj) ..() if(enable_special) @@ -14,6 +17,13 @@ else chassis.step_in = 6 // Improper parts slow the mech down return +*/ + +/obj/item/mecha_parts/mecha_equipment/speedboost/get_step_delay() + if(enable_special) + return -1 + else + return 3 /obj/item/mecha_parts/mecha_equipment/speedboost/detach() chassis.step_in = initial(chassis.step_in) diff --git a/code/game/mecha/equipment/weapons/ballistic/mortar.dm b/code/game/mecha/equipment/weapons/ballistic/mortar.dm index 86928c9da5..c192d0fc9b 100644 --- a/code/game/mecha/equipment/weapons/ballistic/mortar.dm +++ b/code/game/mecha/equipment/weapons/ballistic/mortar.dm @@ -11,6 +11,8 @@ projectile = /obj/item/projectile/arc/fragmentation/mortar projectile_energy_cost = 600 + step_delay = 2 + origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 5, TECH_ILLEGAL = 3) /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/mortar/action_checks(atom/target) diff --git a/code/game/mecha/equipment/weapons/ballistic/shotgun.dm b/code/game/mecha/equipment/weapons/ballistic/shotgun.dm index d2232d0004..e6b12d8ebd 100644 --- a/code/game/mecha/equipment/weapons/ballistic/shotgun.dm +++ b/code/game/mecha/equipment/weapons/ballistic/shotgun.dm @@ -11,6 +11,8 @@ deviation = 0.7 projectile_energy_cost = 25 + step_delay = 2 + origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4) /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot/rigged diff --git a/code/game/mecha/equipment/weapons/energy/laser.dm b/code/game/mecha/equipment/weapons/energy/laser.dm index 8bdcbcf71f..0dfcbd1328 100644 --- a/code/game/mecha/equipment/weapons/energy/laser.dm +++ b/code/game/mecha/equipment/weapons/energy/laser.dm @@ -52,6 +52,8 @@ projectile = /obj/item/projectile/beam/heavylaser fire_sound = 'sound/weapons/lasercannonfire.ogg' + step_delay = 2 + origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4, TECH_MAGNET = 4) /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/rigged diff --git a/code/game/mecha/equipment/weapons/explosive/missile.dm b/code/game/mecha/equipment/weapons/explosive/missile.dm index 1c14a8c1dd..df8cf0c3bb 100644 --- a/code/game/mecha/equipment/weapons/explosive/missile.dm +++ b/code/game/mecha/equipment/weapons/explosive/missile.dm @@ -2,6 +2,8 @@ var/missile_speed = 2 var/missile_range = 30 + step_delay = 2 + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/Fire(atom/movable/AM, atom/target, turf/aimloc) AM.throw_at(target,missile_range, missile_speed, chassis) @@ -19,6 +21,8 @@ missile_range = 15 required_type = /obj/mecha //Why restrict it to just mining or combat mechs? + step_delay = 0 + equip_type = EQUIP_UTILITY /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare/Fire(atom/movable/AM, atom/target, turf/aimloc) diff --git a/code/game/mecha/equipment/weapons/fire/flamethrower.dm b/code/game/mecha/equipment/weapons/fire/flamethrower.dm index f97f598e24..532c35a6b4 100644 --- a/code/game/mecha/equipment/weapons/fire/flamethrower.dm +++ b/code/game/mecha/equipment/weapons/fire/flamethrower.dm @@ -7,6 +7,8 @@ energy_drain = 30 + step_delay = 2 + projectile = /obj/item/projectile/bullet/incendiary/flamethrower/large fire_sound = 'sound/weapons/towelwipe.ogg' diff --git a/code/game/mecha/equipment/weapons/fire/incendiary.dm b/code/game/mecha/equipment/weapons/fire/incendiary.dm index 3d3c174839..ff49d42016 100644 --- a/code/game/mecha/equipment/weapons/fire/incendiary.dm +++ b/code/game/mecha/equipment/weapons/fire/incendiary.dm @@ -16,3 +16,5 @@ projectile_energy_cost = 40 fire_cooldown = 3 origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 5, TECH_PHORON = 2, TECH_ILLEGAL = 1) + + step_delay = 1 diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 355ce629ac..9dccf551c9 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -12,6 +12,8 @@ var/auto_rearm = 0 //Does the weapon reload itself after each shot? required_type = list(/obj/mecha/combat, /obj/mecha/working/hoverpod/combatpod) + step_delay = 1 + equip_type = EQUIP_WEAPON /obj/item/mecha_parts/mecha_equipment/weapon/action_checks(atom/target) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index ca2bcab7b9..130b6f20e6 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -7,6 +7,11 @@ #define MELEE 1 #define RANGED 2 +#define MECHA_OPERATING 0 +#define MECHA_BOLTS_SECURED 1 +#define MECHA_PANEL_LOOSE 2 +#define MECHA_CELL_OPEN 3 +#define MECHA_CELL_OUT 4 #define MECH_FACTION_NT "nano" #define MECH_FACTION_SYNDI "syndi" @@ -48,7 +53,7 @@ var/fail_penetration_value = 0.66 //By how much failing to penetrate reduces your shit. 66% by default. var/obj/item/weapon/cell/cell - var/state = 0 + var/state = MECHA_OPERATING var/list/log = new var/last_message = 0 var/add_req_access = 1 @@ -108,6 +113,24 @@ var/max_universal_equip = 2 var/max_special_equip = 1 + var/list/starting_equipment = null // List containing starting tools. + +// Mech Components, similar to Cyborg, but Bigger. + var/list/internal_components = list( + MECH_HULL = null, + MECH_ACTUATOR = null, + MECH_ARMOR = null, + MECH_GAS = null, + MECH_ELECTRIC = null + ) + var/list/starting_components = list( + /obj/item/mecha_parts/component/hull, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + //Working exosuit vars var/list/cargo = list() var/cargo_capacity = 3 @@ -139,7 +162,7 @@ var/phasing_possible = 0 //This is to allow phasing. var/can_phase = TRUE //This is an internal check during the relevant procs. var/phasing_energy_drain = 200 - + var/switch_dmg_type_possible = 0 //Can you switch damage type? It is mostly for the Phazon and its children. var/smoke_possible = 0 @@ -148,6 +171,8 @@ var/smoke_cooldown = 100 //How long you have between uses. var/datum/effect/effect/system/smoke_spread/smoke_system = new + var/cloak_possible = FALSE // Can this exosuit innately cloak? + ////All of those are for the HUD buttons in the top left. See Grant and Remove procs in mecha_actions. var/datum/action/innate/mecha/mech_eject/eject_action = new @@ -164,10 +189,20 @@ var/datum/action/innate/mecha/mech_cycle_equip/cycle_action = new var/datum/action/innate/mecha/mech_switch_damtype/switch_damtype_action = new var/datum/action/innate/mecha/mech_toggle_phasing/phasing_action = new + var/datum/action/innate/mecha/mech_toggle_cloaking/cloak_action = new var/weapons_only_cycle = FALSE //So combat mechs don't switch to their equipment at times. +/obj/mecha/Initialize() + ..() + for(var/path in starting_components) + var/obj/item/mecha_parts/component/C = new path(src) + C.attach(src) + if(starting_equipment && LAZYLEN(starting_equipment)) + for(var/path in starting_equipment) + var/obj/item/mecha_parts/mecha_equipment/ME = new path(src) + ME.attach(src) /obj/mecha/drain_power(var/drain_check) @@ -245,6 +280,15 @@ else E.forceMove(loc) E.destroy() + + for(var/slot in internal_components) + var/obj/item/mecha_parts/component/C = internal_components[slot] + if(istype(C)) + C.damage_part(rand(10, 20)) + C.detach() + WR.crowbar_salvage += C + C.forceMove(WR) + if(cell) WR.crowbar_salvage += cell cell.forceMove(WR) @@ -256,6 +300,11 @@ for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) E.detach(loc) E.destroy() + for(var/slot in internal_components) + var/obj/item/mecha_parts/component/C = internal_components[slot] + if(istype(C)) + C.detach() + qdel(C) if(cell) qdel(cell) if(internal_tank) @@ -351,6 +400,26 @@ /obj/mecha/examine(mob/user) . = ..() + + var/obj/item/mecha_parts/component/armor/AC = internal_components[MECH_ARMOR] + + var/obj/item/mecha_parts/component/hull/HC = internal_components[MECH_HULL] + + if(AC) + . += "It has [AC] attached. [AC.get_efficiency()<0.5?"It is severely damaged.":""]" + else + . += "It has no armor plating." + + if(HC) + if(!AC || AC.get_efficiency() < 0.7) + . += "It has [HC] attached. [HC.get_efficiency()<0.5?"It is severely damaged.":""]" + else + . += "You cannot tell what type of hull it has." + + else + . += "It does not seem to have a completed hull." + + var/integrity = health/initial(health)*100 switch(integrity) if(85 to 100) @@ -536,6 +605,12 @@ user.forceMove(get_turf(src)) to_chat(user, "You climb out from [src]") return 0 + + var/obj/item/mecha_parts/component/hull/HC = internal_components[MECH_HULL] + if(!HC) + occupant_message("You can't operate an exosuit that doesn't have a hull!") + return + if(connected_port) if(world.time - last_message > 20) src.occupant_message("Unable to move while connected to the air system port") @@ -562,6 +637,44 @@ return call((proc_res["dyndomove"]||src), "dyndomove")(direction) +/obj/mecha/proc/get_step_delay() + var/tally = 0 + + if(overload) + tally = min(1, round(step_in/2)) + + for(var/slot in internal_components) + var/obj/item/mecha_parts/component/C = internal_components[slot] + if(C && C.get_step_delay()) + tally += C.get_step_delay() + + for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) + if(ME.get_step_delay()) + tally += ME.get_step_delay() + + var/obj/item/mecha_parts/component/actuator/actuator = internal_components[MECH_ACTUATOR] + + if(!actuator) // Relying purely on hydraulic pumps. You're going nowhere fast. + tally = 2 SECONDS + + return tally + + tally += 0.5 SECONDS * (1 - actuator.get_efficiency()) // Damaged actuators run slower, slowing as damage increases beyond its threshold. + + if(strafing) + tally = round(tally * actuator.strafing_multiplier) + + for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) + if(istype(ME, /obj/item/mecha_parts/mecha_equipment/speedboost)) + var/obj/item/mecha_parts/mecha_equipment/speedboost/SB = ME + for(var/path in ME.required_type) + if(istype(src, path)) + tally = round(tally * SB.slowdown_multiplier) + break + break + + return max(1, round(tally)) + /obj/mecha/proc/dyndomove(direction) if(!can_move) return 0 @@ -600,7 +713,6 @@ health-- if(health < initial(health) - initial(health)/3) overload = 0 - step_in = initial(step_in) step_energy_drain = initial(step_energy_drain) src.occupant_message("Leg actuators damage threshold exceded. Disabling overload.") @@ -656,7 +768,7 @@ if(!src.check_for_support()) src.pr_inertial_movement.start(list(src,direction)) src.log_message("Movement control lost. Inertial movement started.") - if(do_after(step_in)) + if(do_after(get_step_delay())) can_move = 1 return 1 return 0 @@ -708,7 +820,7 @@ flick("[initial_icon]-phase", src) src.loc = get_step(src,src.dir) src.use_power(phasing_energy_drain) - sleep(step_in*3) + sleep(get_step_delay() * 3) can_phase = TRUE occupant_message("Phazed.") . = ..(obstacle) @@ -785,16 +897,57 @@ update_damage_alerts() if(amount) var/damage = absorbDamage(amount,type) + + damage = components_handle_damage(damage,type) + health -= damage + update_health() log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1) return +/obj/mecha/proc/components_handle_damage(var/damage, var/type = BRUTE) + var/obj/item/mecha_parts/component/armor/AC = internal_components[MECH_ARMOR] + + if(AC) + var/armor_efficiency = AC.get_efficiency() + var/damage_change = armor_efficiency * (damage * 0.5) * AC.damage_absorption[type] + AC.damage_part(damage_change, type) + damage -= damage_change + + var/obj/item/mecha_parts/component/hull/HC = internal_components[MECH_HULL] + + if(HC) + if(HC.integrity) + var/hull_absorb = round(rand(5, 10) / 10, 0.1) * damage + HC.damage_part(hull_absorb, type) + damage -= hull_absorb + + for(var/obj/item/mecha_parts/component/C in (internal_components - list(MECH_HULL, MECH_ARMOR))) + if(prob(C.relative_size)) + var/damage_part_amt = round(damage / 4, 0.1) + C.damage_part(damage_part_amt) + damage -= damage_part_amt + + return damage + +/obj/mecha/proc/get_damage_absorption() + var/obj/item/mecha_parts/component/armor/AC = internal_components[MECH_ARMOR] + + if(!istype(AC)) + return + + else + if(AC.get_efficiency() > 0.25) + return AC.damage_absorption + + return + /obj/mecha/proc/absorbDamage(damage,damage_type) return call((proc_res["dynabsorbdamage"]||src), "dynabsorbdamage")(damage,damage_type) /obj/mecha/proc/dynabsorbdamage(damage,damage_type) - return damage*(listgetindex(damage_absorption,damage_type) || 1) + return damage*(listgetindex(get_damage_absorption(),damage_type) || 1) /obj/mecha/airlock_crush(var/crush_damage) ..() @@ -814,14 +967,24 @@ if(user == occupant) show_radial_occupant(user) return - + user.setClickCooldown(user.get_attack_speed()) src.log_message("Attack by hand/paw. Attacker - [user].",1) + var/obj/item/mecha_parts/component/armor/ArmC = internal_components[MECH_ARMOR] + + var/temp_deflect_chance = deflect_chance + + if(!ArmC) + temp_deflect_chance = 1 + + else + temp_deflect_chance = round(ArmC.get_efficiency() * ArmC.deflect_chance + (defence_mode ? 25 : 0)) + if(istype(user,/mob/living/carbon/human)) var/mob/living/carbon/human/H = user if(H.species.can_shred(user)) - if(!prob(src.deflect_chance)) + if(!prob(temp_deflect_chance)) src.take_damage(15) //The take_damage() proc handles armor values if(prob(25)) //Why would they get free internal damage. At least make it a bit RNG. src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) @@ -838,7 +1001,7 @@ user.visible_message("\The [user] hits \the [src]. Nothing happens.","You hit \the [src] with no visible effect.") src.log_append_to_last("Armor saved.") return - else if ((HULK in user.mutations) && !prob(src.deflect_chance)) + else if ((HULK in user.mutations) && !prob(temp_deflect_chance)) src.take_damage(15) //The take_damage() proc handles armor values if(prob(25)) //Hulks punch hard but lets not give them consistent internal damage. src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) @@ -856,11 +1019,30 @@ //I think this is relative to throws. /obj/mecha/proc/dynhitby(atom/movable/A) + var/obj/item/mecha_parts/component/armor/ArmC = internal_components[MECH_ARMOR] + + var/temp_deflect_chance = deflect_chance + var/temp_damage_minimum = damage_minimum + var/temp_minimum_penetration = minimum_penetration + var/temp_fail_penetration_value = fail_penetration_value + + if(!ArmC) + temp_deflect_chance = 0 + temp_damage_minimum = 0 + temp_minimum_penetration = 0 + temp_fail_penetration_value = 1 + + else + temp_deflect_chance = round(ArmC.get_efficiency() * ArmC.deflect_chance + (defence_mode ? 25 : 0)) + temp_damage_minimum = round(ArmC.get_efficiency() * ArmC.damage_minimum) + temp_minimum_penetration = round(ArmC.get_efficiency() * ArmC.minimum_penetration) + temp_fail_penetration_value = round(ArmC.get_efficiency() * ArmC.fail_penetration_value) + if(istype(A, /obj/item/mecha_parts/mecha_tracking)) A.forceMove(src) src.visible_message("The [A] fastens firmly to [src].") return - if(prob(src.deflect_chance) || istype(A, /mob)) + if(prob(temp_deflect_chance) || istype(A, /mob)) src.occupant_message("\The [A] bounces off the armor.") src.visible_message("\The [A] bounces off \the [src] armor") src.log_append_to_last("Armor saved.") @@ -873,18 +1055,18 @@ var/pass_damage = O.throwforce var/pass_damage_reduc_mod - if(pass_damage <= damage_minimum)//Too little to go through. + if(pass_damage <= temp_damage_minimum)//Too little to go through. src.occupant_message("\The [A] bounces off the armor.") src.visible_message("\The [A] bounces off \the [src] armor") return - else if(O.armor_penetration < minimum_penetration) //If you don't have enough pen, you won't do full damage + else if(O.armor_penetration < temp_minimum_penetration) //If you don't have enough pen, you won't do full damage src.occupant_message("\The [A] struggles to bypass \the [src] armor.") src.visible_message("\The [A] struggles to bypass \the [src] armor") - pass_damage_reduc_mod = fail_penetration_value //This will apply to reduce damage to 2/3 or 66% by default + pass_damage_reduc_mod = temp_fail_penetration_value //This will apply to reduce damage to 2/3 or 66% by default else - src.occupant_message("\The [A] manages to pierces \the [src] armor.") - src.visible_message("\The [A] manages to pierces \the [src] armor") + src.occupant_message("\The [A] manages to pierce \the [src] armor.") +// src.visible_message("\The [A] manages to pierce \the [src] armor") pass_damage_reduc_mod = 1 @@ -911,7 +1093,26 @@ return /obj/mecha/proc/dynbulletdamage(var/obj/item/projectile/Proj) - if(prob(src.deflect_chance)) + var/obj/item/mecha_parts/component/armor/ArmC = internal_components[MECH_ARMOR] + + var/temp_deflect_chance = deflect_chance + var/temp_damage_minimum = damage_minimum + var/temp_minimum_penetration = minimum_penetration + var/temp_fail_penetration_value = fail_penetration_value + + if(!ArmC) + temp_deflect_chance = 0 + temp_damage_minimum = 0 + temp_minimum_penetration = 0 + temp_fail_penetration_value = 1 + + else + temp_deflect_chance = round(ArmC.get_efficiency() * ArmC.deflect_chance + (defence_mode ? 25 : 0)) + temp_damage_minimum = round(ArmC.get_efficiency() * ArmC.damage_minimum) + temp_minimum_penetration = round(ArmC.get_efficiency() * ArmC.minimum_penetration) + temp_fail_penetration_value = round(ArmC.get_efficiency() * ArmC.fail_penetration_value) + + if(prob(temp_deflect_chance)) src.occupant_message("The armor deflects incoming projectile.") src.visible_message("The [src.name] armor deflects the projectile") src.log_append_to_last("Armor saved.") @@ -930,19 +1131,19 @@ for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) pass_damage = ME.handle_projectile_contact(Proj, pass_damage) - if(pass_damage < damage_minimum)//too pathetic to really damage you. + if(pass_damage < temp_damage_minimum)//too pathetic to really damage you. src.occupant_message("The armor deflects incoming projectile.") src.visible_message("The [src.name] armor deflects\the [Proj]") return - else if(Proj.armor_penetration < minimum_penetration) //If you don't have enough pen, you won't do full damage + else if(Proj.armor_penetration < temp_minimum_penetration) //If you don't have enough pen, you won't do full damage src.occupant_message("\The [Proj] struggles to pierce \the [src] armor.") src.visible_message("\The [Proj] struggles to pierce \the [src] armor") - pass_damage_reduc_mod = fail_penetration_value //This will apply to reduce damage to 2/3 or 66% by default + pass_damage_reduc_mod = temp_fail_penetration_value //This will apply to reduce damage to 2/3 or 66% by default else //You go through completely because you use AP. Nice. src.occupant_message("\The [Proj] manages to pierce \the [src] armor.") - src.visible_message("\The [Proj] manages to pierce \the [src] armor") +// src.visible_message("\The [Proj] manages to pierce \the [src] armor") pass_damage_reduc_mod = 1 pass_damage = (pass_damage_reduc_mod*pass_damage)//Apply damage reduction before usage. @@ -961,7 +1162,7 @@ Proj.attack_mob(src.occupant, distance) hit_occupant = 0 else - if(pass_damage > internal_damage_minimum) //Only decently painful attacks trigger a chance of mech damage. + if(pass_damage > internal_damage_minimum) //Only decently painful attacks trigger a chance of mech damage. src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT), 1) Proj.penetrating-- @@ -974,24 +1175,34 @@ //This refer to whenever you are caught in an explosion. /obj/mecha/ex_act(severity) + var/obj/item/mecha_parts/component/armor/ArmC = internal_components[MECH_ARMOR] + + var/temp_deflect_chance = deflect_chance + + if(!ArmC) + temp_deflect_chance = 0 + + else + temp_deflect_chance = round(ArmC.get_efficiency() * ArmC.deflect_chance + (defence_mode ? 25 : 0)) + src.log_message("Affected by explosion of severity: [severity].",1) - if(prob(src.deflect_chance)) + if(prob(temp_deflect_chance)) severity++ src.log_append_to_last("Armor saved, changing severity to [severity].") switch(severity) if(1.0) - qdel(src) + src.take_damage(initial(src.health), "bomb") if(2.0) if (prob(30)) - qdel(src) + src.take_damage(initial(src.health), "bomb") else - src.take_damage(initial(src.health)/2) //The take_damage() proc handles armor values + src.take_damage(initial(src.health)/2, "bomb") src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) if(3.0) if (prob(5)) qdel(src) else - src.take_damage(initial(src.health)/5) //The take_damage() proc handles armor values + src.take_damage(initial(src.health)/5, "bomb") src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) return @@ -1038,20 +1249,39 @@ src.log_message("Attacked by [W]. Attacker - [user]") var/pass_damage_reduc_mod //Modifer for failing to bring AP. - if(prob(src.deflect_chance)) //Does your attack get deflected outright. + var/obj/item/mecha_parts/component/armor/ArmC = internal_components[MECH_ARMOR] + + var/temp_deflect_chance = deflect_chance + var/temp_damage_minimum = damage_minimum + var/temp_minimum_penetration = minimum_penetration + var/temp_fail_penetration_value = fail_penetration_value + + if(!ArmC) + temp_deflect_chance = 0 + temp_damage_minimum = 0 + temp_minimum_penetration = 0 + temp_fail_penetration_value = 1 + + else + temp_deflect_chance = round(ArmC.get_efficiency() * ArmC.deflect_chance + (defence_mode ? 25 : 0)) + temp_damage_minimum = round(ArmC.get_efficiency() * ArmC.damage_minimum) + temp_minimum_penetration = round(ArmC.get_efficiency() * ArmC.minimum_penetration) + temp_fail_penetration_value = round(ArmC.get_efficiency() * ArmC.fail_penetration_value) + + if(prob(temp_deflect_chance)) //Does your attack get deflected outright. src.occupant_message("\The [W] bounces off [src.name].") to_chat(user, "\The [W] bounces off [src.name].") src.log_append_to_last("Armor saved.") - else if(W.force < damage_minimum) //Is your attack too PATHETIC to do anything. 3 damage to a person shouldn't do anything to a mech. + else if(W.force < temp_damage_minimum) //Is your attack too PATHETIC to do anything. 3 damage to a person shouldn't do anything to a mech. src.occupant_message("\The [W] bounces off the armor.") src.visible_message("\The [W] bounces off \the [src] armor") return - else if(W.armor_penetration < minimum_penetration) //If you don't have enough pen, you won't do full damage + else if(W.armor_penetration < temp_minimum_penetration) //If you don't have enough pen, you won't do full damage src.occupant_message("\The [W] struggles to bypass \the [src] armor.") src.visible_message("\The [W] struggles to bypass \the [src] armor") - pass_damage_reduc_mod = fail_penetration_value //This will apply to reduce damage to 2/3 or 66% by default + pass_damage_reduc_mod = temp_fail_penetration_value //This will apply to reduce damage to 2/3 or 66% by default else pass_damage_reduc_mod = 1 //Just making sure. @@ -1080,6 +1310,11 @@ to_chat(user, "[src]-MMI interface initialization failed.") return + if(istype(W, /obj/item/device/robotanalyzer)) + var/obj/item/device/robotanalyzer/RA = W + RA.do_scan(src, user) + return + if(istype(W, /obj/item/mecha_parts/mecha_equipment)) var/obj/item/mecha_parts/mecha_equipment/E = W spawn() @@ -1090,6 +1325,20 @@ else to_chat(user, "You were unable to attach [W] to [src]") return + + if(istype(W, /obj/item/mecha_parts/component) && state == MECHA_CELL_OUT) + var/obj/item/mecha_parts/component/MC = W + spawn() + if(MC.attach(src)) + user.drop_item() + MC.forceMove(src) + user.visible_message("[user] installs \the [W] in \the [src]", "You install \the [W] in \the [src].") + return + + if(istype(W, /obj/item/weapon/card/robot)) + var/obj/item/weapon/card/robot/RoC = W + return attackby(RoC.dummy_card, user) + if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) if(add_req_access || maint_access) if(internals_access_allowed(usr)) @@ -1106,23 +1355,39 @@ else to_chat(user, "Maintenance protocols disabled by operator.") else if(W.is_wrench()) - if(state==1) - state = 2 + if(state==MECHA_BOLTS_SECURED) + state = MECHA_PANEL_LOOSE to_chat(user, "You undo the securing bolts.") - else if(state==2) - state = 1 + else if(state==MECHA_PANEL_LOOSE) + state = MECHA_BOLTS_SECURED to_chat(user, "You tighten the securing bolts.") return else if(W.is_crowbar()) - if(state==2) - state = 3 + if(state==MECHA_PANEL_LOOSE) + state = MECHA_CELL_OPEN to_chat(user, "You open the hatch to the power unit") - else if(state==3) - state=2 + else if(state==MECHA_CELL_OPEN) + state=MECHA_PANEL_LOOSE to_chat(user, "You close the hatch to the power unit") + else if(state==MECHA_CELL_OUT) + var/list/removable_components = list() + for(var/slot in internal_components) + var/obj/item/mecha_parts/component/MC = internal_components[slot] + if(istype(MC)) + removable_components[MC.name] = MC + else + to_chat(user, "\The [src] appears to be missing \the [slot].") + + var/remove = input(user, "Which component do you want to pry out?", "Remove Component") as null|anything in removable_components + if(!remove) + return + + var/obj/item/mecha_parts/component/RmC = removable_components[remove] + RmC.detach() + return else if(istype(W, /obj/item/stack/cable_coil)) - if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + if(state >= MECHA_CELL_OPEN && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) var/obj/item/stack/cable_coil/CC = W if(CC.use(2)) clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) @@ -1134,19 +1399,19 @@ if(hasInternalDamage(MECHA_INT_TEMP_CONTROL)) clearInternalDamage(MECHA_INT_TEMP_CONTROL) to_chat(user, "You repair the damaged temperature controller.") - else if(state==3 && src.cell) + else if(state==MECHA_CELL_OPEN && src.cell) src.cell.forceMove(src.loc) src.cell = null - state = 4 + state = MECHA_CELL_OUT to_chat(user, "You unscrew and pry out the powercell.") src.log_message("Powercell removed") - else if(state==4 && src.cell) - state=3 + else if(state==MECHA_CELL_OUT && src.cell) + state=MECHA_CELL_OPEN to_chat(user, "You screw the cell in place") return else if(istype(W, /obj/item/device/multitool)) - if(state>=3 && src.occupant) + if(state>=MECHA_CELL_OPEN && src.occupant) to_chat(user, "You attempt to eject the pilot using the maintenance controls.") if(src.occupant.stat) src.go_out() @@ -1158,7 +1423,7 @@ return else if(istype(W, /obj/item/weapon/cell)) - if(state==4) + if(state==MECHA_CELL_OUT) if(!src.cell) to_chat(user, "You install the powercell") user.drop_item() @@ -1191,6 +1456,28 @@ user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src]") return + else if(istype(W,/obj/item/stack/nanopaste)) + if(state >= MECHA_PANEL_LOOSE) + var/obj/item/stack/nanopaste/NP = W + + for(var/slot in internal_components) + var/obj/item/mecha_parts/component/C = internal_components[slot] + + if(C) + + if(C.integrity < C.max_integrity) + while(C.integrity < C.max_integrity && NP && do_after(user, 1 SECOND, src)) + if(NP.use(1)) + C.adjust_integrity(10) + + to_chat(user, "You repair damage to \the [C].") + + return + + else + to_chat(user, "You can't reach \the [src]'s internal components.") + return + else call((proc_res["dynattackby"]||src), "dynattackby")(W,user) /* @@ -1299,7 +1586,8 @@ return /obj/mecha/remove_air(amount) - if(use_internal_tank) + var/obj/item/mecha_parts/component/gas/GC = internal_components[MECH_GAS] + if(use_internal_tank && (GC && prob(GC.get_efficiency() * 100))) return cabin_air.remove(amount) else var/turf/T = get_turf(src) @@ -1314,7 +1602,8 @@ /obj/mecha/proc/return_pressure() . = 0 - if(use_internal_tank) + var/obj/item/mecha_parts/component/gas/GC = internal_components[MECH_GAS] + if(use_internal_tank && (GC && prob(GC.get_efficiency() * 100))) . = cabin_air.return_pressure() else var/datum/gas_mixture/t_air = get_turf_air() @@ -1325,7 +1614,8 @@ //skytodo: //No idea what you want me to do here, mate. /obj/mecha/proc/return_temperature() . = 0 - if(use_internal_tank) + var/obj/item/mecha_parts/component/gas/GC = internal_components[MECH_GAS] + if(use_internal_tank && (GC && prob(GC.get_efficiency() * 100))) . = cabin_air.temperature else var/datum/gas_mixture/t_air = get_turf_air() @@ -1380,13 +1670,17 @@ set category = "Exosuit Interface" set src = usr.loc set popup_menu = 0 - + if(!occupant) return - + if(usr != occupant) return - + + var/obj/item/mecha_parts/component/gas/GC = internal_components[MECH_GAS] + if(!GC) + return + for(var/turf/T in locs) var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector) in T if(possible_port) @@ -1407,13 +1701,13 @@ set category = "Exosuit Interface" set src = usr.loc set popup_menu = 0 - + if(!occupant) return - + if(usr != occupant) return - + if(disconnect()) occupant_message("[name] disconnects from the port.") verbs -= /obj/mecha/verb/disconnect_from_port @@ -1449,6 +1743,16 @@ /obj/mecha/proc/internal_tank() if(usr!=src.occupant) return + + var/obj/item/mecha_parts/component/gas/GC = internal_components[MECH_GAS] + if(!GC) + to_chat(occupant, "The life support systems don't seem to respond.") + return + + if(!prob(GC.get_efficiency() * 100)) + to_chat(occupant, "\The [GC] shudders and barks, before returning to how it was before.") + return + use_internal_tank = !use_internal_tank src.occupant_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].") src.log_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].") @@ -1579,6 +1883,8 @@ verbs -= /obj/mecha/verb/toggle_phasing if(!switch_dmg_type_possible) verbs -= /obj/mecha/verb/switch_damtype + if(!cloak_possible) + verbs -= /obj/mecha/verb/toggle_cloak occupant.in_enclosed_vehicle = 1 //Useful for when you need to know if someone is in a mecho. update_cell_alerts() @@ -1697,8 +2003,13 @@ /obj/mecha/proc/internals_access_allowed(mob/living/carbon/human/H) - for(var/atom/ID in list(H.get_active_hand(), H.wear_id, H.belt)) - if(src.check_access(ID,src.internals_req_access)) + if(istype(H)) + for(var/atom/ID in list(H.get_active_hand(), H.wear_id, H.belt)) + if(src.check_access(ID,src.internals_req_access)) + return 1 + else if(istype(H, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = H + if(src.check_access(R.idcard,src.internals_req_access)) return 1 return 0 @@ -1799,9 +2110,15 @@ var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None" var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown" var/cabin_pressure = round(return_pressure(),0.01) + + var/obj/item/mecha_parts/component/hull/HC = internal_components[MECH_HULL] + var/obj/item/mecha_parts/component/armor/AC = internal_components[MECH_ARMOR] + var/output = {"[report_internal_damage()] + Armor Integrity: [AC?"[round(AC.integrity / AC.max_integrity * 100, 0.1)]%":"ARMOR MISSING"]
+ Hull Integrity: [HC?"[round(HC.integrity / HC.max_integrity * 100, 0.1)]%":"HULL MISSING"]
[integrity<30?"DAMAGE LEVEL CRITICAL
":null] - Integrity: [integrity]%
+ Chassis Integrity: [integrity]%
Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
Air source: [use_internal_tank?"Internal Airtank":"Environment"]
Airtank pressure: [tank_pressure]kPa
@@ -1888,6 +2205,7 @@ output += "Universal Module: [W.name] Detach
" for(var/obj/item/mecha_parts/mecha_equipment/W in special_equipment) output += "Special Module: [W.name] Detach
" +<<<<<<< HEAD for(var/obj/item/mecha_parts/mecha_equipment/W in micro_utility_equipment) // VOREstation Edit - Adds micro equipent to the menu output += "Micro Utility Module: [W.name] Detach
" for(var/obj/item/mecha_parts/mecha_equipment/W in micro_weapon_equipment) @@ -1901,6 +2219,15 @@ Available special slots: [max_special_equip-special_equipment.len]
"} +======= + output += {"Available hull slots: [max_hull_equip-hull_equipment.len]
+ Available weapon slots: [max_weapon_equip-weapon_equipment.len]
+ Available utility slots: [max_utility_equip-utility_equipment.len]
+ Available universal slots: [max_universal_equip-universal_equipment.len]
+ Available special slots: [max_special_equip-special_equipment.len]
+ + "} +>>>>>>> 282b42d... Exosuit Modular Internals, The Squeakening (#7329) return output /obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html @@ -2109,15 +2436,15 @@ if(!in_range(src, usr)) return var/mob/user = top_filter.getMob("user") if(user) - if(state==0) - state = 1 + if(state==MECHA_OPERATING) + state = MECHA_BOLTS_SECURED to_chat(user, "The securing bolts are now exposed.") - else if(state==1) - state = 0 + else if(state==MECHA_BOLTS_SECURED) + state = MECHA_OPERATING to_chat(user, "The securing bolts are now hidden.") output_maintenance_dialog(top_filter.getObj("id_card"),user) return - if(href_list["set_internal_tank_valve"] && state >=1) + if(href_list["set_internal_tank_valve"] && state >=MECHA_BOLTS_SECURED) if(!in_range(src, usr)) return var/mob/user = top_filter.getMob("user") if(user) @@ -2125,7 +2452,7 @@ if(new_pressure) internal_tank_valve = new_pressure to_chat(user, "The internal pressure valve has been set to [internal_tank_valve]kPa.") - if(href_list["remove_passenger"] && state >= 1) + if(href_list["remove_passenger"] && state >= MECHA_BOLTS_SECURED) var/mob/user = top_filter.getMob("user") var/list/passengers = list() for (var/obj/item/mecha_parts/mecha_equipment/tool/passenger/P in contents) @@ -2284,6 +2611,13 @@ /obj/mecha/proc/dynusepower(amount) update_cell_alerts() + var/obj/item/mecha_parts/component/electrical/EC = internal_components[MECH_ELECTRIC] + + if(EC) + amount = amount * (2 - EC.get_efficiency()) * EC.charge_cost_mod + else + amount *= 5 + if(get_charge()) cell.use(amount) return 1 @@ -2291,6 +2625,13 @@ /obj/mecha/proc/give_power(amount) update_cell_alerts() + var/obj/item/mecha_parts/component/electrical/EC = internal_components[MECH_ELECTRIC] + + if(!EC) + amount /= 4 + else + amount *= EC.get_efficiency() + if(!isnull(get_charge())) cell.give(amount) return 1 @@ -2306,6 +2647,19 @@ //This is for mobs mostly. /obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message) + var/obj/item/mecha_parts/component/armor/ArmC = internal_components[MECH_ARMOR] + + var/temp_deflect_chance = deflect_chance + var/temp_damage_minimum = damage_minimum + + if(!ArmC) + temp_deflect_chance = 1 + temp_damage_minimum = 0 + + else + temp_deflect_chance = round(ArmC.get_efficiency() * ArmC.deflect_chance + (defence_mode ? 25 : 0)) + temp_damage_minimum = round(ArmC.get_efficiency() * ArmC.damage_minimum) + user.setClickCooldown(user.get_attack_speed()) if(!damage) return 0 @@ -2313,14 +2667,14 @@ src.log_message("Attacked. Attacker - [user].",1) user.do_attack_animation(src) - if(prob(src.deflect_chance))//Deflected + if(prob(temp_deflect_chance))//Deflected src.log_append_to_last("Armor saved.") src.occupant_message("\The [user]'s attack is stopped by the armor.") visible_message("\The [user] rebounds off [src.name]'s armor!") user.attack_log += text("\[[time_stamp()]\] attacked [src.name]") playsound(src, 'sound/weapons/slash.ogg', 50, 1, -1) - else if(damage < damage_minimum)//Pathetic damage levels just don't harm MECH. + else if(damage < temp_damage_minimum)//Pathetic damage levels just don't harm MECH. src.occupant_message("\The [user]'s doesn't dent \the [src] paint.") src.visible_message("\The [user]'s attack doesn't dent \the [src] armor") src.log_append_to_last("Armor saved.") diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm index 33307c77d3..c70c3b9b83 100644 --- a/code/game/mecha/mecha_actions.dm +++ b/code/game/mecha/mecha_actions.dm @@ -3,7 +3,7 @@ //THIS FILE CONTAINS THE CODE TO ADD THE HUD BUTTONS AND THE MECH ACTIONS THEMSELVES. // // -// I better get some free food for this.. +// I better get some free food for this.. @@ -35,7 +35,9 @@ phasing_action.Grant(user, src) if(switch_dmg_type_possible) switch_damtype_action.Grant(user, src) - + if(cloak_possible) + cloak_action.Grant(user, src) + /obj/mecha/proc/RemoveActions(mob/living/user, human_occupant = 0) if(human_occupant) eject_action.Remove(user, src) @@ -51,8 +53,8 @@ thrusters_action.Remove(user, src) phasing_action.Remove(user, src) switch_damtype_action.Remove(user, src) - overload_action.Remove(user, src) - + overload_action.Remove(user, src) + cloak_action.Remove(user, src) // @@ -242,6 +244,15 @@ +/datum/action/innate/mecha/mech_toggle_cloaking + name = "Toggle Mech phasing" + button_icon_state = "mech_phasing_off" + +/datum/action/innate/mecha/mech_toggle_cloaking/Activate() + button_icon_state = "mech_phasing_[chassis.cloaked ? "off" : "on"]" + button.UpdateIcon() + chassis.toggle_cloaking() + ///// @@ -293,12 +304,10 @@ return if(overload) overload = 0 - step_in = initial(step_in) step_energy_drain = initial(step_energy_drain) src.occupant_message("You disable leg actuators overload.") else overload = 1 - step_in = min(1, round(step_in/2)) step_energy_drain = step_energy_drain*overload_coeff src.occupant_message("You enable leg actuators overload.") src.log_message("Toggled leg actuators overload.") @@ -324,7 +333,7 @@ if(smoke_ready) smoke_reserve-- //Remove ammo src.occupant_message("Smoke fired. [smoke_reserve] usages left.") - + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.attach(src) smoke.set_up(10, 0, usr.loc) @@ -422,6 +431,25 @@ return +/obj/mecha/verb/toggle_cloak() + set category = "Exosuit Interface" + set name = "Toggle cloaking" + set src = usr.loc + set popup_menu = 0 + toggle_cloaking() + +/obj/mecha/proc/toggle_cloaking() + if(usr!=src.occupant) + return + + if(cloaked) + uncloak() + else + cloak() + + src.occupant_message("En":"#f00\">Dis"]abled cloaking.") + return + /obj/mecha/verb/toggle_weapons_only_cycle() set category = "Exosuit Interface" set name = "Toggle weapons only cycling" @@ -435,4 +463,3 @@ weapons_only_cycle = !weapons_only_cycle src.occupant_message("En":"#f00\">Dis"]abled weapons only cycling.") return - diff --git a/code/game/mecha/medical/medical.dm b/code/game/mecha/medical/medical.dm index 6e9dee5047..973ddec3fc 100644 --- a/code/game/mecha/medical/medical.dm +++ b/code/game/mecha/medical/medical.dm @@ -9,6 +9,14 @@ cargo_capacity = 1 + starting_components = list( + /obj/item/mecha_parts/component/hull, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/lightweight, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + /obj/mecha/medical/Initialize() . = ..() var/turf/T = get_turf(src) diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm index 00be6d3c3f..dbba0cd251 100644 --- a/code/game/mecha/medical/odysseus.dm +++ b/code/game/mecha/medical/odysseus.dm @@ -1,4 +1,4 @@ -/obj/mecha/medical/odysseus/ +/obj/mecha/medical/odysseus desc = "These exosuits are developed and produced by Vey-Med. (© All rights reserved)." name = "Odysseus" catalogue_data = list( @@ -9,8 +9,8 @@ initial_icon = "odysseus" step_in = 2 max_temperature = 15000 - health = 120 - maxhealth = 120 + health = 70 + maxhealth = 70 wreckage = /obj/effect/decal/mecha_wreckage/odysseus internal_damage_threshold = 35 deflect_chance = 15 @@ -139,5 +139,5 @@ /obj/mecha/medical/odysseus/old/New() ..() health = 25 - maxhealth = 100 //Just slightly worse. + maxhealth = 50 //Just slightly worse. cell.charge = rand(0, (cell.charge/2)) \ No newline at end of file diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index 5bfe3b4395..86405b6934 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -14,6 +14,14 @@ minimum_penetration = 10 + starting_components = list( + /obj/item/mecha_parts/component/hull/durable, + /obj/item/mecha_parts/component/actuator, + /obj/item/mecha_parts/component/armor/mining, + /obj/item/mecha_parts/component/gas, + /obj/item/mecha_parts/component/electrical + ) + /obj/mecha/working/ripley/Destroy() for(var/atom/movable/A in src.cargo) A.loc = loc diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 3ef882c381..96e4c87da3 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -199,6 +199,16 @@ /obj/item/weapon/storage/box/empshells/large starts_with = list(/obj/item/ammo_casing/a12g/emp = 16) +/obj/item/weapon/storage/box/flechetteshells + name = "box of shotgun flechettes" + desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death." + icon_state = "lethalslug_box" + item_state_slots = list(slot_r_hand_str = "syringe_kit", slot_l_hand_str = "syringe_kit") + starts_with = list(/obj/item/ammo_casing/a12g/flechette = 8) + +/obj/item/weapon/storage/box/flechetteshells/large + starts_with = list(/obj/item/ammo_casing/a12g/flechette = 16) + /obj/item/weapon/storage/box/sniperammo name = "box of 14.5mm shells" desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death." diff --git a/code/modules/mob/living/silicon/robot/analyzer.dm b/code/modules/mob/living/silicon/robot/analyzer.dm index f1b2d76eec..e946c7999c 100644 --- a/code/modules/mob/living/silicon/robot/analyzer.dm +++ b/code/modules/mob/living/silicon/robot/analyzer.dm @@ -34,6 +34,8 @@ scan_type = "robot" else if(istype(M, /mob/living/carbon/human)) scan_type = "prosthetics" + else if(istype(M, /obj/mecha)) + scan_type = "mecha" else to_chat(user, "You can't analyze non-robotic things!") return @@ -95,5 +97,37 @@ if(!organ_found) to_chat(user, "No prosthetics located.") + if("mecha") + + var/obj/mecha/Mecha = M + + var/integrity = Mecha.health/initial(Mecha.health)*100 + var/cell_charge = Mecha.get_charge() + var/tank_pressure = Mecha.internal_tank ? round(Mecha.internal_tank.return_pressure(),0.01) : "None" + var/tank_temperature = Mecha.internal_tank ? Mecha.internal_tank.return_temperature() : "Unknown" + var/cabin_pressure = round(Mecha.return_pressure(),0.01) + + var/output = {"Analyzing Results for \the [Mecha]:
+ Chassis Integrity: [integrity]%
+ Powercell charge: [isnull(cell_charge)?"No powercell installed":"[Mecha.cell.percent()]%"]
+ Air source: [Mecha.use_internal_tank?"Internal Airtank":"Environment"]
+ Airtank pressure: [tank_pressure]kPa
+ Airtank temperature: [tank_temperature]K|[tank_temperature - T0C]°C
+ Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
+ Cabin temperature: [Mecha.return_temperature()]K|[Mecha.return_temperature() - T0C]°C
+ DNA Lock: [Mecha.dna?"Mecha.dna":"Not Found"]
+ "} + + to_chat(user, output) + to_chat(user, "
") + to_chat(user, "Internal Diagnostics:") + for(var/slot in Mecha.internal_components) + var/obj/item/mecha_parts/component/MC = Mecha.internal_components[slot] + to_chat(user, "[MC?"[slot]: [MC] [round((MC.integrity / MC.max_integrity) * 100, 0.1)]% integrity. [MC.get_efficiency() * 100] Operational capacity.":"[slot]: Component Not Found"]") + + to_chat(user, "
") + to_chat(user, "General Statistics:") + to_chat(user, "Movement Weight: [Mecha.get_step_delay()]
") + src.add_fingerprint(user) return diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 7ccdbfc9ba..1d08811bae 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -88,6 +88,10 @@ name = "magazine (.45 AP)" ammo_type = /obj/item/ammo_casing/a45/ap +/obj/item/ammo_magazine/m45/hp + name = "magazine (.45 HP)" + ammo_type = /obj/item/ammo_casing/a45/hp + /obj/item/ammo_magazine/box/emp/b45 name = "ammunition box (.45 haywire)" ammo_type = /obj/item/ammo_casing/a45/emp @@ -293,6 +297,11 @@ name = "top mounted magazine (9mm practice)" ammo_type = /obj/item/ammo_casing/a9mm/practice +/obj/item/ammo_magazine/m9mmt/ap + name = "top mounted magazine (9mm armor piercing)" + ammo_type = /obj/item/ammo_casing/a9mm/ap + matter = list(DEFAULT_WALL_MATERIAL = 1000, MAT_PLASTEEL = 2000) + /obj/item/ammo_magazine/m9mmp90 name = "large capacity top mounted magazine (9mm armor-piercing)" icon_state = "p90" diff --git a/code/modules/projectiles/ammunition/rounds.dm b/code/modules/projectiles/ammunition/rounds.dm index b83d7ad235..fa6c5d21aa 100644 --- a/code/modules/projectiles/ammunition/rounds.dm +++ b/code/modules/projectiles/ammunition/rounds.dm @@ -131,6 +131,7 @@ desc = "A .45 Armor-Piercing bullet casing." icon_state = "r-casing" projectile_type = /obj/item/projectile/bullet/pistol/medium/ap + matter = list(DEFAULT_WALL_MATERIAL = 50, MAT_PLASTEEL = 25) /obj/item/ammo_casing/a45/practice desc = "A .45 practice bullet casing." @@ -160,6 +161,7 @@ /obj/item/ammo_casing/a45/hp desc = "A .45 hollow-point bullet casing." projectile_type = /obj/item/projectile/bullet/pistol/medium/hp + matter = list(DEFAULT_WALL_MATERIAL = 60, MAT_PLASTIC = 15) /* * 10mm @@ -246,6 +248,14 @@ // projectile_type = /obj/item/projectile/bullet/shotgun/ion matter = list(DEFAULT_WALL_MATERIAL = 360, "uranium" = 240) +/obj/item/ammo_casing/a12g/flechette + name = "shotgun flechette" + desc = "A 12 gauge flechette cartidge, also known as nailshot." + icon_state = "slshell" + caliber = "12g" + projectile_type = /obj/item/projectile/scatter/flechette + matter = list(DEFAULT_WALL_MATERIAL = 360, MAT_PLASTEEL = 100) + /* * 7.62mm */ diff --git a/code/modules/projectiles/projectile/scatter.dm b/code/modules/projectiles/projectile/scatter.dm index 4b0511d0b4..b3900f8429 100644 --- a/code/modules/projectiles/projectile/scatter.dm +++ b/code/modules/projectiles/projectile/scatter.dm @@ -27,6 +27,10 @@ /obj/item/projectile/bullet/pellet/shotgun/flak = 3 ) +/* + * Energy + */ + /obj/item/projectile/scatter/laser damage = 40 @@ -61,6 +65,12 @@ /obj/item/projectile/bullet/shotgun/ion = 3 ) + +/* + * Flame + */ + + /obj/item/projectile/scatter/flamethrower damage = 5 submunition_spread_max = 100 @@ -70,3 +80,19 @@ submunitions = list( /obj/item/projectile/bullet/incendiary/flamethrower/tiny = 7 ) + + +/* + * Ballistic + */ + + +/obj/item/projectile/scatter/flechette + damage = 60 + + submunition_spread_max = 40 + submunition_spread_min = 10 + + submunitions = list( + /obj/item/projectile/bullet/magnetic/flechette/small = 4 + ) diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm index 468c7ff6bb..d0aaebb7d8 100644 --- a/code/modules/research/circuitprinter.dm +++ b/code/modules/research/circuitprinter.dm @@ -16,7 +16,7 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). var/mat_efficiency = 1 var/speed = 1 - materials = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0, MAT_PLASTEEL = 0, "plastic" = 0, MAT_GRAPHITE, "gold" = 0, "silver" = 0, "osmium" = 0, MAT_LEAD = 0, "phoron" = 0, "uranium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0) + materials = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0, MAT_PLASTEEL = 0, "plastic" = 0, MAT_GRAPHITE = 0, "gold" = 0, "silver" = 0, "osmium" = 0, MAT_LEAD = 0, "phoron" = 0, "uranium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0) hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER) diff --git a/code/modules/research/designs/circuits/circuits.dm b/code/modules/research/designs/circuits/circuits.dm index e2479a8e1c..425223ffe7 100644 --- a/code/modules/research/designs/circuits/circuits.dm +++ b/code/modules/research/designs/circuits/circuits.dm @@ -493,6 +493,8 @@ CIRCUITS BELOW name = "'Durand' central control" id = "durand_main" req_tech = list(TECH_DATA = 4) + materials = list("glass" = 2000, MAT_GRAPHITE = 1250) + chemicals = list("pacid" = 20) build_path = /obj/item/weapon/circuitboard/mecha/durand/main sort_string = "NAADA" @@ -500,6 +502,8 @@ CIRCUITS BELOW name = "'Durand' peripherals control" id = "durand_peri" req_tech = list(TECH_DATA = 4) + materials = list("glass" = 2000, MAT_GRAPHITE = 1250) + chemicals = list("pacid" = 20) build_path = /obj/item/weapon/circuitboard/mecha/durand/peripherals sort_string = "NAADB" @@ -507,6 +511,8 @@ CIRCUITS BELOW name = "'Durand' weapon control and targeting" id = "durand_targ" req_tech = list(TECH_DATA = 4, TECH_COMBAT = 2) + materials = list("glass" = 2000, MAT_GRAPHITE = 1250) + chemicals = list("pacid" = 20) build_path = /obj/item/weapon/circuitboard/mecha/durand/targeting sort_string = "NAADC" diff --git a/code/modules/research/designs/weapons.dm b/code/modules/research/designs/weapons.dm index 13d6036edd..f57b285118 100644 --- a/code/modules/research/designs/weapons.dm +++ b/code/modules/research/designs/weapons.dm @@ -100,14 +100,23 @@ sort_string = "MABBA" /datum/design/item/weapon/ballistic/ammo/stunshell - name = "stun shell" + name = "stun shells" desc = "A stunning shell for a shotgun." id = "stunshell" req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) materials = list(DEFAULT_WALL_MATERIAL = 4000) - build_path = /obj/item/ammo_casing/a12g/stunshell + build_path = /obj/item/weapon/storage/box/stunshells sort_string = "MABBB" +/datum/design/item/weapon/ballistic/ammo/empshell + name = "emp shells" + desc = "An electromagnetic shell for a shotgun." + id = "empshell" + req_tech = list(TECH_COMBAT = 4, TECH_MAGNET = 3) + materials = list(DEFAULT_WALL_MATERIAL = 4000, MAT_URANIUM = 1000) + build_path = /obj/item/weapon/storage/box/empshells + sort_string = "MABBC" + // Phase weapons /datum/design/item/weapon/phase/AssembleDesignName() diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm index 7316c42179..899b5fd9db 100644 --- a/code/modules/research/mechfab_designs.dm +++ b/code/modules/research/mechfab_designs.dm @@ -177,57 +177,57 @@ name = "Durand Chassis" id = "durand_chassis" build_path = /obj/item/mecha_parts/chassis/durand - time = 10 - materials = list(DEFAULT_WALL_MATERIAL = 18750) + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 18750, MAT_PLASTEEL = 20000) /datum/design/item/mechfab/durand/torso name = "Durand Torso" id = "durand_torso" build_path = /obj/item/mecha_parts/part/durand_torso - time = 30 - materials = list(DEFAULT_WALL_MATERIAL = 41250, "glass" = 15000, "silver" = 7500) + time = 60 + materials = list(DEFAULT_WALL_MATERIAL = 41250, MAT_PLASTEEL = 15000, "silver" = 7500) /datum/design/item/mechfab/durand/head name = "Durand Head" id = "durand_head" build_path = /obj/item/mecha_parts/part/durand_head - time = 20 + time = 40 materials = list(DEFAULT_WALL_MATERIAL = 18750, "glass" = 7500, "silver" = 2250) /datum/design/item/mechfab/durand/left_arm name = "Durand Left Arm" id = "durand_left_arm" build_path = /obj/item/mecha_parts/part/durand_left_arm - time = 20 + time = 40 materials = list(DEFAULT_WALL_MATERIAL = 26250, "silver" = 2250) /datum/design/item/mechfab/durand/right_arm name = "Durand Right Arm" id = "durand_right_arm" build_path = /obj/item/mecha_parts/part/durand_right_arm - time = 20 + time = 40 materials = list(DEFAULT_WALL_MATERIAL = 26250, "silver" = 2250) /datum/design/item/mechfab/durand/left_leg name = "Durand Left Leg" id = "durand_left_leg" build_path = /obj/item/mecha_parts/part/durand_left_leg - time = 20 + time = 40 materials = list(DEFAULT_WALL_MATERIAL = 30000, "silver" = 2250) /datum/design/item/mechfab/durand/right_leg name = "Durand Right Leg" id = "durand_right_leg" build_path = /obj/item/mecha_parts/part/durand_right_leg - time = 20 + time = 40 materials = list(DEFAULT_WALL_MATERIAL = 30000, "silver" = 2250) /datum/design/item/mechfab/durand/armour name = "Durand Armour Plates" id = "durand_armour" build_path = /obj/item/mecha_parts/part/durand_armour - time = 60 - materials = list(DEFAULT_WALL_MATERIAL = 37500, "uranium" = 7500) + time = 90 + materials = list(DEFAULT_WALL_MATERIAL = 27500, MAT_PLASTEEL = 10000, "uranium" = 7500) /datum/design/item/mechfab/janus category = "Janus" @@ -1038,4 +1038,151 @@ time = 20 req_tech = list(TECH_MATERIAL = 6, TECH_ENGINEERING = 5, TECH_PHORON = 3, TECH_MAGNET = 4, TECH_POWER = 6) materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 6000, "silver" = 4000) - \ No newline at end of file + +// Exosuit Internals + +/datum/design/item/mechfab/exointernal + category = "Exosuit Internals" + time = 120 + req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + +/datum/design/item/mechfab/exointernal/stan_armor + name = "Armor Plate (Standard)" + category = "Exosuit Internals" + id = "exo_int_armor_standard" + req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10000) + build_path = /obj/item/mecha_parts/component/armor + +/datum/design/item/mechfab/exointernal/light_armor + name = "Armor Plate (Lightweight)" + category = "Exosuit Internals" + id = "exo_int_armor_lightweight" + req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 5000, MAT_PLASTIC = 3000) + build_path = /obj/item/mecha_parts/component/armor/lightweight + +/datum/design/item/mechfab/exointernal/reinf_armor + name = "Armor Plate (Reinforced)" + category = "Exosuit Internals" + id = "exo_int_armor_reinforced" + req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 4) + materials = list(DEFAULT_WALL_MATERIAL = 20000, MAT_PLASTEEL = 10000) + build_path = /obj/item/mecha_parts/component/armor/reinforced + +/datum/design/item/mechfab/exointernal/mining_armor + name = "Armor Plate (Blast)" + category = "Exosuit Internals" + id = "exo_int_armor_blast" + req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 4) + materials = list(DEFAULT_WALL_MATERIAL = 20000, MAT_PLASTEEL = 10000) + build_path = /obj/item/mecha_parts/component/armor/mining + +/datum/design/item/mechfab/exointernal/gygax_armor + name = "Armor Plate (Marshal)" + category = "Exosuit Internals" + id = "exo_int_armor_gygax" + req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_COMBAT = 2) + materials = list(DEFAULT_WALL_MATERIAL = 40000, MAT_DIAMOND = 8000) + build_path = /obj/item/mecha_parts/component/armor/marshal + +/datum/design/item/mechfab/exointernal/darkgygax_armor + name = "Armor Plate (Blackops)" + category = "Exosuit Internals" + id = "exo_int_armor_dgygax" + req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 5, TECH_COMBAT = 4, TECH_ILLEGAL = 2) + materials = list(MAT_PLASTEEL = 20000, MAT_DIAMOND = 10000, MAT_GRAPHITE = 20000) + build_path = /obj/item/mecha_parts/component/armor/marshal/reinforced + +/datum/design/item/mechfab/exointernal/durand_armour + name = "Armor Plate (Military)" + id = "exo_int_armor_durand" + req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_COMBAT = 2) + materials = list(DEFAULT_WALL_MATERIAL = 40000, MAT_PLASTEEL = 9525, "uranium" = 8000) + build_path = /obj/item/mecha_parts/component/armor/military + +/datum/design/item/mechfab/exointernal/marauder_armour + name = "Armor Plate (Cutting Edge)" + id = "exo_int_armor_marauder" + req_tech = list(TECH_MATERIAL = 8, TECH_ENGINEERING = 7, TECH_COMBAT = 6, TECH_ILLEGAL = 4) + materials = list(MAT_DURASTEEL = 40000, MAT_GRAPHITE = 8000, MAT_OSMIUM = 8000) + build_path = /obj/item/mecha_parts/component/armor/military/marauder + +/datum/design/item/mechfab/exointernal/phazon_armour + name = "Armor Plate (Janus)" + id = "exo_int_armor_phazon" + req_tech = list(TECH_MATERIAL = 6, TECH_ENGINEERING = 6, TECH_COMBAT = 6, TECH_ILLEGAL = 4) + materials = list(MAT_MORPHIUM = 40000, MAT_DURASTEEL = 8000, MAT_OSMIUM = 8000) + build_path = /obj/item/mecha_parts/component/armor/alien + +/datum/design/item/mechfab/exointernal/stan_hull + name = "Hull (Standard)" + category = "Exosuit Internals" + id = "exo_int_hull_standard" + req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10000) + build_path = /obj/item/mecha_parts/component/hull + +/datum/design/item/mechfab/exointernal/durable_hull + name = "Hull (Durable)" + category = "Exosuit Internals" + id = "exo_int_hull_durable" + req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 8000, MAT_PLASTEEL = 5000) + build_path = /obj/item/mecha_parts/component/hull/durable + +/datum/design/item/mechfab/exointernal/light_hull + name = "Hull (Lightweight)" + category = "Exosuit Internals" + id = "exo_int_hull_light" + req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 4) + materials = list(DEFAULT_WALL_MATERIAL = 5000, MAT_PLASTIC = 3000) + build_path = /obj/item/mecha_parts/component/hull/lightweight + +/datum/design/item/mechfab/exointernal/stan_gas + name = "Life-Support (Standard)" + category = "Exosuit Internals" + id = "exo_int_lifesup_standard" + req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10000) + build_path = /obj/item/mecha_parts/component/gas + +/datum/design/item/mechfab/exointernal/reinf_gas + name = "Life-Support (Reinforced)" + category = "Exosuit Internals" + id = "exo_int_lifesup_reinforced" + req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 4) + materials = list(DEFAULT_WALL_MATERIAL = 8000, MAT_PLASTEEL = 8000, MAT_GRAPHITE = 1000) + build_path = /obj/item/mecha_parts/component/gas/reinforced + +/datum/design/item/mechfab/exointernal/stan_electric + name = "Electrical Harness (Standard)" + category = "Exosuit Internals" + id = "exo_int_electric_standard" + req_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 5000, MAT_PLASTIC = 1000) + build_path = /obj/item/mecha_parts/component/electrical + +/datum/design/item/mechfab/exointernal/efficient_electric + name = "Electrical Harness (High)" + category = "Exosuit Internals" + id = "exo_int_electric_efficient" + req_tech = list(TECH_POWER = 4, TECH_ENGINEERING = 4, TECH_DATA = 2) + materials = list(DEFAULT_WALL_MATERIAL = 5000, MAT_PLASTIC = 3000, MAT_SILVER = 3000) + build_path = /obj/item/mecha_parts/component/electrical/high_current + +/datum/design/item/mechfab/exointernal/stan_actuator + name = "Actuator Lattice (Standard)" + category = "Exosuit Internals" + id = "exo_int_actuator_standard" + req_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10000) + build_path = /obj/item/mecha_parts/component/actuator + +/datum/design/item/mechfab/exointernal/hispeed_actuator + name = "Actuator Lattice (Overclocked)" + category = "Exosuit Internals" + id = "exo_int_actuator_overclock" + req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_POWER = 4) + materials = list(MAT_PLASTEEL = 10000, MAT_OSMIUM = 3000, MAT_GOLD = 5000) + build_path = /obj/item/mecha_parts/component/actuator/hispeed \ No newline at end of file diff --git a/html/changelogs/mechoid - exointernals.yml b/html/changelogs/mechoid - exointernals.yml new file mode 100644 index 0000000000..dd25e29efb --- /dev/null +++ b/html/changelogs/mechoid - exointernals.yml @@ -0,0 +1,39 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Mechoid + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Exosuits now have internal components." + - rscadd: "Autolathes can use plastic and plasteel." + - rscadd: "Autolathes can have tiered recipes, based on their manipulator rating." + - tweak: "Exosuit base health has been lowered due to the changes to damage processing." diff --git a/icons/effects/actions_mecha.dmi b/icons/effects/actions_mecha.dmi index 0a505767a3021ec6bedfbb260e2edf3d19bc3b7d..882ceb534f6dc6516cfa49cbc1d5225464b0ff29 100644 GIT binary patch literal 8185 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 literal 7707 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