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({"