Skip to content

Commit

Permalink
[COMMISSION] New mech weapons: club, bow & BFG (#8486)
Browse files Browse the repository at this point in the history
* initial

* fix mech_weapon_overlays

* mech weapon changes

* final changes

* mayhaps just a little too high

* mace change

* whoopsie

* balance changes

* momma didn't raise no mathmatician

* tf

* cleanup

* its working

* bfg rebalance

* crossbow rebalance

* fuck it
  • Loading branch information
cheesePizza2 committed Aug 9, 2024
1 parent e2a123a commit 423c6bf
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 22 deletions.
3 changes: 3 additions & 0 deletions code/modules/mechs/equipment/_equipment.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
207 changes: 197 additions & 10 deletions code/modules/mechs/equipment/combat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1163,13 +1360,3 @@
spawn_tags = SPAWN_MECH_QUIPMENT
spawn_blacklisted = FALSE
rarity_value = 50










4 changes: 4 additions & 0 deletions code/modules/mechs/mech.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mechs/mech_icon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 25 additions & 5 deletions code/modules/mechs/mech_interaction.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
Expand Down
27 changes: 21 additions & 6 deletions code/modules/projectiles/guns/energy/charge.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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)
Expand All @@ -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."))
Expand All @@ -140,4 +155,4 @@
/obj/item/gun/energy/dropped(mob/user)
..()
if(overcharge_level)
overcharge_level = 0
overcharge_level = 0
5 changes: 5 additions & 0 deletions code/modules/projectiles/projectile/bullettypes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
5 changes: 5 additions & 0 deletions code/modules/projectiles/projectile/plasma.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file modified icons/mechs/mech_equipment.dmi
Binary file not shown.
Binary file modified icons/mechs/mech_weapon_overlays.dmi
Binary file not shown.
Binary file modified icons/obj/projectiles.dmi
Binary file not shown.

0 comments on commit 423c6bf

Please sign in to comment.