Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions code/__DEFINES/werewolf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#define IS_WEREWOLF(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/werewolf))

// Rage thresholds for /datum/rage/werewolf
#define WW_RAGE_LOW "25"
#define WW_RAGE_MEDIUM "50"
#define WW_RAGE_HIGH "75"
#define WW_RAGE_CRITICAL "100"
#define WW_RAGE_LOW 25
#define WW_RAGE_MEDIUM 50
#define WW_RAGE_HIGH 75
#define WW_RAGE_CRITICAL 100
6 changes: 4 additions & 2 deletions code/_globalvars/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"Recognized" = TRAIT_RECOGNIZED,
"Member of the Oratorium Throni Vacui" = TRAIT_INQUISITION,
"Inflexible" = TRAIT_UNDODGING,
"Graceless" = TRAIT_UNPARRYING,
),
/obj/item/bodypart = list(
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS
Expand Down Expand Up @@ -214,7 +215,8 @@ GLOBAL_LIST_INIT(roguetraits, list(
TRAIT_NOBLE = span_blue("I'm of noble blood."),
TRAIT_EMPATH = "I can notice when people are stressed.",
TRAIT_BREADY = "Defensive stance does not passively fatigue me.",
TRAIT_UNDODGING = span_danger("I am unable to dodge, the only way I could avoid a blow would be by blocking or parrying it."),
TRAIT_UNDODGING = span_danger("I am unable to dodge."),
TRAIT_UNPARRYING = span_danger("I am unable to block and parry attacks."),
TRAIT_BLINDFIGHTING = span_info("I have an incredible sense of awareness, allowing me to parry even when I can't see it coming."),
TRAIT_MEDIUMARMOR = "I can move freely in medium armor.",
TRAIT_HEAVYARMOR = "I can move freely in heavy armor.",
Expand Down Expand Up @@ -273,7 +275,7 @@ GLOBAL_LIST_INIT(roguetraits, list(
TRAIT_APRICITY = "The warmth of the sun rejuvenates me, allowing me to regain my stamina quicker.",
TRAIT_BLACKLEG = "I can cheat by rigging coin and dice, and peek at cards.",
TRAIT_INQUISITION = span_info("I am a member of the Oratorium Throni Vacui. I can easily identify others of my cadre at a glance."),
TRAIT_SILVER_BLESSED = span_info("I am anointed with holy silver, which preserves me from curses that bite, miracles of the false gods hold no sway over me."),
TRAIT_SILVER_BLESSED = span_info("I am anointed with holy silver, which preserves me from bitten curses. Miracles not of Psydon hold no sway over me."),
TRAIT_MATTHIOS_EYES = span_notice("I have a sense for what the most valuable item someone has is."),
TRAIT_CRATEMOVER = "I am able to drag heavy objects without any difficulty.",
TRAIT_SEE_LEYLINES = "I can see the lines that make up this world.",
Expand Down
17 changes: 5 additions & 12 deletions code/datums/enchantments/silver.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#define AFFECTED_VLORD 1
#define AFFECTED 2
#define SILVER_BANE_MAX_STACKS 6
#define SILVER_BANE_COOLDOWN (5 SECONDS)
#define SILVER_BANE_COOLDOWN (2.5 SECONDS)

/datum/enchantment/silver
enchantment_name = "Nightlurkers Bane"
Expand Down Expand Up @@ -90,7 +90,7 @@
/datum/status_effect/debuff/silver_bane
id = "silver_bane"
alert_type = /atom/movable/screen/alert/status_effect/debuff/silver_bane
duration = 30 SECONDS
duration = 15 SECONDS
tick_interval = -1 // No ticking needed
effectedstats = list(STATKEY_STR = -2, STATKEY_PER = -2, STATKEY_INT = -2, STATKEY_CON = -2, STATKEY_END = -2, STATKEY_SPD = -2, STATKEY_LCK = -2)
var/stacks = 0
Expand All @@ -115,6 +115,7 @@
return TRUE

/datum/status_effect/debuff/silver_bane/on_remove()
to_chat(owner, span_notice("The silver's overwhelming curse fades..."))
REMOVE_TRAIT(owner, TRAIT_COVEN_BANE, VAMPIRE_TRAIT)
. = ..()

Expand Down Expand Up @@ -147,23 +148,15 @@
if(affected_type == AFFECTED_VLORD)
// Vampire lords get lighter punishment
owner.Knockdown(30)
owner.Paralyze(15)
owner.Stun(15)
else
// Normal creatures get full punishment
owner.Immobilize(45)
owner.Stun(22.5)

update_alert()

addtimer(CALLBACK(src, PROC_REF(end_stun)), 8 SECONDS)

/datum/status_effect/debuff/silver_bane/proc/end_stun()
if(!owner)
qdel(src)
return

to_chat(owner, span_notice("The silver's overwhelming curse fades..."))
qdel(src)
QDEL_IN(src, 8 SECONDS)

/datum/status_effect/debuff/silver_bane/proc/update_alert()
if(!owner)
Expand Down
17 changes: 13 additions & 4 deletions code/datums/rage/werewolf_rage.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
rage_change_on_life = -0.5
/// Base rage gain multiplier from stress
var/stress_rage_multiplier = 0.1
rage_thresholds = list(
rage_thresholds = alist(
WW_RAGE_LOW = list(),
WW_RAGE_MEDIUM = list(),
WW_RAGE_HIGH = list(),
Expand Down Expand Up @@ -49,9 +49,9 @@
/datum/rage/werewolf/upon_tier_change(new_rage_tier, old_rage_tier)
. = ..()
var/active_mob = secondary_mob || holder_mob
if(new_rage_tier && rage_thresholds["[new_rage_tier]"])
if(new_rage_tier && rage_thresholds[new_rage_tier])
// Notify player of tier change
switch("[new_rage_tier]")
switch(new_rage_tier)
if(WW_RAGE_LOW)
to_chat(active_mob, span_notice("My rage begins to build..."))
if(WW_RAGE_MEDIUM)
Expand All @@ -67,7 +67,10 @@
/datum/rage/werewolf/proc/on_stress_added(datum/source, datum/stress_event/new_stress)
SIGNAL_HANDLER

if(!holder_mob || holder_mob.stat >= DEAD)
if(holder_mob.stat >= UNCONSCIOUS)
return

if(holder_mob.has_status_effect(/datum/status_effect/debuff/barbfalter/werewolf_untransform))
return

var/new_stress_amount = new_stress.stress_change
Expand All @@ -83,6 +86,12 @@
/datum/rage/werewolf/proc/upon_attacked(mob/living/attacked, mob/living/carbon/human/attacker, damage)
SIGNAL_HANDLER

if(holder_mob.stat >= UNCONSCIOUS)
return

if(holder_mob.has_status_effect(/datum/status_effect/debuff/barbfalter/werewolf_untransform))
return

var/base_rage = max(1, damage / 2)
var/rage_multiplier = max(stress_rage_multiplier, 1)

Expand Down
6 changes: 3 additions & 3 deletions code/datums/wounds/_wound.dm
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,14 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
return

/// Heals this wound by the given amount, and deletes it if it's healed completely
/datum/wound/proc/heal_wound(heal_amount)
/datum/wound/proc/heal_wound(heal_amount, forced = FALSE)
// Wound cannot be healed normally, whp is null
if(isnull(whp) || !heal_amount)
return FALSE
var/amount_healed = min(whp, round(heal_amount, DAMAGE_PRECISION))
whp -= amount_healed
if(whp <= 0)
if(!should_persist())
if(!forced && !should_persist())
if(bodypart_owner)
remove_from_bodypart(src)
else if(owner)
Expand Down Expand Up @@ -611,7 +611,7 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/// Multiplier that wound pain is increased by
var/upgrade_pain = 0

/datum/wound/dynamic/heal_wound(heal_amount)
/datum/wound/dynamic/heal_wound(heal_amount, forced)
. = ..()
if(!. || QDELETED(src))
return
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/natural/animals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@
return TRUE
if(is_species(user, /datum/species/werewolf))
visible_message(span_danger("[user] ravenously consumes [src]!"), span_warning("I feed on succulent flesh. I feel reinvigorated."))
H.rage_datum?.update_rage(text2num(WW_RAGE_HIGH))
H.rage_datum?.update_rage(WW_RAGE_HIGH)
gib()
return TRUE
if(!src.apply_damage(damage, BRUTE))
Expand Down
1 change: 1 addition & 0 deletions code/modules/antagonists/villain/werewolf/werewolf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
// owner.current should now be the original human mob, if not something is terribly wrong
if(!silent && owner.current)
to_chat(owner.current,span_danger("I am no longer a [special_role]!"))
REMOVE_TRAIT(owner, TRAIT_NO_TRANSFORM, REF(src))
owner.special_role = null
owner.current.remove_spell(/datum/action/cooldown/spell/undirected/werewolf_form)
owner.current.remove_language(/datum/language/beast)
Expand Down
35 changes: 16 additions & 19 deletions code/modules/antagonists/villain/werewolf/werewolf_spells.dm
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,24 @@

/datum/action/cooldown/spell/undirected/claws/cast(atom/cast_on)
. = ..()
var/obj/item/weapon/werewolf_claw/left/l
var/obj/item/weapon/werewolf_claw/right/r

l = owner.get_active_held_item()
r = owner.get_inactive_held_item()
var/obj/item/weapon/werewolf_claw/left/left_claw
var/obj/item/weapon/werewolf_claw/right/right_claw

if(extended)
if(istype(owner.get_active_held_item(), /obj/item/weapon/werewolf_claw))
owner.dropItemToGround(l, TRUE)
owner.dropItemToGround(r, TRUE)
qdel(l)
qdel(r)
//owner.visible_message("Your claws retract.", "You feel your claws retracting.", "You hear a sound of claws retracting.")
extended = FALSE
for(var/obj/item/weapon/werewolf_claw/claw in owner.held_items)
qdel(claw)
to_chat(owner, "You feel your claws retracting.")
//owner.visible_message("Your claws retract.", "You feel your claws retracting.", "You hear a sound of claws retracting.")
else
l = new(owner, 1)
r = new(owner, 2)
owner.put_in_hands(l, TRUE, FALSE, TRUE)
owner.put_in_hands(r, TRUE, FALSE, TRUE)
left_claw = new()
right_claw = new()
if(!owner.put_in_l_hand(left_claw))
qdel(left_claw)
if(!owner.put_in_r_hand(right_claw))
qdel(right_claw)
to_chat(owner, "You feel your claws extending.")
//owner.visible_message("Your claws extend.", "You feel your claws extending.", "You hear a sound of claws extending.")
extended = TRUE
extended = !extended

/datum/action/cooldown/spell/woundlick
name = "Lick the wounds"
Expand All @@ -108,8 +105,8 @@
if(!istype(cast_on))
return

if(do_after(owner, 7 SECONDS, cast_on))
var/ramount = 5
if(do_after(owner, 4 SECONDS, cast_on))
var/ramount = 5 // fully metabolized just under 9 seconds. DO NOT ALLOW REAGENT STACKING
var/rid = /datum/reagent/medicine/healthpot
cast_on.reagents.add_reagent(rid, ramount)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
COOLDOWN_START(src, message_cooldown, 5 SECONDS)
human_user.rage_datum.update_rage(10)

if(transformed && !HAS_TRAIT(human_user, TRAIT_PARALYSIS))
if(human_user.rage_datum.check_rage(text2num(WW_RAGE_MEDIUM)))
if(transformed && !HAS_TRAIT(human_user, TRAIT_PARALYSIS) && !human_user.has_status_effect(/datum/status_effect/debuff/silver_bane))
if(human_user.rage_datum.check_rage(WW_RAGE_MEDIUM))
if(human_user.blood_volume > BLOOD_VOLUME_SURVIVE)
for(var/datum/wound/wound as anything in human_user.get_wounds())
wound.heal_wound(1.2)
Expand All @@ -33,26 +33,31 @@
return FALSE
return TRUE

/datum/antagonist/werewolf/proc/begin_transform()
set waitfor = 0

if(!try_transform_checks()) return
/datum/antagonist/werewolf/proc/begin_transform(datum/source, stage = 1)
SIGNAL_HANDLER

var/mob/living/carbon/human/human_user = owner.current
ADD_TRAIT(human_user, TRAIT_NO_TRANSFORM, REF(src))
human_user.flash_fullscreen("redflash3")
human_user.emote("agony", forced = TRUE)
to_chat(human_user, span_userdanger("UNIMAGINABLE PAIN!"))
human_user.Stun(5.1 SECONDS, ignore_canstun = TRUE)
human_user.Knockdown(5.1 SECONDS, ignore_canstun = TRUE)
sleep(2.5 SECONDS)
human_user.emote("agony", forced = TRUE)
sleep(2.5 SECONDS)
REMOVE_TRAIT(human_user, TRAIT_NO_TRANSFORM, REF(src))

if(!try_transform_checks()) return

werewolf_transform()
if(stage == 1)
if(!try_transform_checks())
return
ADD_TRAIT(human_user, TRAIT_NO_TRANSFORM, REF(src))
human_user.flash_fullscreen("redflash3")
INVOKE_ASYNC(human_user, TYPE_PROC_REF(/mob, emote), "agony", null, null, FALSE, TRUE)
to_chat(human_user, span_userdanger("UNIMAGINABLE PAIN!"))
human_user.Stun(5.1 SECONDS, ignore_canstun = TRUE)
human_user.Knockdown(5.1 SECONDS, ignore_canstun = TRUE)
addtimer(CALLBACK(src, PROC_REF(begin_transform), null, 2), 2.5 SECONDS, TIMER_DELETE_ME)

if(stage == 2)
INVOKE_ASYNC(human_user, TYPE_PROC_REF(/mob, emote), "agony", null, null, FALSE, TRUE)
addtimer(CALLBACK(src, PROC_REF(begin_transform), null, 3), 2.5 SECONDS, TIMER_DELETE_ME)

if(stage == 3)
REMOVE_TRAIT(human_user, TRAIT_NO_TRANSFORM, REF(src))
if(!try_transform_checks())
return
INVOKE_ASYNC(src, PROC_REF(werewolf_transform))

/datum/antagonist/werewolf/proc/werewolf_transform()
if(!try_transform_checks()) return
Expand All @@ -78,7 +83,7 @@
new_werewolf.adjustOxyLoss(human_user.getOxyLoss() / 2)
new_werewolf.adjustCloneLoss(human_user.getCloneLoss() / 2)
new_werewolf.blood_volume = human_user.blood_volume
human_user.fully_heal(HEAL_DAMAGE|HEAL_BLOOD|HEAL_WOUNDS|HEAL_RESTRAINTS)
human_user.fully_heal(HEAL_BLOOD|HEAL_WOUNDS|HEAL_RESTRAINTS)

playsound(new_werewolf, pick('sound/combat/gib (1).ogg','sound/combat/gib (2).ogg'), 200, FALSE, 3)
new_werewolf.playsound_local(get_turf(new_werewolf), 'sound/music/wolfintro.ogg', 80, FALSE, pressure_affected = FALSE)
Expand All @@ -92,8 +97,14 @@
/datum/antagonist/werewolf/proc/pre_transformation()
var/mob/living/carbon/human/human_user = owner.current
for(var/obj/item/item as anything in human_user.get_equipped_items(FALSE))
if(istype(item, /obj/item/clothing) || istype(item, /obj/item/storage/belt))
if(istype(item, /obj/item/storage/belt))
item.take_damage(damage_amount = item.max_integrity * 0.15, sound_effect = FALSE)
else if(istype(item, /obj/item/clothing))
var/obj/item/clothing/clothing_item = item
if(clothing_item.armor_class >= AC_HEAVY)
human_user.dropItemToGround(clothing_item, silent = TRUE)
else
clothing_item.take_damage(damage_amount = item.max_integrity * 0.35, sound_effect = FALSE)
else
human_user.dropItemToGround(item, silent = TRUE)

Expand Down Expand Up @@ -132,21 +143,26 @@
for(var/obj/item/dropped_item in werewolf_user)
werewolf_user.dropItemToGround(dropped_item, silent = TRUE)
var/mob/living/carbon/human/caster_mob = status_caster_mob
INVOKE_ASYNC(werewolf_user, TYPE_PROC_REF(/mob, emote), "scream")
INVOKE_ASYNC(werewolf_user, TYPE_PROC_REF(/mob, emote), "scream", null, null, FALSE, TRUE)

to_chat(caster_mob, span_userdanger("The beast within returns to slumber."))
playsound(caster_mob, pick('sound/combat/gib (1).ogg','sound/combat/gib (2).ogg'), 200, FALSE, 3)
caster_mob.Knockdown(30)
caster_mob.Stun(30)
caster_mob.rage_datum.remove_secondary()
caster_mob.rage_datum.rage_change_on_life += transformed_rage_decay
caster_mob.apply_status_effect(/datum/status_effect/debuff/barbfalter/werewolf_untransform)

caster_mob.adjustBruteLoss(werewolf_user.getBruteLoss() / 2)
caster_mob.adjustFireLoss(werewolf_user.getFireLoss() / 2)
caster_mob.adjustToxLoss(werewolf_user.getToxLoss() / 2)
caster_mob.adjustOxyLoss(werewolf_user.getOxyLoss() / 2)
caster_mob.adjustCloneLoss(werewolf_user.getCloneLoss() / 2)
// caster_mob.adjustBruteLoss(werewolf_user.getBruteLoss() / 2)
// caster_mob.adjustFireLoss(werewolf_user.getFireLoss() / 2)
// caster_mob.adjustToxLoss(werewolf_user.getToxLoss() / 2)
// caster_mob.adjustOxyLoss(werewolf_user.getOxyLoss() / 2)
// caster_mob.adjustCloneLoss(werewolf_user.getCloneLoss() / 2)
// caster_mob.blood_volume = werewolf_user.blood_volume

UnregisterSignal(werewolf_user, COMSIG_LIVING_UNSHAPESHIFTED)
transformed = FALSE

// After untransforming, debuffs and blocks rage from damage/stress
/datum/status_effect/debuff/barbfalter/werewolf_untransform
duration = 5 MINUTES
4 changes: 4 additions & 0 deletions code/modules/clothing/ring/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@
desc = "A ring of blessed silver, bearing the Archbishop's symbol. By dipping it in melted redtallow, it can seal writs of religious importance."
sellprice = 90

/obj/item/clothing/ring/signet/silver/Initialize(mapload)
. = ..()
enchant(/datum/enchantment/silver)

/obj/item/clothing/ring/signet/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(tallowed)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@
if(heal_flags & ADMIN_HEAL_ALL)
qdel(wound)
else
wound.heal_wound(wound.whp)
wound.heal_wound(wound.whp, forced = TRUE)

if(heal_flags & HEAL_TEMP)
bodytemperature = BODYTEMP_NORMAL
Expand Down
2 changes: 1 addition & 1 deletion code/modules/spells/spell_types/pointed/lunge.dm
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
var/y_offset = base_y + rand(-3, 3)
animate(pixel_x = x_offset, pixel_y = y_offset, time = 1)

if(!do_after(owner, 2 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_SLOWDOWNS), extra_checks = CALLBACK(src, TYPE_PROC_REF(/datum/action/cooldown/spell/lunge, CheckCanTarget), target_atom), hidden = TRUE))
if(!do_after(owner, 1.5 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_SLOWDOWNS), extra_checks = CALLBACK(src, TYPE_PROC_REF(/datum/action/cooldown/spell/lunge, CheckCanTarget), target_atom), hidden = TRUE))
end_target_lunge(base_x, base_y)

return FALSE
Expand Down
5 changes: 4 additions & 1 deletion code/modules/spells/spell_types/pointed/throw.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
if(QDELETED(owner.pulling) || !isliving(owner.pulling))
return FALSE

if(owner.grab_state < GRAB_AGGRESSIVE)
return FALSE

return TRUE

/datum/action/cooldown/spell/throw_target/proc/prepare_throw(atom/target_atom)
Expand All @@ -69,7 +72,7 @@
var/base_y = owner.base_pixel_y
animate(owner, pixel_x = base_x - 4, pixel_y = base_y, time = 0.5 SECONDS)

if(!do_after(owner, 1 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_SLOWDOWNS), extra_checks = CALLBACK(src, PROC_REF(CheckCanThrow), target_atom), hidden = TRUE))
if(!do_after(owner, 0.8 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_SLOWDOWNS), extra_checks = CALLBACK(src, PROC_REF(CheckCanThrow), target_atom), hidden = TRUE))
end_throw_prep(base_x, base_y)
return FALSE

Expand Down
Loading
Loading