From 1d50393ee1c38ac0cc3b50f0beed231581df3f62 Mon Sep 17 00:00:00 2001
From: BadAtThisGame <79063506+BadAtThisGame302@users.noreply.github.com>
Date: Tue, 17 Dec 2024 01:11:57 +0200
Subject: [PATCH] Werewolf Update + Silver Overhaul (#1231)
* Werewolf and Silver Bane tweaks
* Fixes
* Forgot STA
* Roguetown reference??
* Adds claw sprites
* Guayo updates
---------
Co-authored-by: NPC1314 <110836368+NPC1314@users.noreply.github.com>
---
code/__DEFINES/medical.dm | 2 +
code/_onclick/hud/ghost.dm | 4 +-
code/_onclick/item_attack.dm | 56 ++++-
code/_onclick/other_mobs.dm | 12 +-
code/datums/status_effects/rogue/debuff.dm | 9 +-
code/datums/wounds/_wound.dm | 82 ++++++-
code/datums/wounds/arteries.dm | 4 +-
code/datums/wounds/bruises.dm | 2 +
code/datums/wounds/dislocations.dm | 2 +
code/datums/wounds/fractures.dm | 38 ++--
code/game/gamemodes/objectives_rogue.dm | 12 +-
code/game/objects/items.dm | 3 +
code/game/objects/items/rogueitems/cup.dm | 8 +-
.../items/rogueitems/natural/animals.dm | 21 ++
.../items/rogueweapons/melee/knives.dm | 49 +----
.../items/rogueweapons/melee/swords.dm | 208 +-----------------
.../objects/items/rogueweapons/melee/whips.dm | 54 +----
.../antagonists/roguetown/villain/werewolf.dm | 188 ----------------
.../roguetown/villain/werewolf/werewolf.dm | 184 ++++++++++++++++
.../villain/werewolf/werewolf_spells.dm | 67 ++++++
.../werewolf/werewolf_transformation.dm | 192 ++++++++++++++++
code/modules/error_handler/error_viewer.dm | 2 +-
.../species_types/roguetown/other/werewolf.dm | 8 +-
code/modules/mob/living/grabbing.dm | 76 +++----
code/modules/mob/roguetransform.dm | 153 -------------
code/modules/surgery/bodyparts/_bodyparts.dm | 21 +-
icons/roguetown/weapons/32.dmi | Bin 73207 -> 76054 bytes
stonekeep.dme | 5 +-
28 files changed, 709 insertions(+), 753 deletions(-)
delete mode 100644 code/modules/antagonists/roguetown/villain/werewolf.dm
create mode 100644 code/modules/antagonists/roguetown/villain/werewolf/werewolf.dm
create mode 100644 code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm
create mode 100644 code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm
delete mode 100644 code/modules/mob/roguetransform.dm
diff --git a/code/__DEFINES/medical.dm b/code/__DEFINES/medical.dm
index 9ff7070366..1325d5138a 100644
--- a/code/__DEFINES/medical.dm
+++ b/code/__DEFINES/medical.dm
@@ -87,3 +87,5 @@
#define WOUND_SEVERITY_CRITICAL 4
/// Wounds that are almost immediately fatal, such as a dissected aorta
#define WOUND_SEVERITY_FATAL 5
+/// This wound has werewolf infection
+#define WOUND_SEVERITY_BIOHAZARD 6
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index 6264c83b20..2ef17d3ede 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -56,12 +56,12 @@
// Store the current time for the player
GLOB.job_respawn_delays[G.ckey] = world.time + target_job.same_job_respawn_delay
+ verbs -= /client/proc/descend
for(var/turf/spawn_loc in GLOB.underworldcoinspawns)
var/mob/living/carbon/spirit/O = new /mob/living/carbon/spirit(spawn_loc)
O.livingname = G.name
O.ckey = G.ckey
SSdroning.area_entered(get_area(O), O.client)
- verbs -= /client/proc/descend
return
// var/take_triumph = FALSE
@@ -70,12 +70,12 @@
if(C.skeletons)
G.returntolobby()
if(alert("Travel with the boatman?", "", "Yes", "No") == "Yes")
+ verbs -= /client/proc/descend
for(var/turf/spawn_loc in GLOB.underworldcoinspawns)
var/mob/living/carbon/spirit/O = new /mob/living/carbon/spirit(spawn_loc)
O.livingname = G.name
O.ckey = G.ckey
SSdroning.area_entered(get_area(O), O.client)
- verbs -= /client/proc/descend
/* if(world.time < G.ghostize_time + RESPAWNTIME)
var/ttime = round((G.ghostize_time + RESPAWNTIME - world.time) / 10)
var/list/thingsz = list("My connection to the world is still too strong.",\
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 00d4130b2c..b77a938a50 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -9,14 +9,14 @@
*/
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
if(user.check_arm_grabbed(user.active_hand_index))
- to_chat(user, "I can't move my arm!")
+ to_chat(user, span_notice("I can't move my arm!"))
return
if(!user.has_hand_for_held_index(user.active_hand_index, TRUE)) //we obviously have a hadn, but we need to check for fingers/prosthetics
- to_chat(user, "I can't move the fingers.")
+ to_chat(user, span_warning("I can't move the fingers."))
return
if(!istype(src, /obj/item/grabbing))
if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS))
- to_chat(user, "...What?")
+ to_chat(user, span_warning("...What?"))
return
if(tool_behaviour && target.tool_act(user, src, tool_behaviour))
return
@@ -80,7 +80,7 @@
return FALSE
if(force && HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "I don't want to harm other living beings!")
+ to_chat(user, span_warning("I don't want to harm other living beings!"))
return
M.lastattacker = user.real_name
@@ -363,12 +363,12 @@
verbu = pick(user.used_intent.attack_verb)
if(newforce > 1)
if(user.rogfat_add(5))
- user.visible_message("[user] [verbu] [src] with [I]!")
+ user.visible_message(span_danger("[user] [verbu] [src] with [I]!"))
else
- user.visible_message("[user] [verbu] [src] with [I]!")
+ user.visible_message(span_warning("[user] [verbu] [src] with [I]!"))
newforce = 1
else
- user.visible_message("[user] [verbu] [src] with [I]!")
+ user.visible_message(span_warning("[user] [verbu] [src] with [I]!"))
take_damage(newforce, I.damtype, "melee", 1)
if(newforce > 1)
I.take_damage(1, BRUTE, "melee")
@@ -390,12 +390,12 @@
verbu = pick(user.used_intent.attack_verb)
if(newforce > 1)
if(user.rogfat_add(5))
- user.visible_message("[user] [verbu] [src] with [I]!")
+ user.visible_message(span_danger("[user] [verbu] [src] with [I]!"))
else
- user.visible_message("[user] [verbu] [src] with [I]!")
+ user.visible_message(span_warning("[user] [verbu] [src] with [I]!"))
newforce = 1
else
- user.visible_message("[user] [verbu] [src] with [I]!")
+ user.visible_message(span_warning("[user] [verbu] [src] with [I]!"))
take_damage(newforce, I.damtype, "melee", 1)
if(newforce > 1)
@@ -451,6 +451,42 @@
return "body"
/obj/item/proc/funny_attack_effects(mob/living/target, mob/living/user, nodmg)
+ if(is_silver)
+ if(world.time < src.last_used + 120)
+ to_chat(user, span_notice("The silver effect is on cooldown."))
+ return
+
+ if(ishuman(target) && target.mind)
+ var/mob/living/carbon/human/s_user = user
+ var/mob/living/carbon/human/H = target
+ var/datum/antagonist/werewolf/W = H.mind.has_antag_datum(/datum/antagonist/werewolf/)
+ var/datum/antagonist/vampirelord/lesser/V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
+ var/datum/antagonist/vampirelord/V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
+ if(V)
+ if(V.disguised)
+ H.visible_message("The silver weapon weakens the curse temporarily!")
+ to_chat(H, span_userdanger("I'm hit by my BANE!"))
+ H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
+ src.last_used = world.time
+ else
+ H.visible_message("The silver weapon weakens the curse temporarily!")
+ to_chat(H, span_userdanger("I'm hit by my BANE!"))
+ H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
+ src.last_used = world.time
+ if(V_lord)
+ if(V_lord.vamplevel < 4 && !V)
+ H.visible_message("The silver weapon weakens the curse temporarily!")
+ to_chat(H, span_userdanger("I'm hit by my BANE!"))
+ H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
+ src.last_used = world.time
+ if(V_lord.vamplevel == 4 && !V)
+ to_chat(s_user, " The silver weapon fails!")
+ H.visible_message(H, span_userdanger("This feeble metal can't hurt me, I AM ANCIENT!"))
+ if(W && W.transformed == TRUE)
+ H.visible_message("The silver weapon weakens the curse temporarily!")
+ to_chat(H, span_userdanger("I'm hit by my BANE!"))
+ H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
+ src.last_used = world.time
return
/mob/living/attacked_by(obj/item/I, mob/living/user)
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 5190fa5f17..367d03d6f3 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -203,15 +203,19 @@
next_attack_msg.Cut()
+ var/datum/wound/caused_wound
+ if(!nodmg)
+ caused_wound = affecting.bodypart_attacked_by(BCLASS_BITE, dam2do, user, user.zone_selected, crit_message = TRUE)
+
if(!nodmg)
playsound(src, "smallslash", 100, TRUE, -1)
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if(user.mind && mind)
- if(user.mind.has_antag_datum(/datum/antagonist/werewolf))
- if(!src.mind.has_antag_datum(/datum/antagonist/werewolf))
- if(prob(10))
- addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living/carbon/human, werewolf_infect)), 3 MINUTES)
+ if(istype(user.dna.species, /datum/species/werewolf))
+ caused_wound?.werewolf_infect_attempt()
+ if(prob(30))
+ user.werewolf_feed(src)
if(user.mind.has_antag_datum(/datum/antagonist/zombie) && !src.mind.has_antag_datum(/datum/antagonist/zombie))
INVOKE_ASYNC(H, TYPE_PROC_REF(/mob/living/carbon/human, zombie_infect_attempt))
diff --git a/code/datums/status_effects/rogue/debuff.dm b/code/datums/status_effects/rogue/debuff.dm
index bba9ca7759..1d6fb8ee40 100644
--- a/code/datums/status_effects/rogue/debuff.dm
+++ b/code/datums/status_effects/rogue/debuff.dm
@@ -77,17 +77,14 @@
/datum/status_effect/debuff/silver_curse
id = "silver_curse"
alert_type = /atom/movable/screen/alert/status_effect/debuff/silver_curse
- duration = 5 SECONDS
-/* Pointless subtype, code doesnt handle it well, dont use
-/datum/status_effect/debuff/silver_curse/greater
- duration = 10 SECONDS
-*/
+ effectedstats = list("strength" = -2,"perception" = -2,"intelligence" = -2, "constitution" = -2, "endurance" = -2,"speed" = -2)
+ duration = 45 SECONDS
+
/atom/movable/screen/alert/status_effect/debuff/silver_curse
name = "Silver Curse"
desc = "My BANE!"
icon_state = "hunger3"
-
// PINTLEDESTRUCTION
/datum/status_effect/debuff/pintledestruction
diff --git a/code/datums/wounds/_wound.dm b/code/datums/wounds/_wound.dm
index eb3ab978d9..e9683faf22 100644
--- a/code/datums/wounds/_wound.dm
+++ b/code/datums/wounds/_wound.dm
@@ -75,12 +75,22 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/// Some wounds make no sense on a dismembered limb and need to go
var/qdel_on_droplimb = FALSE
+ /// Werewolf infection probability for bites on this wound
+ var/werewolf_infection_probability = 15
+ /// Time taken until werewolf infection comes in
+ var/werewolf_infection_time = 2 MINUTES
+ /// Actual infection timer
+ var/werewolf_infection_timer
+
/datum/wound/Destroy(force)
. = ..()
if(bodypart_owner)
remove_from_bodypart()
else if(owner)
remove_from_mob()
+ if(werewolf_infection_timer)
+ deltimer(werewolf_infection_timer)
+ werewolf_infection_timer = null
bodypart_owner = null
owner = null
@@ -90,9 +100,9 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
return
var/visible_name = name
if(is_sewn())
- visible_name += " (sewn)"
+ visible_name += span_green("(sewn)")
if(is_clotted())
- visible_name += " (clotted)"
+ visible_name += span_danger("(clotted)")
return visible_name
/// Description of this wound returned to the player when the bodypart is checked with check_for_injuries()
@@ -148,11 +158,11 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
else if(owner)
remove_from_mob()
LAZYADD(affected.wounds, src)
- sortList(affected.wounds, GLOBAL_PROC_REF(cmp_wound_severity_dsc))
+ sortTim(affected.wounds, GLOBAL_PROC_REF(cmp_wound_severity_dsc))
bodypart_owner = affected
owner = bodypart_owner.owner
on_bodypart_gain(affected)
- on_mob_gain(affected.owner)
+ INVOKE_ASYNC(src, PROC_REF(on_mob_gain), affected.owner) //this is literally a fucking lint error like new species cannot possible spawn with wounds until after its ass
if(crit_message)
var/message = get_crit_message(affected.owner, affected)
if(message)
@@ -223,6 +233,10 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/datum/wound/proc/on_mob_gain(mob/living/affected)
if(mob_overlay)
affected.update_damage_overlays()
+ if(werewolf_infection_timer)
+ deltimer(werewolf_infection_timer)
+ werewolf_infection_timer = null
+ werewolf_infect_attempt()
/// Removes this wound from a given, simpler than adding to a bodypart - No extra effects
/datum/wound/proc/remove_from_mob()
@@ -249,7 +263,7 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/// Called on handle_wounds(), on the life() proc
/datum/wound/proc/on_death()
return
-
+
/// Heals this wound by the given amount, and deletes it if it's healed completely
/datum/wound/proc/heal_wound(heal_amount)
// Wound cannot be healed normally, whp is null
@@ -258,12 +272,13 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
var/amount_healed = min(whp, round(heal_amount, DAMAGE_PRECISION))
whp -= amount_healed
if(whp <= 0)
- if(bodypart_owner)
- remove_from_bodypart(src)
- else if(owner)
- remove_from_mob(src)
- else
- qdel(src)
+ if(!should_persist())
+ if(bodypart_owner)
+ remove_from_bodypart(src)
+ else if(owner)
+ remove_from_mob(src)
+ else
+ qdel(src)
return amount_healed
/// Sews the wound up, changing its properties to the sewn ones
@@ -285,6 +300,16 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
owner?.update_damage_overlays()
return TRUE
+/// Checks if this wound has a special infection (zombie or werewolf)
+/datum/wound/proc/has_special_infection()
+ return (werewolf_infection_timer)
+
+/// Some wounds cannot go away naturally
+/datum/wound/proc/should_persist()
+ if(has_special_infection())
+ return TRUE
+ return FALSE
+
/// Cauterizes the wound
/datum/wound/proc/cauterize_wound()
if(!can_cauterize)
@@ -302,6 +327,41 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/datum/wound/proc/is_clotted()
return !isnull(clotting_threshold) && (bleed_rate <= clotting_threshold)
+/datum/wound/proc/werewolf_infect_attempt()
+ if(QDELETED(src) || QDELETED(owner) || QDELETED(bodypart_owner))
+ return FALSE
+ if(werewolf_infection_timer || !ishuman(owner) || !prob(werewolf_infection_probability))
+ return
+ var/mob/living/carbon/human/human_owner = owner
+ if(!human_owner.can_werewolf())
+ return
+ if(human_owner.stat >= DEAD) //forget it
+ return
+ to_chat(human_owner, span_danger("I feel horrible... REALLY horrible..."))
+ human_owner.mob_timers["puke"] = world.time
+ human_owner.vomit(1, blood = TRUE, stun = FALSE)
+ werewolf_infection_timer = addtimer(CALLBACK(src, PROC_REF(wake_werewolf)), werewolf_infection_time, TIMER_STOPPABLE)
+ severity = WOUND_SEVERITY_BIOHAZARD
+ if(bodypart_owner)
+ sortTim(bodypart_owner.wounds, GLOBAL_PROC_REF(cmp_wound_severity_dsc))
+ return TRUE
+
+/datum/wound/proc/wake_werewolf()
+ if(QDELETED(src) || QDELETED(owner) || QDELETED(bodypart_owner))
+ return FALSE
+ if(!ishuman(owner))
+ return FALSE
+ var/mob/living/carbon/human/human_owner = owner
+ var/datum/antagonist/werewolf/wolfy = human_owner.werewolf_check()
+ if(!wolfy)
+ return FALSE
+ werewolf_infection_timer = null
+ owner.flash_fullscreen("redflash3")
+ to_chat(owner, span_danger("It hurts... Is this really the end for me?"))
+ owner.emote("scream") // heres your warning to others bro
+ owner.Knockdown(1)
+ return wolfy
+
/// Returns whether or not this wound should embed a weapon
/proc/should_embed_weapon(datum/wound/wound_or_boolean, obj/item/weapon)
if(!istype(wound_or_boolean))
diff --git a/code/datums/wounds/arteries.dm b/code/datums/wounds/arteries.dm
index 78e4340e2c..9953aefc11 100644
--- a/code/datums/wounds/arteries.dm
+++ b/code/datums/wounds/arteries.dm
@@ -20,6 +20,8 @@
sleep_healing = 0
embed_chance = 0
+ werewolf_infection_probability = 100
+
/datum/wound/artery/can_stack_with(datum/wound/other)
if(istype(other, /datum/wound/artery) && (type == other.type))
return FALSE
@@ -79,7 +81,7 @@
"MY HEART IS TORN!",
"MY HEART IS BLEEDING!",
)
- to_chat(affected, "[pick(heartaches)]")
+ to_chat(affected, span_userdanger("[pick(heartaches)]"))
if(HAS_TRAIT(affected, TRAIT_CRITICAL_WEAKNESS))
affected.death()
if(affected.mind.has_antag_datum(/datum/antagonist/vampirelord/))
diff --git a/code/datums/wounds/bruises.dm b/code/datums/wounds/bruises.dm
index 61ca92e7b5..54a714eb9a 100644
--- a/code/datums/wounds/bruises.dm
+++ b/code/datums/wounds/bruises.dm
@@ -10,6 +10,8 @@
can_cauterize = FALSE
passive_healing = 0.5
+ werewolf_infection_probability = 0
+
/datum/wound/bruise/small
name = "bruise"
whp = 15
diff --git a/code/datums/wounds/dislocations.dm b/code/datums/wounds/dislocations.dm
index 32bc7098eb..bbe68dbe70 100644
--- a/code/datums/wounds/dislocations.dm
+++ b/code/datums/wounds/dislocations.dm
@@ -19,6 +19,8 @@
critical = TRUE
passive_healing = 0.25
qdel_on_droplimb = TRUE
+
+ werewolf_infection_probability = 0
/// Whether or not we can be surgically relocated
var/can_relocate = TRUE
diff --git a/code/datums/wounds/fractures.dm b/code/datums/wounds/fractures.dm
index 68b5b0e0e8..b715b286b3 100644
--- a/code/datums/wounds/fractures.dm
+++ b/code/datums/wounds/fractures.dm
@@ -3,9 +3,9 @@
check_name = "FRACTURE"
severity = WOUND_SEVERITY_SEVERE
crit_message = list(
- "The bone shatters!",
- "The bone is broken!",
- "The %BODYPART is mauled!",
+ "The bone shatters!",
+ "The bone is broken!",
+ "The %BODYPART is mauled!",
"The bone snaps through the skin!",
)
sound_effect = "wetbreak"
@@ -16,7 +16,9 @@
can_cauterize = FALSE
disabling = TRUE
critical = TRUE
- sleep_healing = 0 // no sleep healing that is retarded
+ sleep_healing = 0 // no sleep healing that is dumb
+
+ werewolf_infection_probability = 0
/// Whether or not we can be surgically set
var/can_set = TRUE
/// Emote we use when applied
@@ -25,7 +27,7 @@
/datum/wound/fracture/get_visible_name(mob/user)
. = ..()
if(passive_healing)
- . += " (set)"
+ . += span_green("(set)")
/datum/wound/fracture/can_stack_with(datum/wound/other)
if(istype(other, /datum/wound/fracture) && (type == other.type))
@@ -50,9 +52,9 @@
name = "cranial fracture"
check_name = "SKULLCRACK"
crit_message = list(
- "The skull shatters in a gruesome way!",
- "The head is smashed!",
- "The skull is broken!",
+ "The skull shatters in a gruesome way!",
+ "The head is smashed!",
+ "The skull is broken!",
"The skull caves in!",
)
sound_effect = "headcrush"
@@ -114,7 +116,7 @@
paralysis = TRUE
mortal = TRUE
dents_brain = TRUE
-
+
/datum/wound/fracture/head/brain/on_life()
. = ..()
owner.adjustOxyLoss(2.5)
@@ -153,9 +155,9 @@
name = "mandibular fracture"
check_name = "JAW FRACTURE"
crit_message = list(
- "The mandible comes apart beautifully!",
- "The jaw is smashed!",
- "The jaw is shattered!",
+ "The mandible comes apart beautifully!",
+ "The jaw is smashed!",
+ "The jaw is shattered!",
"The jaw caves in!",
)
whp = 50
@@ -175,7 +177,7 @@
name = "cervical fracture"
check_name = "NECK"
crit_message = list(
- "The spine shatters in a spectacular way!",
+ "The spine shatters in a spectacular way!",
"The spine snaps!",
"The spine cracks!",
"The spine is broken!",
@@ -198,7 +200,7 @@
if(iscarbon(affected))
var/mob/living/carbon/carbon_affected = affected
carbon_affected.update_disabled_bodyparts()
-
+
/datum/wound/fracture/neck/on_life()
. = ..()
owner.adjustOxyLoss(2.5)
@@ -222,9 +224,9 @@
name = "pelvic fracture"
check_name = "PELVIS"
crit_message = list(
- "The pelvis shatters in a magnificent way!",
- "The pelvis is smashed!",
- "The pelvis is mauled!",
+ "The pelvis shatters in a magnificent way!",
+ "The pelvis is smashed!",
+ "The pelvis is mauled!",
"The pelvic floor caves in!",
)
whp = 50
@@ -236,7 +238,7 @@
name = "broken buck"
check_name = "BUCKBROKEN"
crit_message = "The buck is broken expertly!"
-
+
/datum/wound/fracture/groin/on_mob_gain(mob/living/affected)
. = ..()
affected.Stun(20)
diff --git a/code/game/gamemodes/objectives_rogue.dm b/code/game/gamemodes/objectives_rogue.dm
index cb3ae84474..30f505aeea 100644
--- a/code/game/gamemodes/objectives_rogue.dm
+++ b/code/game/gamemodes/objectives_rogue.dm
@@ -15,12 +15,12 @@
if(C)
explanation_text = "Feed [C.banditgoal] mammon to an idol of greed."
else
- explanation_text = "Pray to ZIZO."
+ explanation_text = "Pray to Matthios."
/datum/objective/delf
name = "delf"
- explanation_text = "Feed honeys to the mother."
+ explanation_text = "Feed honeys to the silkseed bearer."
/datum/objective/delf/check_completion()
if(SSticker.mode)
@@ -33,9 +33,9 @@
if(SSticker.mode)
var/datum/game_mode/chaosmode/C = SSticker.mode
if(C)
- explanation_text = "Feed [C.delfgoal] honeys to the mother."
+ explanation_text = "Feed [C.delfgoal] honeys to the silkseed bearer."
else
- explanation_text = "Pray to ZIZO."
+ explanation_text = "Pray to Ananshor."
/datum/objective/rt_maniac
name = "slaying"
@@ -50,7 +50,7 @@
/datum/objective/werewolf
name = "conquer"
- explanation_text = "Destroy all elder vampires in ROGUETOWN. I can sniff them in my true form."
+ explanation_text = "The hubric arrogant rot of Noc stains the town of Rockhill, I must slay the elder vampires. I can smell their decay in my true form."
team_explanation_text = ""
triumph_count = 5
@@ -62,7 +62,7 @@
/datum/objective/vampire
name = "conquer"
- explanation_text = "Destroy all alpha werewolves in ROGUETOWN. I can detect them in my true form."
+ explanation_text = "The savage maddening stink of Dendorian perversion fluxes within Rockhill. Destroying the werbeast is imperative, I can sense them in my true form."
team_explanation_text = ""
triumph_count = 5
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index d3672ff1c1..6054bf0d50 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -224,6 +224,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/onprop = list()
var/force_reupdate_inhand = TRUE
+ var/is_silver = FALSE
+ var/last_used = 0
+
// Boolean sanity var for smelteries to avoid runtimes. Is this is a bar smelted through ore for exp gain?
var/smelted = FALSE
// Can this be used against a training dummy to learn skills? Prevents dumb exploits.
diff --git a/code/game/objects/items/rogueitems/cup.dm b/code/game/objects/items/rogueitems/cup.dm
index dfb9db0179..a5ad296622 100644
--- a/code/game/objects/items/rogueitems/cup.dm
+++ b/code/game/objects/items/rogueitems/cup.dm
@@ -50,15 +50,11 @@
desc = "A silver goblet, its surface adorned with intricate carvings and runes."
icon_state = "silver"
sellprice = 30
+ last_used = 0
+ is_silver = TRUE
/obj/item/reagent_containers/glass/cup/silver/funny_attack_effects(mob/living/target, mob/living/user, nodmg)
. = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- if(H.dna && H.dna.species)
- if(istype(H.dna.species, /datum/species/werewolf))
- target.Knockdown(30)
- target.Stun(30)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/vampirelord))
var/datum/antagonist/vampirelord/VD = target.mind.has_antag_datum(/datum/antagonist/vampirelord)
if(!VD.disguised)
diff --git a/code/game/objects/items/rogueitems/natural/animals.dm b/code/game/objects/items/rogueitems/natural/animals.dm
index 5bf2a85149..742036360a 100644
--- a/code/game/objects/items/rogueitems/natural/animals.dm
+++ b/code/game/objects/items/rogueitems/natural/animals.dm
@@ -99,3 +99,24 @@
var/obj/item/ssaddle
var/simple_detect_bonus = 0 // A flat percentage bonus to our ability to detect sneaking people only. Use in lieu of giving mobs huge STAPER bonuses if you want them to be observant.
+/mob/living/simple_animal/onbite(mob/living/carbon/human/user)
+ var/damage = 10*(user.STASTR/20)
+ if(HAS_TRAIT(user, TRAIT_STRONGBITE))
+ damage = damage*2
+ playsound(user.loc, "smallslash", 100, FALSE, -1)
+ user.next_attack_msg.Cut()
+ if(stat == DEAD)
+ if(user.has_status_effect(/datum/status_effect/debuff/silver_curse))
+ to_chat(user, span_notice("My power is weakened, I cannot heal!"))
+ return
+ if(user.mind && istype(user, /mob/living/carbon/human/species/werewolf))
+ visible_message(span_danger("The werewolf ravenously consumes the [src]!"))
+ to_chat(src, span_warning("I feed on succulent flesh. I feel reinvigorated."))
+ user.reagents.add_reagent(/datum/reagent/medicine/healthpot, 30)
+ gib()
+ return
+ if(src.apply_damage(damage, BRUTE))
+ if(istype(user, /mob/living/carbon/human/species/werewolf))
+ visible_message(span_danger("The werewolf bites into [src] and thrashes!"))
+ else
+ visible_message(span_danger("[user] bites [src]! What is wrong with them?"))
diff --git a/code/game/objects/items/rogueweapons/melee/knives.dm b/code/game/objects/items/rogueweapons/melee/knives.dm
index 18f79fe1f3..bacc260a1b 100644
--- a/code/game/objects/items/rogueweapons/melee/knives.dm
+++ b/code/game/objects/items/rogueweapons/melee/knives.dm
@@ -204,7 +204,8 @@
max_blade_int = 112 // .8 of steel
max_integrity = 240 // .8 of steel
sellprice = 45
- var/last_used = 0
+ last_used = 0
+ is_silver = TRUE
/obj/item/rogueweapon/knife/dagger/silver/pickup(mob/user)
. = ..()
@@ -238,52 +239,6 @@
if(V_lord.vamplevel < 4 && !H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser))
H.Knockdown(10)
-/obj/item/rogueweapon/knife/dagger/silver/funny_attack_effects(mob/living/target, mob/living/user = usr, nodmg)
- if(world.time < src.last_used + 100)
- to_chat(user, "The silver effect is on cooldown.")
- return
-
- . = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/s_user = user
- var/mob/living/carbon/human/H = target
- var/datum/antagonist/vampirelord/lesser/V = FALSE
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
- var/datum/antagonist/vampirelord/V_lord = FALSE
- if(H.mind.has_antag_datum(/datum/antagonist/vampirelord/))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(V)
- if(V.disguised)
- H.visible_message("The silver weapon manifests the [H] curse!")
- to_chat(H, "I'm hit by my BANE!")
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- else
- to_chat(H, "I'm hit by my BANE!")
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord)
- if(V_lord.vamplevel < 4 && !V)
- to_chat(H, "I'm hit by my BANE!")
- H.Knockdown(10)
- H.fire_act(1,4)
- src.last_used = world.time
- if(V_lord.vamplevel == 4 && !V)
- s_user.Knockdown(10)
- to_chat(s_user, " The silver weapon fails!")
- H.visible_message(H, "This feeble metal can't hurt me, I HAVE TRANSCENDED!")
- return
- //I hate that i have to add a unique line of this code to EVERY silver weapon because they dont share a universal unique damage. -IP
- //if is non carbon undead burn the fuck.
- if((target.mob_biotypes & MOB_UNDEAD))
- target.adjustFireLoss(25)
- return
-
//................ Profane Dagger ............... //
/obj/item/rogueweapon/knife/dagger/steel/profane
// name = "profane dagger"
diff --git a/code/game/objects/items/rogueweapons/melee/swords.dm b/code/game/objects/items/rogueweapons/melee/swords.dm
index 2fa74ab651..38314a1e4f 100644
--- a/code/game/objects/items/rogueweapons/melee/swords.dm
+++ b/code/game/objects/items/rogueweapons/melee/swords.dm
@@ -194,7 +194,8 @@
smeltresult = /obj/item/ingot/silver
max_integrity = INTEGRITY_STRONG
sellprice = 45
- var/last_used = 0
+ last_used = 0
+ is_silver = TRUE
/obj/item/rogueweapon/sword/silver/pickup(mob/user)
. = ..()
@@ -230,49 +231,6 @@
H.Knockdown(10)
H.Paralyze(1)
-/obj/item/rogueweapon/sword/silver/funny_attack_effects(mob/living/target, mob/living/user = usr, nodmg)
- if(world.time < src.last_used + 100)
- to_chat(user, "The silver effect is on cooldown.")
- return
-
- . = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/s_user = user
- var/mob/living/carbon/human/H = target
- var/datum/antagonist/vampirelord/lesser/V = FALSE
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
- var/datum/antagonist/vampirelord/V_lord = FALSE
- if(H.mind.has_antag_datum(/datum/antagonist/vampirelord/))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(V)
- if(V.disguised)
- H.visible_message("The silver weapon manifests the [H] curse!")
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- else
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord)
- if(V_lord.vamplevel < 4 && !V)
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(25)
- H.Knockdown(10)
- H.fire_act(1,4)
- src.last_used = world.time
- if(V_lord.vamplevel == 4 && !V)
- s_user.Knockdown(10)
- to_chat(s_user, " The silver weapon fails!")
- H.visible_message(H, "This feeble metal can't hurt me, I HAVE TRANSCENDED!")
-
/obj/item/rogueweapon/sword/iron
force = DAMAGE_SWORD-1
force_wielded = DAMAGE_SWORD_WIELD-1
@@ -465,7 +423,8 @@
max_blade_int = 240 // .8 of base steel
max_integrity = 400 // .8 of base steel
sellprice = 45
- var/last_used = 0
+ last_used = 0
+ is_silver = TRUE
/obj/item/rogueweapon/sword/rapier/silver/pickup(mob/user)
. = ..()
@@ -501,49 +460,6 @@
H.Knockdown(10)
H.Paralyze(1)
-/obj/item/rogueweapon/sword/rapier/silver/funny_attack_effects(mob/living/target, mob/living/user = usr, nodmg)
- if(world.time < src.last_used + 100)
- to_chat(user, "The silver effect is on cooldown.")
- return
-
- . = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/s_user = user
- var/mob/living/carbon/human/H = target
- var/datum/antagonist/vampirelord/lesser/V = FALSE
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
- var/datum/antagonist/vampirelord/V_lord = FALSE
- if(H.mind.has_antag_datum(/datum/antagonist/vampirelord/))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(V)
- if(V.disguised)
- H.visible_message("The silver weapon manifests the [H] curse!")
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- else
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord)
- if(V_lord.vamplevel < 4 && !V)
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(25)
- H.Knockdown(10)
- H.fire_act(1,4)
- src.last_used = world.time
- if(V_lord.vamplevel == 4 && !V)
- s_user.Knockdown(10)
- to_chat(s_user, " The silver weapon fails!")
- H.visible_message(H, "This feeble metal can't hurt me, I HAVE TRANSCENDED!")
-
// Hoplite Kophesh
/obj/item/rogueweapon/sword/khopesh
name = "ancient khopesh"
@@ -635,7 +551,8 @@
desc = "A sword with a silvered grip, a jeweled hilt and a honed blade; a design fit for nobility."
sellprice = 363
static_price = TRUE
- var/last_used = 0
+ last_used = 0
+ is_silver = TRUE
/obj/item/rogueweapon/sword/long/judgement/getonmobprop(tag)
. = ..()
@@ -663,73 +580,6 @@
H.Knockdown(10)
H.Paralyze(1)
-/obj/item/rogueweapon/sword/long/judgement/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
- . = ..()
- if(ishuman(M))
- var/datum/antagonist/vampirelord/V_lord = FALSE
- var/mob/living/carbon/human/H = M
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- to_chat(H, "I cannot equip this, it is made of my BANE!")
- H.Knockdown(20)
- H.adjustFireLoss(60)
- H.Paralyze(1)
- H.fire_act(1,5)
- if(V_lord)
- if(V_lord.vamplevel < 4 && !H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- to_chat(H, "I cannot equip this, it is made of my BANE!")
- H.Knockdown(10)
- H.Paralyze(1)
- else
- if(prob(25))
- H.fire_act(1,3)
-
-/obj/item/rogueweapon/sword/long/judgement/funny_attack_effects(mob/living/target, mob/living/user = usr, nodmg)
- if(world.time < src.last_used + 120)
- to_chat(user, "The silver effect is on cooldown.")
- return
-
- . = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/s_user = user
- var/mob/living/carbon/human/H = target
- var/datum/antagonist/vampirelord/lesser/V = FALSE
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
- var/datum/antagonist/vampirelord/V_lord = FALSE
- if(H.mind.has_antag_datum(/datum/antagonist/vampirelord/))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(V)
- if(V.disguised)
- H.visible_message("The silver weapon undoes [H]'s wicked disguise!")
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(60)
- H.Knockdown(30)
- H.fire_act(1,5)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- else
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(60)
- H.Knockdown(30)
- H.fire_act(1,5)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord)
- if(V_lord.vamplevel < 4 && !V)
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord.vamplevel == 4 && !V)
- if(prob(25))
- H.fire_act(1,3)
- to_chat(s_user, " The silver weapon barely works against such an abomination!")
- H.visible_message(H, "This feeble metal can't stop me, I HAVE TRANSCENDED!")
-
/obj/item/rogueweapon/sword/long/vlord // this sprite is a one handed sword, not a longsword.
force = DAMAGE_SWORD
force_wielded = DAMAGE_LONGSWORD_WIELD+2
@@ -785,7 +635,8 @@
wbalance = -1
wdefense = 4
sellprice = 90
- var/last_used = 0
+ last_used = 0
+ is_silver = TRUE
/obj/item/rogueweapon/sword/long/forgotten/pickup(mob/user)
. = ..()
@@ -821,49 +672,6 @@
H.Knockdown(10)
H.Paralyze(1)
-/obj/item/rogueweapon/sword/long/forgotten/funny_attack_effects(mob/living/target, mob/living/user = usr, nodmg)
- if(world.time < src.last_used + 100)
- to_chat(user, "The silver effect is on cooldown.")
- return
-
- . = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/s_user = user
- var/mob/living/carbon/human/H = target
- var/datum/antagonist/vampirelord/lesser/V = FALSE
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
- var/datum/antagonist/vampirelord/V_lord = FALSE
- if(H.mind.has_antag_datum(/datum/antagonist/vampirelord/))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(V)
- if(V.disguised)
- H.visible_message("The silver weapon manifests the [H] curse!")
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- else
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord)
- if(V_lord.vamplevel < 4 && !V)
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(25)
- H.Knockdown(10)
- H.fire_act(1,4)
- src.last_used = world.time
- if(V_lord.vamplevel == 4 && !V)
- s_user.Knockdown(10)
- to_chat(s_user, " The silver weapon fails!")
- H.visible_message(H, "This feeble metal can't hurt me, I HAVE TRANSCENDED!")
-
//................ Greatsword ............... //
/obj/item/rogueweapon/sword/long/greatsword
force = DAMAGE_SWORD_WIELD //If someone can one-hand this, props to them.
diff --git a/code/game/objects/items/rogueweapons/melee/whips.dm b/code/game/objects/items/rogueweapons/melee/whips.dm
index a656550ba9..1a4a178b17 100644
--- a/code/game/objects/items/rogueweapons/melee/whips.dm
+++ b/code/game/objects/items/rogueweapons/melee/whips.dm
@@ -75,11 +75,12 @@
resistance_flags = FIRE_PROOF
smeltresult = /obj/item/ingot/steel
sellprice = 50
-
+
/obj/item/rogueweapon/whip/antique/silver
name = "Contemptum"
desc = "An extremely well maintained whip, with a gleaming silver tip and gilded handle. Both bane and punishment."
- var/last_used = 0
+ last_used = 0
+ is_silver = TRUE
/obj/item/rogueweapon/whip/antique/silver/pickup(mob/user)
. = ..()
@@ -98,55 +99,6 @@
H.Knockdown(10)
H.Paralyze(1)
-/obj/item/rogueweapon/whip/antique/silver/funny_attack_effects(mob/living/target, mob/living/user = usr, nodmg)
- if(world.time < src.last_used + 100)
- to_chat(user, "The silver effect is on cooldown.")
- return
-
- . = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/s_user = user
- var/mob/living/carbon/human/H = target
- var/datum/antagonist/vampirelord/lesser/V = FALSE
- if(H.mind?.has_antag_datum(/datum/antagonist/vampirelord/lesser))
- V = H.mind.has_antag_datum(/datum/antagonist/vampirelord/lesser)
- var/datum/antagonist/vampirelord/V_lord = FALSE
- if(H.mind.has_antag_datum(/datum/antagonist/vampirelord/))
- V_lord = H.mind.has_antag_datum(/datum/antagonist/vampirelord/)
- if(V)
- if(V.disguised)
- H.visible_message("The silver weapon undoes [H]'s wicked disguise!")
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(30)
- H.fire_act(1,5)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- else
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(30)
- H.Knockdown(30)
- H.fire_act(1,5)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse)
- src.last_used = world.time
- if(V_lord)
- if(V_lord.vamplevel < 4 && !V)
- to_chat(H, "I'm hit by my BANE!")
- H.adjustFireLoss(20)
- H.Knockdown(20)
- H.fire_act(1,4)
- H.apply_status_effect(/datum/status_effect/debuff/silver_curse) // Lesser curse applied still
- src.last_used = world.time
- if(V_lord.vamplevel == 4 && !V)
- if(prob(25))
- H.fire_act(1,3)
- to_chat(s_user, " The silver weapon barely works against such an abomination!")
- H.visible_message(H, "This feeble metal can't stop me, I HAVE TRANSCENDED!")
- return
- if((target.mob_biotypes & MOB_UNDEAD))
- target.adjustFireLoss(25)
- return
-
//................ Lashkiss Whip ............... //
/obj/item/rogueweapon/whip/spiderwhip
force = DAMAGE_WHIP+3
diff --git a/code/modules/antagonists/roguetown/villain/werewolf.dm b/code/modules/antagonists/roguetown/villain/werewolf.dm
deleted file mode 100644
index 3572843a17..0000000000
--- a/code/modules/antagonists/roguetown/villain/werewolf.dm
+++ /dev/null
@@ -1,188 +0,0 @@
-#ifdef TESTSERVER
-/mob/living/carbon/human/verb/become_werewolf()
- set category = "DEBUGTEST"
- set name = "WEREWOLFTEST"
- if(mind)
- var/datum/antagonist/werewolf/new_antag = new /datum/antagonist/werewolf()
- mind.add_antag_datum(new_antag)
-#endif
-
-/datum/antagonist/werewolf
- name = "Werewolf"
- roundend_category = "Werewolves"
- antagpanel_category = "Werewolf"
- job_rank = ROLE_WEREWOLF
- antag_hud_type = ANTAG_HUD_TRAITOR
- antag_hud_name = "werewolf"
- var/special_role = ROLE_WEREWOLF
- var/transformed
- var/transforming
- var/transform_cooldown
- confess_lines = list("THE BEAST INSIDE ME!", "BEWARE THE BEAST!", "MY LUPINE MARK!")
- var/wolfname = "Werevolf"
- var/last_howl = 0
- var/pre_transform
- var/next_idle_sound
-
-/datum/antagonist/werewolf/lesser
- name = "Lesser Werewolf"
- increase_votepwr = FALSE
-
-/datum/antagonist/werewolf/lesser/roundend_report()
- return
-
-/datum/antagonist/werewolf/examine_friendorfoe(datum/antagonist/examined_datum,mob/examiner,mob/examined)
- if(istype(examined_datum, /datum/antagonist/werewolf/lesser))
- return "A young lupine kin."
- if(istype(examined_datum, /datum/antagonist/werewolf))
- return "An elder lupine kin."
- if(examiner.Adjacent(examined))
- if(istype(examined_datum, /datum/antagonist/vampirelord/lesser))
- if(transformed)
- return "A lesser Vampire."
- if(istype(examined_datum, /datum/antagonist/vampirelord))
- if(transformed)
- return "An Ancient Vampire. I must be careful!"
-
-/datum/antagonist/werewolf/on_gain()
- transform_cooldown = SSticker.round_start_time
- owner.special_role = name
- ADD_TRAIT(owner.current, TRAIT_VILLAIN, TRAIT_GENERIC)
- if(increase_votepwr)
- forge_werewolf_objectives()
- finalize_werewolf()
- wolfname = "[pick_n_take(GLOB.wolf_prefixes)] [pick_n_take(GLOB.wolf_suffixes)]"
- return ..()
-
-/datum/antagonist/werewolf/on_removal()
- if(!silent && owner.current)
- to_chat(owner.current,"I am no longer a [special_role]!")
- owner.special_role = null
- return ..()
-
-/datum/antagonist/werewolf/proc/add_objective(datum/objective/O)
- objectives += O
-
-/datum/antagonist/werewolf/proc/remove_objective(datum/objective/O)
- objectives -= O
-
-/datum/antagonist/werewolf/proc/forge_werewolf_objectives()
- if(!(locate(/datum/objective/escape) in objectives))
- var/datum/objective/werewolf/escape_objective = new
- escape_objective.owner = owner
- add_objective(escape_objective)
- return
-
-/datum/antagonist/werewolf/greet()
- to_chat(owner.current, "Ever since that bite, I have been a [owner.special_role].")
- owner.announce_objectives()
- ..()
-
-/datum/antagonist/werewolf/proc/finalize_werewolf()
- owner.current.playsound_local(get_turf(owner.current), 'sound/music/wolfintro.ogg', 80, FALSE, pressure_affected = FALSE)
-
-
-/datum/antagonist/werewolf/on_life(mob/user)
- if(!user)
- return
- var/mob/living/carbon/human/H = user
- if(H.stat == DEAD)
- return
- if(H.advsetup)
- return
-
- if(transformed)
- H.real_name = wolfname
- H.name = "WEREVOLF"
-
- if(!transforming && !transformed)
- if(world.time % 5)
- if(GLOB.tod == "night")
- if(isturf(H.loc))
- var/turf/T = H.loc
- if(T.can_see_sky())
- transforming = world.time
- to_chat(H, "THE MOONLIGHT SCORNS ME... THE LUPINE MARK!")
- H.flash_fullscreen("redflash3")
-
- if(transforming)
- if(world.time >= transforming + 40 SECONDS)
- H.flash_fullscreen("redflash3")
- transforming = FALSE
- pre_transform = FALSE
- if(transformed)
- transformed = FALSE
- H.werewolf_untransform()
- else
- transformed = TRUE
- H.werewolf_transform()
- else if(world.time >= transforming + 35 SECONDS)
- if(!pre_transform)
- pre_transform = TRUE
- if(transformed)
- H.emote("rage", forced = TRUE)
- else
- H.emote("agony", forced = TRUE)
- H.flash_fullscreen("redflash3")
- H.Stun(30)
- to_chat(H, "THE PAIN!")
- else
- if(transformed)
- if(H.m_intent != MOVE_INTENT_SNEAK)
- if(world.time > next_idle_sound + 8 SECONDS)
- next_idle_sound = world.time
- H.emote("idle")
- if(GLOB.tod != "night")
- H.flash_fullscreen("redflash1")
- to_chat(H, "The curse begins to fade...")
- transforming = world.time
-
-/mob/living/carbon/human/proc/howl_button()
- set name = "Howl"
- set category = "WEREWOLF"
-
- if(stat)
- return
- var/datum/antagonist/werewolf/WD = mind.has_antag_datum(/datum/antagonist/werewolf)
- if(WD && WD.transformed)
- if(world.time > WD.last_howl + 10 SECONDS)
- var/message = stripped_input(src, "Howl at the hidden moon", "WEREWOLF")
- if(!message)
- return
- if(world.time < WD.last_howl + 10 SECONDS)
- return
- WD.last_howl = world.time
- playsound(src, pick('sound/vo/mobs/wwolf/howl (1).ogg','sound/vo/mobs/wwolf/howl (2).ogg'), 100, TRUE)
- for(var/mob/player in GLOB.player_list)
- if(player.mind)
- if(player.stat == DEAD)
- continue
- if(isbrain(player)) //also technically dead
- continue
- if(player.mind.has_antag_datum(/datum/antagonist/werewolf))
- to_chat(player, "[WD.wolfname] howls: [message]")
- if(player == src)
- continue
- if(get_dist(player, src) > 7)
- player.playsound_local(get_turf(player), pick('sound/vo/mobs/wwolf/howldist (1).ogg','sound/vo/mobs/wwolf/howldist (2).ogg'), 100, FALSE, pressure_affected = FALSE)
- playsound(src, pick('sound/vo/mobs/wwolf/howl (1).ogg','sound/vo/mobs/wwolf/howl (2).ogg'), 100, TRUE)
- else
- to_chat(src, "I must wait.")
- return
-
-
-/mob/living/carbon/human/proc/werewolf_infect()
- if(!mind)
- return
- if(mind.has_antag_datum(/datum/antagonist/vampirelord))
- return
- if(mind.has_antag_datum(/datum/antagonist/zombie))
- return
- if(mind.has_antag_datum(/datum/antagonist/werewolf))
- return
- var/datum/antagonist/werewolf/new_antag = new /datum/antagonist/werewolf/lesser()
- mind.add_antag_datum(new_antag)
- new_antag.transforming = world.time
- to_chat(src, "I feel horrible...")
- src.playsound_local(get_turf(src), 'sound/music/horror.ogg', 80, FALSE, pressure_affected = FALSE)
- flash_fullscreen("redflash3")
diff --git a/code/modules/antagonists/roguetown/villain/werewolf/werewolf.dm b/code/modules/antagonists/roguetown/villain/werewolf/werewolf.dm
new file mode 100644
index 0000000000..106b18a6fd
--- /dev/null
+++ b/code/modules/antagonists/roguetown/villain/werewolf/werewolf.dm
@@ -0,0 +1,184 @@
+/datum/antagonist/werewolf
+ name = "Verewolf"
+ roundend_category = "Werewolves"
+ antagpanel_category = "Werewolf"
+ job_rank = ROLE_WEREWOLF
+ confess_lines = list(
+ "THE BEAST INSIDE ME!",
+ "BEWARE THE BEAST!",
+ "MY LUPINE MARK!",
+ )
+ //rogue_enabled = TRUE
+ var/special_role = ROLE_WEREWOLF
+ var/transformed
+ var/transforming
+ var/untransforming
+ var/wolfname = "Verewolf"
+
+/datum/antagonist/werewolf/lesser
+ name = "Lesser Verewolf"
+ increase_votepwr = FALSE
+
+/datum/antagonist/werewolf/lesser/roundend_report()
+ return
+
+/datum/antagonist/werewolf/examine_friendorfoe(datum/antagonist/examined_datum,mob/examiner,mob/examined)
+ if(istype(examined_datum, /datum/antagonist/werewolf/lesser))
+ return span_boldnotice("A young lupine kin.")
+ if(istype(examined_datum, /datum/antagonist/werewolf))
+ return span_boldnotice("An elder lupine kin.")
+ if(examiner.Adjacent(examined))
+ if(istype(examined_datum, /datum/antagonist/vampirelord/lesser))
+ if(transformed)
+ return span_boldwarning("A lesser Vampire.")
+ if(istype(examined_datum, /datum/antagonist/vampirelord))
+ if(transformed)
+ return span_boldwarning("An Ancient Vampire. I must be careful!")
+
+/datum/antagonist/werewolf/on_gain()
+ owner.special_role = name
+ if(increase_votepwr)
+ forge_werewolf_objectives()
+
+ wolfname = "[pick(GLOB.wolf_prefixes)] [pick(GLOB.wolf_suffixes)]"
+ return ..()
+
+/datum/antagonist/werewolf/on_removal()
+ if(!silent && owner.current)
+ to_chat(owner.current,span_danger("I am no longer a [special_role]!"))
+ owner.special_role = null
+ return ..()
+
+/datum/antagonist/werewolf/proc/add_objective(datum/objective/O)
+ objectives += O
+
+/datum/antagonist/werewolf/proc/remove_objective(datum/objective/O)
+ objectives -= O
+
+/datum/antagonist/werewolf/proc/forge_werewolf_objectives()
+ if(!(locate(/datum/objective/escape) in objectives))
+ var/datum/objective/werewolf/escape_objective = new
+ escape_objective.owner = owner
+ add_objective(escape_objective)
+ return
+
+/datum/antagonist/werewolf/greet()
+ to_chat(owner.current, span_userdanger("Ever since that bite, I have been a [name]."))
+ owner.announce_objectives()
+ return ..()
+
+/mob/living/carbon/human/proc/can_werewolf()
+ if(!mind)
+ return FALSE
+ if(mind.has_antag_datum(/datum/antagonist/vampirelord))
+ return FALSE
+ if(mind.has_antag_datum(/datum/antagonist/werewolf))
+ return FALSE
+ if(mind.has_antag_datum(/datum/antagonist/skeleton))
+ return FALSE
+ return TRUE
+
+/mob/living/carbon/human/proc/werewolf_check(werewolf_type = /datum/antagonist/werewolf/lesser)
+ if(!mind)
+ return
+ var/already_wolfy = mind.has_antag_datum(/datum/antagonist/werewolf)
+ if(already_wolfy)
+ return already_wolfy
+ if(!can_werewolf())
+ return
+ return mind.add_antag_datum(werewolf_type)
+
+/mob/living/carbon/human/proc/werewolf_infect_attempt()
+ var/datum/antagonist/werewolf/wolfy = werewolf_check()
+ if(!wolfy)
+ return
+ if(stat >= DEAD) //do shit the natural way i guess
+ return
+ to_chat(src, span_danger("I feel horrible... REALLY horrible..."))
+ mob_timers["puke"] = world.time
+ vomit(1, blood = TRUE, stun = FALSE)
+ return wolfy
+
+/mob/living/carbon/human/proc/werewolf_feed(mob/living/carbon/human/target, healing_amount = 10)
+ if(!istype(target))
+ return
+ if(src.has_status_effect(/datum/status_effect/debuff/silver_curse))
+ to_chat(src, span_notice("My power is weakened, I cannot heal!"))
+ return
+ if(target.mind)
+ if(target.mind.has_antag_datum(/datum/antagonist/zombie))
+ to_chat(src, span_warning("I should not feed on rotten flesh."))
+ return
+ if(target.mind.has_antag_datum(/datum/antagonist/vampirelord))
+ to_chat(src, span_warning("I should not feed on corrupted flesh."))
+ return
+ if(target.mind.has_antag_datum(/datum/antagonist/werewolf))
+ to_chat(src, span_warning("I should not feed on my kin's flesh."))
+ return
+
+ to_chat(src, span_warning("I feed on succulent flesh. I feel reinvigorated."))
+ return src.reagents.add_reagent(/datum/reagent/medicine/healthpot, healing_amount)
+
+/obj/item/clothing/suit/roguetown/armor/skin_armor/werewolf_skin
+ slot_flags = null
+ name = "verewolf's skin"
+ desc = ""
+ icon_state = null
+ body_parts_covered = FULL_BODY
+ armor = list("blunt" = 90, "slash" = 90, "stab" = 80, "piercing" = 70, "fire" = 40, "acid" = 0)
+ prevent_crits = list(BCLASS_CUT, BCLASS_CHOP, BCLASS_STAB, BCLASS_BLUNT, BCLASS_TWIST)
+ blocksound = SOFTHIT
+ blade_dulling = DULLING_BASHCHOP
+ sewrepair = FALSE
+ max_integrity = 550
+ item_flags = DROPDEL
+
+/datum/intent/simple/werewolf
+ name = "claw"
+ icon_state = "inchop"
+ blade_class = BCLASS_CHOP
+ attack_verb = list("claws", "mauls", "eviscerates")
+ animname = "chop"
+ hitsound = "genslash"
+ penfactor = 50
+ candodge = TRUE
+ canparry = TRUE
+ miss_text = "slashes the air!"
+ miss_sound = "bluntwooshlarge"
+// item_damage_type = "slash"
+
+/obj/item/rogueweapon/werewolf_claw
+ name = "Verevolf Claw"
+ desc = ""
+ item_state = null
+ lefthand_file = null
+ righthand_file = null
+ icon = 'icons/roguetown/weapons/32.dmi'
+ max_blade_int = 900
+ max_integrity = 900
+ force = 15
+ block_chance = 0
+ wdefense = 2
+ armor_penetration = 15
+ associated_skill = /datum/skill/combat/unarmed
+ wlength = WLENGTH_NORMAL
+ w_class = WEIGHT_CLASS_BULKY
+ can_parry = TRUE
+ sharpness = IS_SHARP
+ parrysound = "bladedmedium"
+ swingsound = BLADEWOOSH_MED
+ possible_item_intents = list(/datum/intent/simple/werewolf)
+ parrysound = list('sound/combat/parry/parrygen.ogg')
+ embedding = list("embedded_pain_multiplier" = 0, "embed_chance" = 0, "embedded_fall_chance" = 0)
+ item_flags = DROPDEL
+
+/obj/item/rogueweapon/werewolf_claw/right
+ icon_state = "claw_r"
+
+/obj/item/rogueweapon/werewolf_claw/left
+ icon_state = "claw_l"
+
+/obj/item/rogueweapon/werewolf_claw/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC)
+ ADD_TRAIT(src, TRAIT_NOEMBED, TRAIT_GENERIC)
diff --git a/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm
new file mode 100644
index 0000000000..3c3b2307d8
--- /dev/null
+++ b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm
@@ -0,0 +1,67 @@
+/obj/effect/proc_holder/spell/self/howl
+ name = "Howl"
+ desc = "!"
+ overlay_state = "howl"
+ antimagic_allowed = TRUE
+ charge_max = 600 //1 minute
+ ignore_cockblock = TRUE
+ var/use_language = FALSE
+
+/obj/effect/proc_holder/spell/self/howl/cast(mob/user = usr)
+ ..()
+ var/message = input("Howl at the hidden moon...", "MOONCURSED") as text|null
+ if(!message) return
+
+ var/datum/antagonist/werewolf/werewolf_player = user.mind.has_antag_datum(/datum/antagonist/werewolf)
+
+ // sound played for owner
+ playsound(src, pick('sound/vo/mobs/wwolf/howl (1).ogg','sound/vo/mobs/wwolf/howl (2).ogg'), 75, TRUE)
+
+ for(var/mob/player in GLOB.player_list)
+
+ if(!player.mind) continue
+ if(player.stat == DEAD) continue
+ if(isbrain(player)) continue
+
+ // Announcement to other werewolves (and anyone else who has beast language somehow)
+ if(player.mind.has_antag_datum(/datum/antagonist/werewolf) || (use_language && player.has_language(/datum/language/beast)))
+ to_chat(player, span_boldannounce("[werewolf_player ? werewolf_player.wolfname : user.real_name] howls to the hidden moon: [message]"))
+
+ //sound played for other players
+ if(player == src) continue
+ if(get_dist(player, src) > 7)
+ player.playsound_local(get_turf(player), pick('sound/vo/mobs/wwolf/howldist (1).ogg','sound/vo/mobs/wwolf/howldist (2).ogg'), 50, FALSE, pressure_affected = FALSE)
+
+ user.log_message("howls: [message] (WEREWOLF)" ,LOG_ATTACK)
+
+/obj/effect/proc_holder/spell/self/claws
+ name = "Lupine Claws"
+ desc = "!"
+ overlay_state = "claws"
+ antimagic_allowed = TRUE
+ charge_max = 20 //2 seconds
+ ignore_cockblock = TRUE
+ var/extended = FALSE
+
+/obj/effect/proc_holder/spell/self/claws/cast(mob/user = usr)
+ ..()
+ var/obj/item/rogueweapon/werewolf_claw/left/l
+ var/obj/item/rogueweapon/werewolf_claw/right/r
+
+ l = user.get_active_held_item()
+ r = user.get_inactive_held_item()
+ if(extended)
+ if(istype(user.get_active_held_item(), /obj/item/rogueweapon/werewolf_claw))
+ user.dropItemToGround(l, TRUE)
+ user.dropItemToGround(r, TRUE)
+ qdel(l)
+ qdel(r)
+ //user.visible_message("Your claws retract.", "You feel your claws retracting.", "You hear a sound of claws retracting.")
+ extended = FALSE
+ else
+ l = new(user,1)
+ r = new(user,2)
+ user.put_in_hands(l, TRUE, FALSE, TRUE)
+ user.put_in_hands(r, TRUE, FALSE, TRUE)
+ //user.visible_message("Your claws extend.", "You feel your claws extending.", "You hear a sound of claws extending.")
+ extended = TRUE
diff --git a/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm
new file mode 100644
index 0000000000..721be359d5
--- /dev/null
+++ b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm
@@ -0,0 +1,192 @@
+/mob/living/carbon/human
+ var/mob/stored_mob = null
+
+/datum/antagonist/werewolf/on_life(mob/user)
+ if(!user) return
+ var/mob/living/carbon/human/H = user
+ if(H.stat == DEAD) return
+ if(H.advsetup) return
+
+ // Werewolf transforms at night AND under the sky
+ if(!transformed && !transforming)
+ if(GLOB.tod == "night")
+ if(isturf(H.loc))
+ var/turf/loc = H.loc
+ if(loc.can_see_sky())
+ to_chat(H, span_userdanger("The moonlight scorns me... It is too late."))
+ owner.current.playsound_local(get_turf(owner.current), 'sound/music/wolfintro.ogg', 80, FALSE, pressure_affected = FALSE)
+ H.flash_fullscreen("redflash3")
+ transforming = world.time // timer
+
+ // Begin transformation
+ else if(transforming)
+ if (world.time >= transforming + 35 SECONDS) // Stage 3
+ H.werewolf_transform()
+ transforming = FALSE
+ transformed = TRUE // Mark as transformed
+
+ else if (world.time >= transforming + 25 SECONDS) // Stage 2
+ H.flash_fullscreen("redflash3")
+ H.emote("agony", forced = TRUE)
+ to_chat(H, span_userdanger("UNIMAGINABLE PAIN!"))
+ H.Stun(30)
+ H.Knockdown(30)
+
+ else if (world.time >= transforming + 10 SECONDS) // Stage 1
+ H.emote("")
+ to_chat(H, span_warning("I can feel my muscles aching, it feels HORRIBLE..."))
+
+
+ // Werewolf reverts to human form during the day
+ else if(transformed)
+ H.real_name = wolfname
+ H.name = wolfname
+
+ if(GLOB.tod != "night")
+ if(!untransforming)
+ untransforming = world.time // Start untransformation phase
+
+ if (world.time >= untransforming + 30 SECONDS) // Untransform
+ H.emote("rage", forced = TRUE)
+ H.werewolf_untransform()
+ transformed = FALSE
+ untransforming = FALSE // Reset untransforming phase
+
+ else if (world.time >= untransforming) // Alert player
+ H.flash_fullscreen("redflash1")
+ to_chat(H, span_warning("Daylight shines around me... the curse begins to fade."))
+
+
+/mob/living/carbon/human/species/werewolf/death(gibbed)
+ werewolf_untransform(TRUE, gibbed)
+
+/mob/living/carbon/human/proc/werewolf_transform()
+ if(!mind)
+ log_runtime("NO MIND ON [src.name] WHEN TRANSFORMING")
+ Paralyze(1, ignore_canstun = TRUE)
+ for(var/obj/item/W in src)
+ dropItemToGround(W)
+ regenerate_icons()
+ icon = null
+ var/oldinv = invisibility
+ invisibility = INVISIBILITY_MAXIMUM
+ cmode = FALSE
+ if(client)
+ SSdroning.play_area_sound(get_area(src), client)
+// stop_cmusic()
+
+ src.fully_heal(FALSE)
+
+ var/ww_path
+ if(gender == MALE)
+ ww_path = /mob/living/carbon/human/species/werewolf/male
+ else
+ ww_path = /mob/living/carbon/human/species/werewolf/female
+
+ var/mob/living/carbon/human/species/werewolf/W = new ww_path(loc)
+
+ W.set_patron(src.patron)
+ W.gender = gender
+ W.regenerate_icons()
+ W.stored_mob = src
+ W.limb_destroyer = TRUE
+ W.ambushable = FALSE
+ W.cmode_music = 'sound/music/combat_werewolf.ogg'
+ W.skin_armor = new /obj/item/clothing/suit/roguetown/armor/skin_armor/werewolf_skin(W)
+ playsound(W.loc, pick('sound/combat/gib (1).ogg','sound/combat/gib (2).ogg'), 200, FALSE, 3)
+ W.spawn_gibs(FALSE)
+ apply_status_effect(STATUS_EFFECT_STASIS, null, TRUE)
+ src.forceMove(W)
+
+ W.after_creation()
+ W.stored_language = new
+ W.stored_language.copy_known_languages_from(src)
+ W.stored_skills = mind.known_skills.Copy()
+ W.stored_experience = mind.skill_experience.Copy()
+ mind.transfer_to(W)
+ W.mind.known_skills = list()
+ W.mind.skill_experience = list()
+ W.grant_language(/datum/language/beast)
+
+ W.base_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB)
+ W.update_a_intents()
+
+ to_chat(W, span_userdanger("I transform into a horrible beast!"))
+ W.emote("rage")
+
+ W.mind.adjust_skillrank(/datum/skill/combat/wrestling, 5, TRUE)
+ W.mind.adjust_skillrank(/datum/skill/combat/unarmed, 5, TRUE)
+ W.mind.adjust_skillrank(/datum/skill/misc/climbing, 6, TRUE)
+
+ W.STASTR = 15
+ W.STACON = 15
+ W.STAEND = 15
+
+ W.AddSpell(new /obj/effect/proc_holder/spell/self/howl)
+ W.AddSpell(new /obj/effect/proc_holder/spell/self/claws)
+
+ ADD_TRAIT(src, TRAIT_NOSLEEP, TRAIT_GENERIC)
+
+ ADD_TRAIT(W, TRAIT_STRONGBITE, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_ZJUMP, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_NOFALLDAMAGE1, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_NOROGSTAM, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_BASHDOORS, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_SHOCKIMMUNE, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_STEELHEARTED, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_BREADY, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_TOXIMMUNE, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_ORGAN_EATER, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_NASTY_EATER, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_NOSTINK, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_CRITICAL_RESISTANCE, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_IGNORESLOWDOWN, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_HARDDISMEMBER, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_PIERCEIMMUNE, TRAIT_GENERIC)
+ ADD_TRAIT(W, TRAIT_ANTIMAGIC, TRAIT_GENERIC)
+
+ invisibility = oldinv
+
+
+/mob/living/carbon/human/proc/werewolf_untransform(dead,gibbed)
+ if(!stored_mob)
+ return
+ if(!mind)
+ log_runtime("NO MIND ON [src.name] WHEN UNTRANSFORMING")
+ Paralyze(1, ignore_canstun = TRUE)
+ for(var/obj/item/W in src)
+ dropItemToGround(W)
+ icon = null
+ invisibility = INVISIBILITY_MAXIMUM
+
+ var/mob/living/carbon/human/W = stored_mob
+ stored_mob = null
+ REMOVE_TRAIT(W, TRAIT_NOSLEEP, TRAIT_GENERIC)
+ if(dead)
+ W.death(gibbed)
+
+ W.forceMove(get_turf(src))
+ W.remove_status_effect(STATUS_EFFECT_STASIS)
+
+ REMOVE_TRAIT(W, TRAIT_NOMOOD, TRAIT_GENERIC)
+
+ mind.transfer_to(W)
+
+ var/mob/living/carbon/human/species/werewolf/WA = src
+ W.copy_known_languages_from(WA.stored_language)
+ W.mind.known_skills = WA.stored_skills.Copy()
+ W.mind.skill_experience = WA.stored_experience.Copy()
+
+ W.RemoveSpell(new /obj/effect/proc_holder/spell/self/howl)
+ W.RemoveSpell(new /obj/effect/proc_holder/spell/self/claws)
+
+ W.regenerate_icons()
+
+ to_chat(W, span_userdanger("I return to my facade."))
+ playsound(W.loc, pick('sound/combat/gib (1).ogg','sound/combat/gib (2).ogg'), 200, FALSE, 3)
+ W.spawn_gibs(FALSE)
+ W.Knockdown(30)
+ W.Stun(30)
+
+ qdel(src)
diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm
index adcbb8fb57..dce0db6dec 100644
--- a/code/modules/error_handler/error_viewer.dm
+++ b/code/modules/error_handler/error_viewer.dm
@@ -25,7 +25,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache)
var/name = ""
/datum/error_viewer/proc/browse_to(client/user, html)
- var/datum/browser/browser = new(user.mob, "error_viewer", null, 600, 400)
+ var/datum/browser/noclose/browser = new(user.mob, "error_viewer", null, 600, 400)
browser.set_content(html)
browser.add_head_content({"