diff --git a/code/modules/mechs/equipment/_equipment.dm b/code/modules/mechs/equipment/_equipment.dm index aec638bad08..526c1b8fd41 100644 --- a/code/modules/mechs/equipment/_equipment.dm +++ b/code/modules/mechs/equipment/_equipment.dm @@ -31,6 +31,9 @@ /obj/item/mech_equipment/proc/pretick() return FALSE +/obj/item/mech_equipment/proc/get_overlay_state() + return icon_state + /obj/item/mech_equipment/attack() //Generally it's not desired to be able to attack with items return 0 diff --git a/code/modules/mechs/equipment/combat.dm b/code/modules/mechs/equipment/combat.dm index 7f2b756068a..1accd2e61c0 100644 --- a/code/modules/mechs/equipment/combat.dm +++ b/code/modules/mechs/equipment/combat.dm @@ -802,6 +802,203 @@ cocked = FALSE // not being able to fire removes the CH(done in reloadGun now) +/obj/item/mech_equipment/mounted_system/mace + name = "\improper NT \"Warhead\" mace" + desc = "An exosuit-mounted mace. Doubles as a flail. Handle with care." + icon_state = "mech_mace" + holding_type = /obj/item/tool/hammer/mace/mech + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_STEEL = 10) + origin_tech = list(TECH_COMBAT = 4, TECH_MAGNET = 3) + +/obj/item/mech_equipment/mounted_system/attack_self(mob/user) + . = ..() + owner.update_icon() + +/obj/item/mech_equipment/mounted_system/mace/Initialize() + . = ..() + var/obj/item/tool/hammer/mace/mech/holdin = holding + holdin.wielded = TRUE + +obj/item/mech_equipment/mounted_system/mace/get_overlay_state() + var/obj/item/tool/hammer/mace/mech/mace = holding + if(mace.flail_mode) + icon_state = "mech_mace_flail" + else + icon_state = initial(icon_state) + return "[icon_state][active ? "_flail" : ""]" + +/obj/item/tool/hammer/mace/mech + name = "huge mace" + desc = "You should not see this. Contact a coder" + matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_PLASTIC = 5) + w_class = ITEM_SIZE_BULKY + wielded = TRUE + canremove = FALSE + armor_divisor = ARMOR_PEN_HALF + tool_qualities = list(QUALITY_HAMMERING = 45) // SEE: attack_self() + structure_damage_factor = STRUCTURE_DAMAGE_DESTRUCTIVE + spawn_blacklisted = TRUE + force = WEAPON_FORCE_BRUTAL + force_wielded_multiplier = 1.5 + /// Determines what mode our mace is. FALSE is mace, TRUE is flail + var/flail_mode = FALSE + +/obj/item/tool/hammer/mace/mech/attack_self(mob/user) + flail_mode = !flail_mode + + if(flail_mode) + name = "huge flail" + extended_reach = TRUE + forced_broad_strike = TRUE + force = WEAPON_FORCE_ROBUST + armor_divisor = ARMOR_PEN_SHALLOW + structure_damage_factor = STRUCTURE_DAMAGE_WEAK // lot harder to bash a wall open when your flail keeps glancing off + tool_qualities = list() + else + name = initial(name) + extended_reach = initial(extended_reach) + forced_broad_strike = initial(forced_broad_strike) + force = initial(force) + armor_divisor = initial(armor_divisor) + structure_damage_factor = initial(structure_damage_factor) + tool_qualities = list(QUALITY_HAMMERING = 45) // initial doesn't work on lists + +/obj/item/tool/hammer/mace/mech/attackby(mob/living/target, mob/user, params) + . = ..() + if(. && ismech(loc) && istype(target) && target != user) + var/hit_verb = "slammed" + var/intensity = 1 + if(ishuman(target)) + var/mob/living/carbon/human/targ = target + if(targ.stats.getStat(STAT_VIG) > STAT_LEVEL_ADEPT) + intensity = STAT_LEVEL_ADEPT / targ.stats.getStat(STAT_VIG) + hit_verb = (intensity > 0.6) ? "knocked" : "grazed" + if(flail_mode) + target.visible_message(SPAN_NOTICE("[target] gets [hit_verb] by [user]'s [src]!"), SPAN_DANGER("You get [hit_verb] by [user]'s [src]!"), "You hear something soft hit a metal plate!", 6) + target.Weaken(3 * intensity) + target.throw_at(get_turf_away_from_target_complex(target, user, 3), FLOOR(5 * intensity, 1), 1, user) + else + target.visible_message(SPAN_NOTICE("[target] gets [hit_verb] by [user]'s [src]!"), SPAN_DANGER("You get [hit_verb] by [user]'s [src]!"), "You hear something soft hit a metal plate!", 6) + target.damage_through_armor(20 * intensity, BRUTE, BP_CHEST, ARMOR_MELEE, ARMOR_PEN_HALF, src, FALSE, FALSE, 1) + +/obj/item/mech_equipment/mounted_system/bfg + name = "mounted BFG" + icon_state = "plasmabfg" + holding_type = /obj/item/gun/energy/plasma_mech + restricted_software = list(MECH_SOFTWARE_ADVWEAPONS) + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + origin_tech = list(TECH_MATERIAL = 4, TECH_PLASMA = 4, TECH_ENGINEERING = 6, TECH_COMBAT = 3) + matter = list(MATERIAL_PLASTEEL = 20, MATERIAL_STEEL = 10, MATERIAL_SILVER = 10) + spawn_tags = SPAWN_MECH_QUIPMENT + spawn_blacklisted = FALSE + rarity_value = 60 + +/obj/item/gun/energy/plasma_mech + name = "mounted BFG" + desc = "A large, bulky weapon that fires a massive energy blast. It's a bit unwieldy, but it packs a punch." + safety = FALSE + spawn_tags = null + spawn_blacklisted = TRUE + use_external_power = TRUE + self_recharge = TRUE + restrict_safety = TRUE + twohanded = FALSE + charge_cost = MECH_WEAPON_POWER_COST * 5 + projectile_type = /obj/item/projectile/plasma/aoe/heat/strong/mech + fire_sound='sound/weapons/energy/melt.ogg' + burst = 1 + init_firemodes = list( + WEAPON_CHARGE + ) + fire_delay = 120 + overcharge_max = 12 + matter = list() + cell_type = /obj/item/cell/medium/mech + +#define CROSSBOW_MAX_AMOUNT 7 +#define CROSSBOW_AMOUNT_OF_MATERIAL_PER_SHOT 5 + +/obj/item/mech_equipment/mounted_system/crossbow + name = "mounted crossbow" + icon_state = "crossbow" + holding_type = /obj/item/gun/energy/crossbow_mech + restricted_software = list(MECH_SOFTWARE_WEAPONS) + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + origin_tech = list(TECH_MATERIAL = 4, TECH_PLASMA = 4, TECH_ENGINEERING = 6, TECH_COMBAT = 3) + matter = list(MATERIAL_STEEL = 10, MATERIAL_PLASTEEL = 15) + spawn_tags = SPAWN_MECH_QUIPMENT + spawn_blacklisted = FALSE + rarity_value = 60 + +/obj/item/mech_equipment/mounted_system/crossbow/attackby(obj/item/I, mob/living/user, params) + if(!istype(I, /obj/item/stack/material)) + return ..() + + var/obj/item/gun/energy/crossbow_mech/CM = holding + if(CM.shots_amount == CROSSBOW_MAX_AMOUNT) + to_chat(user, SPAN_NOTICE("\The [CM] is full!")) + return + + var/obj/item/stack/material/mat = I + if(!mat.material.hardness) + to_chat(user, SPAN_NOTICE("\The [mat] can't be used as a bolt!")) + return + + // precalc using amount to cut down on calculations. we use EITHER enough to fill up the slot OR the entire stack minus a remainder + var/using = min(CROSSBOW_AMOUNT_OF_MATERIAL_PER_SHOT * (CROSSBOW_MAX_AMOUNT - CM.shots_amount), mat.amount - (mat.amount % CROSSBOW_AMOUNT_OF_MATERIAL_PER_SHOT)) + + if(using == 0) + to_chat(user, SPAN_NOTICE("There aren't enough sheets in \the [mat]!")) + return + + to_chat(user , SPAN_NOTICE("You pack [using] sheets of \the [mat] into \the [src].")) + CM.shots_amount += using / CROSSBOW_AMOUNT_OF_MATERIAL_PER_SHOT + CM.calculate_damage(mat.material) + mat.use(using) + +/obj/item/gun/energy/crossbow_mech + name = "mounted crossbow" + desc = "A large, bulky weapon that fires a plasteel bolt. It's a bit unwieldy, but it packs a punch." + safety = FALSE + spawn_tags = null + spawn_blacklisted = TRUE + use_external_power = TRUE + self_recharge = TRUE + restrict_safety = TRUE + twohanded = FALSE + charge_cost = MECH_WEAPON_POWER_COST * 2 + projectile_type = /obj/item/projectile/bullet/bolt/mech + fire_sound='sound/weapons/energy/melt.ogg' + burst = 1 + init_firemodes = list( + WEAPON_CHARGE + ) + fire_delay = 10 + overcharge_max = 3 + matter = list() + cell_type = /obj/item/cell/medium/mech + var/shots_amount = 0 + var/damage_types = list(BRUTE = 34) + var/bolt_armor_divisor = 2 + +/obj/item/gun/energy/crossbow_mech/proc/calculate_damage(material/bolt_mat) + if(!bolt_mat || !istype(bolt_mat)) + CRASH("calculate_damage() called with no/invalid bolt material!") + + damage_types = list(BRUTE = max(0, round((bolt_mat.weight * 1.2), 1))) + bolt_armor_divisor = max(1, round(log(bolt_mat.hardness / 20) + 1, 1)) + +/obj/item/gun/energy/crossbow_mech/consume_next_projectile() + if(cell.use(charge_cost) && shots_amount) + shots_amount-- + var/obj/item/projectile/bullet/bolt/mech/bolt = new projectile_type + bolt.damage_types = damage_types + bolt.armor_divisor = bolt_armor_divisor + . = bolt + +#undef CROSSBOW_MAX_AMOUNT +#undef CROSSBOW_AMOUNT_OF_MATERIAL_PER_SHOT /// Yes this also drains power from blocking halloss /// Yes i justify it cause it stops by kinetic power and not by lethality / material hardness @@ -1163,13 +1360,3 @@ spawn_tags = SPAWN_MECH_QUIPMENT spawn_blacklisted = FALSE rarity_value = 50 - - - - - - - - - - diff --git a/code/modules/mechs/mech.dm b/code/modules/mechs/mech.dm index 3d4932c8ebf..d6b3ea4ecec 100644 --- a/code/modules/mechs/mech.dm +++ b/code/modules/mechs/mech.dm @@ -80,6 +80,10 @@ // Strafing - Is the mech currently strafing? var/strafing = FALSE +/mob/living/exosuit/show_message(msg, type, alt, alt_type) + for(var/mob/i in pilots) + i.show_message(msg, type, alt, alt_type) + /mob/living/exosuit/proc/occupant_message(msg as text) for(var/mob/i in pilots) to_chat(i, msg) diff --git a/code/modules/mechs/mech_icon.dm b/code/modules/mechs/mech_icon.dm index 567a66b6291..7db769f85db 100644 --- a/code/modules/mechs/mech_icon.dm +++ b/code/modules/mechs/mech_icon.dm @@ -43,7 +43,7 @@ for(var/hardpoint in hardpoints) var/obj/item/mech_equipment/hardpoint_object = hardpoints[hardpoint] if(hardpoint_object) - var/use_icon_state = "[hardpoint_object.icon_state]_[hardpoint]" + var/use_icon_state = "[hardpoint_object.get_overlay_state()]_[hardpoint]" if(use_icon_state in GLOB.mech_weapon_overlays) var/color = COLOR_WHITE var/decal = null diff --git a/code/modules/mechs/mech_interaction.dm b/code/modules/mechs/mech_interaction.dm index c6ebd3a9c43..d47967f4e40 100644 --- a/code/modules/mechs/mech_interaction.dm +++ b/code/modules/mechs/mech_interaction.dm @@ -45,8 +45,8 @@ if(!(user in pilots) && user != src) return - // Are we facing the target? - if(A.loc != src && !(get_dir(src, A) & dir)) + // Are we facing the target? Skipped if we're targetting ourselves + if(src != A && A.loc != src && !(get_dir(src, A) & dir)) return if(!selected_system) @@ -86,10 +86,9 @@ failed = TRUE if(!failed && selected_system) - if(selected_system == A) - selected_system.attack_self(user) + if(src == A) setClickCooldown(5) - return + return selected_system.attack_self(user) // Slip up and attack yourself maybe. failed = FALSE if(emp_damage > EMP_MOVE_DISRUPT && prob(10)) @@ -512,6 +511,27 @@ Use this if you turn on armor ablation for mechs: if(do_mob(user, src, 30) && coil.use(5)) mc.repair_burn_damage(15) + // crossbow bolt handling + else if(istype(I, /obj/item/stack/material)) + var/list/choices = list() + for(var/hardpoint in hardpoints) + if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/mounted_system/crossbow)) + var/obj/item/mech_equipment/mounted_system/crossbow/cross = hardpoints[hardpoint] + var/obj/item/gun/energy/crossbow_mech/CM = cross.holding + choices["[hardpoint] - [CM.shots_amount]/3"] = cross + var/obj/item/mech_equipment/mounted_system/crossbow/cross = null + if(!length(choices)) + return + if(length(choices)==1) + cross = choices[choices[1]] + else + var/chosenCross = input("Select crossbow to reload") as null|anything in choices + if(chosenCross) + cross = choices[chosenCross] + if(cross) + cross.attackby(I, user) + return + var/list/usable_qualities = list(QUALITY_PULSING, QUALITY_BOLT_TURNING, QUALITY_PRYING, QUALITY_SCREW_DRIVING, QUALITY_WELDING) var/tool_type = I.get_tool_type(user, usable_qualities, src) diff --git a/code/modules/projectiles/guns/energy/charge.dm b/code/modules/projectiles/guns/energy/charge.dm index 034be65f2b6..9cf2282d616 100644 --- a/code/modules/projectiles/guns/energy/charge.dm +++ b/code/modules/projectiles/guns/energy/charge.dm @@ -11,8 +11,14 @@ /datum/firemode/charge/update(var/force_state = null) var/mob/living/L - if (gun && gun.is_held()) - L = gun.loc + if (gun) + // bit of a hack here, but we want mounted systems to work properly + if (istype(gun.loc, /obj/item/mech_equipment/mounted_system)) + var/obj/item/mech_equipment/mounted_system/MS = gun.loc + if(MS.owner) + L = MS.owner.get_mob() // this will only work for one pilot but the only fix is to rewrite everything AHHHHH I HATE THIS + else if (gun.is_held()) + L = gun.loc var/enable = FALSE //Force state is used for forcing it to be disabled in circumstances where it'd normally be valid @@ -22,9 +28,17 @@ //First of all, lets determine whether we're enabling or disabling the click handler + // Mech systems skip hand check + var/skip_hand_check = FALSE + if(istype(gun.loc, /obj/item/mech_equipment/mounted_system)) + var/obj/item/mech_equipment/mounted_system/MS = gun.loc + if(MS.owner) + var/mob/living/exosuit/ES = MS.owner + if(ES.selected_system == MS) + skip_hand_check = TRUE //We enable it if the gun is held in the user's active hand and the safety is off - if (L.get_active_hand() == gun) + if (skip_hand_check || L.get_active_hand() == gun) //Lets also make sure it can fire var/can_fire = TRUE @@ -105,7 +119,7 @@ /obj/item/gun/energy/proc/add_charge(var/mob/living/user) deltimer(overcharge_timer) - if(get_holding_mob() == user && get_cell() && cell.checked_use(1)) + if((get_holding_mob() == user || istype(loc, /obj/item/mech_equipment/mounted_system)) && get_cell() && cell.checked_use(1)) overcharge_level = min(overcharge_max, overcharge_level + get_overcharge_add(user)) set_light(2, overcharge_level/2, "#ff0d00") if(overcharge_level < overcharge_max) @@ -125,7 +139,8 @@ var/overcharge_add = overcharge_level_to_mult() damage_multiplier += overcharge_add penetration_multiplier += overcharge_add - if(overcharge_level > 2 && cell.checked_use(overcharge_level)) + // minimum overcharge is based on overcharge max. initial is used so that upgrades don't also raise min. possibly move to separate variable? + if(overcharge_level > initial(overcharge_max) / 2 && cell.checked_use(overcharge_level)) Fire(target, user) else visible_message(SPAN_WARNING("\The [src] sputters.")) @@ -140,4 +155,4 @@ /obj/item/gun/energy/dropped(mob/user) ..() if(overcharge_level) - overcharge_level = 0 \ No newline at end of file + overcharge_level = 0 diff --git a/code/modules/projectiles/projectile/bullettypes.dm b/code/modules/projectiles/projectile/bullettypes.dm index a0e1931c2cc..db36d42f39f 100644 --- a/code/modules/projectiles/projectile/bullettypes.dm +++ b/code/modules/projectiles/projectile/bullettypes.dm @@ -360,3 +360,8 @@ There are important things regarding this file: if(istype(target)) var/obj/item/ammo_casing/crossbow/bolt/R = new(null) target.embed(R, def_zone) + +/obj/item/projectile/bullet/bolt/mech + name = "large bolt" + damage_types = list(BRUTE = 34) + matter = list(MATERIAL_STEEL = 5) diff --git a/code/modules/projectiles/projectile/plasma.dm b/code/modules/projectiles/projectile/plasma.dm index 0605d61dea8..2e5c93c39ae 100644 --- a/code/modules/projectiles/projectile/plasma.dm +++ b/code/modules/projectiles/projectile/plasma.dm @@ -106,6 +106,11 @@ fire_stacks = TRUE +/obj/item/projectile/plasma/aoe/heat/strong/mech + damage_types = list(BURN = 34) + heat_damage = 40 + icon_state = "mech_plasma" + /obj/item/projectile/plasma/check_penetrate(var/atom/A) if(istype(A, /obj/item/shield)) var/obj/item/shield/S = A diff --git a/icons/mechs/mech_equipment.dmi b/icons/mechs/mech_equipment.dmi index 10c1fcd7dbd..a4a38ab52e7 100644 Binary files a/icons/mechs/mech_equipment.dmi and b/icons/mechs/mech_equipment.dmi differ diff --git a/icons/mechs/mech_weapon_overlays.dmi b/icons/mechs/mech_weapon_overlays.dmi index 66179245438..474acea5422 100644 Binary files a/icons/mechs/mech_weapon_overlays.dmi and b/icons/mechs/mech_weapon_overlays.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 169ef679178..9a5a4af8ad5 100755 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ