Skip to content

Commit

Permalink
Improves jousting and gives it to more weapons (tgstation#76321)
Browse files Browse the repository at this point in the history
## About The Pull Request

I was reading over components and saw one called jousting, I vividly
remember it being mentioned every so often but I've never seen it
in-game. Turns out the SINGLE case for it is when you are using a spear
on a borg. The code itself was also very over the place, making it a
little confusing to figure out what it did.

I tried cleaning the file up as much as I could, and since I wanted to
see this in-game more often, I made some player-facing changes too:

- You can now joust from any vehicle, not just borgs (Secway, ATV,
scooter, Charger holoparasite)
- Added jousting to the broom, pitchfork, captain's sabre, and energy
sword while active (ONLY esword, NOT desword).
- Added examine text to indicate this feature exists.

Extra notes:
Esword gains half the damage increase and half the knockdown chance than
other ways of jousting
Broom only gets 25% damage increase from jousting, since the broom is
already pretty strong I thought it would be better off as something used
mostly to knockdown.
Spears have to travel a longer distance than other weapons to get their
jousting benefits (since it's supposed to be a ghetto weapon)
Jousting now takes the minimum distance needed into account when
handling knockdown chance & damage dealt, so travelling 5 tiles will no
longer be 100% chance of knockdown if you need a minimum distance of 3
tiles to joust (it will instead be 40%, since you've only traveled 2
tiles in 'jousting' mode).

## Why It's Good For The Game

This is an underused component and I thought it would bring some pretty
cool interactions, especially for Holoparasite & Janitors, as a new way
to use vehicles to your advantage when it's otherwise seen as just a
slowdown.

## Changelog

:cl:
balance: Jousting now works on anything you're buckled to, not just
Cyborgs.
balance: Brooms, Pitchforks, the Captain's Sabre, and Energy swords can
now be used for jousting.
balance: Spears need to travel a longer distance to joust now.
balance: Jousting's knockdown and damage now only gets stronger after
you've traveled the minimum tiles needed to joust.
/:cl:
  • Loading branch information
JohnFulpWillard authored Jul 1, 2023
1 parent f3d02ae commit 333bef4
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 47 deletions.
147 changes: 105 additions & 42 deletions code/datums/components/jousting.dm
Original file line number Diff line number Diff line change
@@ -1,27 +1,77 @@
///Amount of time each timer has, used to reset the jousting back, indicating that the person has stopped moving.
#define MOVEMENT_RESET_COOLDOWN_TIME (0.3 SECONDS)

/**
* ##jousting
*
* Given to items, it allows you to charge into people with additional damage and potential knockdown
* by being buckled onto something. If the other person is also jousting, can knock eachother down.
*/
/datum/component/jousting
///The current person holding parent.
var/mob/living/current_holder
///The current direction of the jousting.
var/current_direction = NONE
var/max_tile_charge = 5
var/min_tile_charge = 2 //tiles before this code gets into effect.
///How many tiles we've charged up thus far
var/current_tile_charge = 0
var/movement_reset_tolerance = 3 //deciseconds
var/unmounted_damage_boost_per_tile = 0
var/unmounted_knockdown_chance_per_tile = 0
var/unmounted_knockdown_time = 0
var/mounted_damage_boost_per_tile = 2
var/mounted_knockdown_chance_per_tile = 20
var/mounted_knockdown_time = 20
var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
var/mob/current_holder
var/current_timerid

/datum/component/jousting/Initialize()

///How much of an increase in damage is achieved every tile moved during jousting.
var/damage_boost_per_tile
///The boosted chances of a knockdown occuring while jousting.
var/knockdown_chance_per_tile
///How much of an increase in knockdown is achieved every tile moved during jousting, if it knocks down.
var/knockdown_time
///The max amount of tiles before you can joust someone.
var/max_tile_charge
///The min amount of tiles before you can joust someone.
var/min_tile_charge

/datum/component/jousting/Initialize(
damage_boost_per_tile = 2,
knockdown_chance_per_tile = 20,
knockdown_time = 2 SECONDS,
max_tile_charge = 5,
min_tile_charge = 2,
)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
src.damage_boost_per_tile = damage_boost_per_tile
src.knockdown_chance_per_tile = knockdown_chance_per_tile
src.knockdown_time = knockdown_time
src.max_tile_charge = max_tile_charge
src.min_tile_charge = min_tile_charge

RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(on_attack))
RegisterSignal(parent, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))

/datum/component/jousting/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(
COMSIG_ATOM_EXAMINE,
COMSIG_ITEM_EQUIPPED,
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_ATTACK,
COMSIG_TRANSFORMING_ON_TRANSFORM,
))

/datum/component/jousting/proc/on_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
examine_list += span_notice("It can be used on a vehicle for jousting, dealing potential knockdowns and additional damage.")

/datum/component/jousting/proc/on_transform(obj/item/source, mob/user, active)
SIGNAL_HANDLER
if(!user)
return

if(active)
INVOKE_ASYNC(src, PROC_REF(on_equip), user)
else
INVOKE_ASYNC(src, PROC_REF(on_drop), user)

///Called when a mob equips the spear, registers them as the holder and checks their signals for moving.
/datum/component/jousting/proc/on_equip(datum/source, mob/user, slot)
SIGNAL_HANDLER

Expand All @@ -31,52 +81,65 @@
/datum/component/jousting/proc/on_drop(datum/source, mob/user)
SIGNAL_HANDLER

reset_charge()
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
current_holder = null
current_direction = NONE
current_tile_charge = 0

/**
* Performs the actual attack, handling damage/knockdown depending on how far you've jousted.
* We deduct the minimum tile charge from the current tile charge to get what will actually be buffed
* So your charge will only get benefits from each extra tile after the minimum (and before the maximum).
*/
/datum/component/jousting/proc/on_attack(datum/source, mob/living/target, mob/user)
SIGNAL_HANDLER

if(user != current_holder)
if(user != current_holder || !user.buckled)
return
var/current = current_tile_charge
var/obj/item/I = parent
var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
var/usable_charge = (current_tile_charge - min_tile_charge)
if(!current_direction || (usable_charge <= 0))
return

var/turf/target_turf = get_step(user, current_direction)
if(target in range(1, target_turf))
var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
var/sharp = I.get_sharpness()
var/msg
if(damage)
msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
target.apply_damage(damage, BRUTE, user.zone_selected, 0)
if(prob(knockdown_chance))
msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
if(target_buckled)
var/obj/item/parent_item = parent
var/sharp = parent_item.get_sharpness()
var/msg = "[user] [sharp ? "impales" : "slams into"] [target] [sharp ? "on" : "with"] their [parent]"
target.apply_damage((damage_boost_per_tile * usable_charge), BRUTE, user.zone_selected, 0)
if(prob(knockdown_chance_per_tile * usable_charge))
msg += " and knocks [target] [target.buckled ? "off of [target.buckled]" : "down"]"
if(target.buckled)
target.buckled.unbuckle_mob(target)
target.Paralyze(knockdown_time)
if(length(msg))
user.visible_message(span_danger("[msg]!"))
user.visible_message(span_danger("[msg]!"))

/**
* Called when a mob moves.
* Handles checking their direction, changing it if they turned,
* and increments how many tiles they've been charging for.
* Lastly, refreshes their charge reset timer, giving them a new one instead.
*/
/datum/component/jousting/proc/mob_move(datum/source, newloc, dir)
SIGNAL_HANDLER

if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
if(!current_holder)
CRASH("[src] called mob_move despite supposedly not having a mob registed to joust as.")
if(!current_holder.buckled)
return

if(dir != current_direction)
current_tile_charge = 0
current_tile_charge = initial(current_tile_charge)
current_direction = dir
if(current_tile_charge < max_tile_charge)
current_tile_charge++
if(current_timerid)
deltimer(current_timerid)
current_timerid = addtimer(CALLBACK(src, PROC_REF(reset_charge)), movement_reset_tolerance, TIMER_STOPPABLE)
addtimer(CALLBACK(src, PROC_REF(reset_charge)), MOVEMENT_RESET_COOLDOWN_TIME, TIMER_UNIQUE | TIMER_OVERRIDE)

/**
* reset charge
*
* Resets their direction and tile charge back to their initial values.
* This is used when someone is no longer jousting and it should cleanup.
*/
/datum/component/jousting/proc/reset_charge()
current_tile_charge = 0
current_direction = initial(current_direction)
current_tile_charge = initial(current_tile_charge)

#undef MOVEMENT_RESET_COOLDOWN_TIME
9 changes: 8 additions & 1 deletion code/game/objects/items/broom.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@

/obj/item/pushbroom/Initialize(mapload)
. = ..()
AddComponent(/datum/component/two_handed, force_unwielded=8, force_wielded=12, icon_wielded="[base_icon_state]1", wield_callback = CALLBACK(src, PROC_REF(on_wield)), unwield_callback = CALLBACK(src, PROC_REF(on_unwield)))
AddComponent(/datum/component/jousting, damage_boost_per_tile = 1)
AddComponent(/datum/component/two_handed, \
force_unwielded = 8, \
force_wielded = 12, \
icon_wielded = "[base_icon_state]1", \
wield_callback = CALLBACK(src, PROC_REF(on_wield)), \
unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \
)

/obj/item/pushbroom/update_icon_state()
icon_state = "[base_icon_state]0"
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/items/melee/energy.dm
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@

/obj/item/melee/energy/sword/saber/Initialize(mapload)
. = ..()
AddComponent(/datum/component/jousting, damage_boost_per_tile = 1, knockdown_chance_per_tile = 10)
if(!sword_color_icon && LAZYLEN(possible_sword_colors))
sword_color_icon = pick(possible_sword_colors)

Expand Down
7 changes: 4 additions & 3 deletions code/game/objects/items/melee/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@

/obj/item/melee/sabre/Initialize(mapload)
. = ..()
AddComponent(/datum/component/jousting)
//fast and effective, but as a sword, it might damage the results.
AddComponent(/datum/component/butchering, \
speed = 3 SECONDS, \
effectiveness = 95, \
bonus_modifier = 5, \
speed = 3 SECONDS, \
effectiveness = 95, \
bonus_modifier = 5, \
)
// The weight of authority comes down on the tider's crimes.
AddElement(/datum/element/bane, target_type = /mob/living/carbon/human, damage_multiplier = 0.35)
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/items/pitchfork.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

/obj/item/pitchfork/Initialize(mapload)
. = ..()
AddComponent(/datum/component/jousting)
AddComponent(/datum/component/two_handed, force_unwielded=7, force_wielded=15, icon_wielded="[base_icon_state]1")

/obj/item/pitchfork/update_icon_state()
Expand Down
5 changes: 4 additions & 1 deletion code/game/objects/items/spear.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
. = ..()
force = force_unwielded
//decent in a pinch, but pretty bad.
AddComponent(/datum/component/jousting)
AddComponent(/datum/component/jousting, \
max_tile_charge = 9, \
min_tile_charge = 6, \
)

AddComponent(/datum/component/butchering, \
speed = 10 SECONDS, \
Expand Down

0 comments on commit 333bef4

Please sign in to comment.