Merge branch 'master' into Clinging-to-hope

This commit is contained in:
Qwertytoforty
2021-11-14 16:43:35 -05:00
committed by GitHub
374 changed files with 20608 additions and 22123 deletions
+1 -1
View File
@@ -501,7 +501,7 @@
log_game("Teleport spell failed - no other teleport runes")
return
if(!is_level_reachable(user.z))
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
log_game("Teleport spell failed - user in away mission")
return
+5
View File
@@ -139,6 +139,11 @@
to_chat(user, "<span class='cultitalic'>The veil is not weak enough here to summon a cultist, you must be on station!</span>")
return
if(ispath(rune, /obj/effect/rune/teleport))
if(!is_level_reachable(user.z))
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
return
var/old_color = user.color // we'll temporarily redden the user for better feedback to fellow cultists. Store this to revert them back.
if(narsie_rune)
if(!narsie_rune_check(user, A))
+1 -1
View File
@@ -461,7 +461,7 @@ structure_check() searches for nearby cultist structures required for the invoca
return
if(!is_level_reachable(user.z))
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
log_game("Teleport rune failed - user in away mission")
fail_invoke()
return
@@ -786,3 +786,24 @@
/datum/AI_Module/large/cameracrack/upgrade(mob/living/silicon/ai/AI)
if(AI.builtInCamera)
QDEL_NULL(AI.builtInCamera)
/datum/AI_Module/large/engi_upgrade
module_name = "Engineering Cyborg Emitter Upgrade"
mod_pick_name = "emitter"
description = "Downloads firmware that activates the built in emitter in all engineering cyborgs linked to you. Cyborgs built after this upgrade will have it pre-installed."
cost = 50 // IDK look into this
one_purchase = TRUE
upgrade = TRUE
unlock_text = "<span class='notice'>Firmware downloaded. Bugs removed. Built in emitters operating at 73% efficiency.</span>"
unlock_sound = 'sound/items/rped.ogg'
/datum/AI_Module/large/engi_upgrade/upgrade(mob/living/silicon/ai/AI)
AI.purchased_modules += /obj/item/robot_module/engineering
log_game("[key_name(usr)] purchased emitters for all engineering cyborgs.")
message_admins("<span class='notice'>[key_name_admin(usr)] purchased emitters for all engineering cyborgs!</span>")
for(var/mob/living/silicon/robot/R in AI.connected_robots)
if(!istype(R.module, /obj/item/robot_module/engineering))
continue
R.module.malfhacked = TRUE
R.module.rebuild_modules()
to_chat(R, "<span class='notice'>New firmware downloaded. Emitter is now online.</span>")
@@ -736,7 +736,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
desc = "Contains secrets of the universe."
icon_state = "abductor"
icon_closed = "abductor"
icon_opened = "abductoropen"
icon_opened = "abductor_open"
material_drop = /obj/item/stack/sheet/mineral/abductor
/obj/structure/door_assembly/door_assembly_abductor
@@ -42,19 +42,32 @@
speed = 1
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
var/essence = 75 //The resource of revenants. Max health is equal to three times this amount
var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
var/essence_regenerating = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no
var/essence_regen_amount = 5 //How much essence regenerates
var/essence_accumulated = 0 //How much essence the revenant has stolen
var/revealed = 0 //If the revenant can take damage from normal sources.
var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var.
var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var.
var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
var/essence_drained = 0 //How much essence the revenant has drained.
var/draining = 0 //If the revenant is draining someone.
var/list/drained_mobs = list() //Cannot harvest the same mob twice
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has.
///The resource of revenants. Max health is equal to three times this amount
var/essence = 75
///The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
var/essence_regen_cap = 75
///If the revenant regenerates essence or not; 1 for yes, 0 for no
var/essence_regenerating = TRUE
///How much essence regenerates
var/essence_regen_amount = 5
///How much essence the revenant has stolen
var/essence_accumulated = 0
///If the revenant can take damage from normal sources.
var/revealed = FALSE
///How long the revenant is revealed for, is about 2 seconds times this var.
var/unreveal_time = 0
///How long the revenant is stunned for, is about 2 seconds times this var.
var/unstun_time = 0
///If the revenant's abilities are blocked by a chaplain's power.
var/inhibited = FALSE
///How much essence the revenant has drained.
var/essence_drained = 0
///If the revenant is draining someone.
var/draining = FALSE
/// contains a list of UIDs of mobs who have been drained. cannot drain the same mob twice.
var/list/drained_mobs = list()
///How many perfect, regen-cap increasing souls the revenant has.
var/perfectsouls = 0
/mob/living/simple_animal/revenant/Life(seconds, times_fired)
@@ -232,25 +245,21 @@
..()
/mob/living/simple_animal/revenant/proc/castcheck(essence_cost)
if(!src)
return
if(holy_check(src))
return
var/turf/T = get_turf(src)
if(istype(T, /turf/simulated/wall))
to_chat(src, "<span class='revenwarning'>You cannot use abilities from inside of a wall.</span>")
return 0
if(src.inhibited)
if(inhibited)
to_chat(src, "<span class='revenwarning'>Your powers have been suppressed by nulling energy!</span>")
return 0
if(!src.change_essence_amount(essence_cost, 1))
if(!change_essence_amount(essence_cost, 1))
to_chat(src, "<span class='revenwarning'>You lack the essence to use that ability.</span>")
return 0
return 1
/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null)
if(!src)
return
if(essence + essence_amt <= 0)
return
essence = max(0, essence+essence_amt)
@@ -264,8 +273,6 @@
return 1
/mob/living/simple_animal/revenant/proc/reveal(time)
if(!src)
return
if(time <= 0)
return
revealed = 1
@@ -280,8 +287,6 @@
update_spooky_icon()
/mob/living/simple_animal/revenant/proc/stun(time)
if(!src)
return
if(time <= 0)
return
notransform = 1
@@ -31,7 +31,8 @@
if(draining)
to_chat(src, "<span class='revenwarning'>You are already siphoning the essence of a soul!</span>")
return
if(target in drained_mobs)
var/mob_UID = target.UID()
if(mob_UID in drained_mobs)
to_chat(src, "<span class='revenwarning'>[target]'s soul is dead and empty.</span>")
return
if(!target.stat)
@@ -39,7 +40,7 @@
if(prob(10))
to_chat(target, "You feel as if you are being watched.")
return
draining = 1
draining = TRUE
essence_drained = rand(15, 20)
to_chat(src, "<span class='revennotice'>You search for the soul of [target].</span>")
if(do_after(src, 10, 0, target = target)) //did they get deleted in that second?
@@ -65,7 +66,7 @@
if(!target.stat)
to_chat(src, "<span class='revenwarning'>They are now powerful enough to fight off your draining.</span>")
to_chat(target, "<span class='boldannounce'>You feel something tugging across your body before subsiding.</span>")
draining = 0
draining = FALSE
return //hey, wait a minute...
to_chat(src, "<span class='revenminor'>You begin siphoning essence from [target]'s soul.</span>")
if(target.stat != DEAD)
@@ -84,7 +85,8 @@
to_chat(src, "<span class='revennotice'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>")
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
"<span class='revenwarning'>Violets lights, dancing in your vision, getting clo--</span>")
drained_mobs.Add(target)
drained_mobs.Add(mob_UID)
add_attack_logs(src, target, "revenant harvested soul")
target.death(0)
else
to_chat(src, "<span class='revenwarning'>[target ? "[target] has":"They have"] been drawn out of your grasp. The link has been broken.</span>")
@@ -96,10 +98,10 @@
return
else
to_chat(src, "<span class='revenwarning'>You are not close enough to siphon [target ? "[target]'s":"their"] soul. The link has been broken.</span>")
draining = 0
draining = FALSE
essence_drained = 0
return
draining = 0
draining = FALSE
essence_drained = 0
return
@@ -142,7 +144,7 @@
name = "Report this to a coder"
var/reveal = 80 //How long it reveals the revenant in deciseconds
var/stun = 20 //How long it stuns the revenant in deciseconds
var/locked = 1 //If it's locked and needs to be unlocked before use
var/locked = TRUE //If it's locked and needs to be unlocked before use
var/unlock_amount = 100 //How much essence it costs to unlock
var/cast_amount = 50 //How much essence it costs to use
@@ -155,36 +157,36 @@
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, charge_check = TRUE, show_message = FALSE)
if(user.inhibited)
return 0
return FALSE
if(charge_counter < charge_max)
return 0
return FALSE
if(locked)
if(user.essence <= unlock_amount)
return 0
return FALSE
if(user.essence <= cast_amount)
return 0
return 1
return FALSE
return TRUE
/obj/effect/proc_holder/spell/aoe_turf/revenant/proc/attempt_cast(mob/living/simple_animal/revenant/user = usr)
if(locked)
if(!user.castcheck(-unlock_amount))
charge_counter = charge_max
return 0
return FALSE
name = "[initial(name)] ([cast_amount]E)"
to_chat(user, "<span class='revennotice'>You have unlocked [initial(name)]!</span>")
panel = "Revenant Abilities"
locked = 0
locked = FALSE
charge_counter = charge_max
return 0
return FALSE
if(!user.castcheck(-cast_amount))
charge_counter = charge_max
return 0
return FALSE
name = "[initial(name)] ([cast_amount]E)"
user.reveal(reveal)
user.stun(stun)
if(action)
action.UpdateButtonIcon()
return 1
return TRUE
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload
@@ -201,25 +203,29 @@
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
spawn(0)
for(var/obj/machinery/light/L in T.contents)
spawn(0)
if(!L.on)
return
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
do_sparks(4, 0, L)
new/obj/effect/temp_visual/revenant(L.loc)
sleep(20)
if(!L.on) //wait, wait, don't shock me
return
flick("[L.base_state]2", L)
for(var/mob/living/M in view(shock_range, L))
if(M == user)
return
M.Beam(L,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
M.electrocute_act(shock_damage, L, flags = SHOCK_NOGLOVES)
do_sparks(4, 0, M)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
select_lights(T, user)
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/select_lights(turf/T, mob/living/simple_animal/revenant/user)
for(var/obj/machinery/light/L in T.contents)
INVOKE_ASYNC(src, .proc/shock_lights, L, user)
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/shock_lights(obj/machinery/light/L, mob/living/simple_animal/revenant/user)
if(!L.on)
return
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
do_sparks(4, 0, L)
new /obj/effect/temp_visual/revenant(L.loc)
sleep(2 SECONDS)
if(!L.on) //wait, wait, don't shock me
return
flick("[L.base_state]2", L)
for(var/mob/living/M in view(shock_range, L))
if(M == user)
continue
M.Beam(L, icon_state = "purple_lightning", icon = 'icons/effects/effects.dmi', time = 0.5 SECONDS)
M.electrocute_act(shock_damage, L, flags = SHOCK_NOGLOVES)
do_sparks(4, 0, M)
playsound(M, 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
//Defile: Corrupts nearby stuff, unblesses floor tiles.
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile
@@ -232,46 +238,14 @@
unlock_amount = 75
cast_amount = 30
action_icon_state = "defile"
var/stamdamage= 25
var/toxdamage = 5
var/confusion = 20
var/maxconfusion = 30
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
spawn(0)
if(T.flags & NOJAUNT)
T.flags -= NOJAUNT
new/obj/effect/temp_visual/revenant(T)
for(var/mob/living/carbon/human/human in T.contents)
to_chat(human, "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>")
human.adjustStaminaLoss(stamdamage)
human.adjustToxLoss(toxdamage)
human.AdjustConfused(confusion, bound_lower = 0, bound_upper = maxconfusion)
new/obj/effect/temp_visual/revenant(human.loc)
if(!istype(T, /turf/simulated/wall/indestructible) && !istype(T, /turf/simulated/wall/rust) && !istype(T, /turf/simulated/wall/r_wall) && istype(T, /turf/simulated/wall) && prob(15))
new/obj/effect/temp_visual/revenant(T)
T.ChangeTurf(/turf/simulated/wall/rust)
if(!istype(T, /turf/simulated/wall/r_wall/rust) && istype(T, /turf/simulated/wall/r_wall) && prob(15))
new/obj/effect/temp_visual/revenant(T)
T.ChangeTurf(/turf/simulated/wall/r_wall/rust)
for(var/obj/structure/window/window in T.contents)
window.take_damage(rand(30,80))
if(window && window.fulltile)
new/obj/effect/temp_visual/revenant/cracks(window.loc)
for(var/obj/structure/closet/closet in T.contents)
closet.open()
if(!istype(T, /turf/simulated/floor/plating) && !istype(T, /turf/simulated/floor/engine/cult) && istype(T, /turf/simulated/floor) && prob(15))
var/turf/simulated/floor/floor = T
if(floor.intact && floor.floor_tile)
new floor.floor_tile(floor)
floor.broken = 0
floor.burnt = 0
floor.make_plating(1)
for(var/obj/machinery/light/light in T.contents)
light.flicker(30) //spooky
if(!attempt_cast(user))
return
for(var/turf/T in targets)
T.defile()
for(var/atom/A in T.contents)
A.defile()
//Malfunction: Makes bad stuff happen to robots and machines.
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction
@@ -287,29 +261,107 @@
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
spawn(0)
for(var/mob/living/simple_animal/bot/bot in T.contents)
if(!bot.emagged)
new/obj/effect/temp_visual/revenant(bot.loc)
bot.locked = 0
bot.open = 1
bot.emag_act(null)
for(var/mob/living/carbon/human/human in T.contents)
to_chat(human, "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
new/obj/effect/temp_visual/revenant(human.loc)
human.emp_act(1)
for(var/obj/thing in T.contents)
if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
continue
if(prob(20))
if(prob(50))
new/obj/effect/temp_visual/revenant(thing.loc)
thing.emag_act(null)
else
if(!istype(thing, /obj/machinery/clonepod)) //I hate everything but mostly the fact there's no better way to do this without just not affecting it at all
thing.emp_act(1)
for(var/mob/living/silicon/robot/S in T.contents) //Only works on cyborgs, not AI
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
new/obj/effect/temp_visual/revenant(S.loc)
S.spark_system.start()
S.emp_act(1)
INVOKE_ASYNC(src, .proc/effect, user, T)
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/proc/effect(mob/living/simple_animal/revenant/user, turf/T)
T.rev_malfunction()
for(var/atom/A in T.contents)
A.rev_malfunction()
/atom/proc/defile()
return
/atom/proc/rev_malfunction()
return
/mob/living/carbon/human/rev_malfunction()
to_chat(src, "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
new /obj/effect/temp_visual/revenant(loc)
emp_act(1)
/mob/living/simple_animal/bot/rev_malfunction()
if(!emagged)
new /obj/effect/temp_visual/revenant(loc)
locked = FALSE
open = TRUE
emag_act(null)
/obj/rev_malfunction()
if(prob(20))
if(prob(50))
new /obj/effect/temp_visual/revenant(loc)
emag_act(null)
/obj/machinery/clonepod/rev_malfunction()
emag_act(null)
/obj/machinery/power/apc/rev_malfunction()
return
/obj/machinery/power/smes/rev_malfunction()
return
/mob/living/silicon/robot/rev_malfunction()
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 1)
new /obj/effect/temp_visual/revenant(loc)
spark_system.start()
emp_act(1)
/turf/defile()
if(flags & NOJAUNT)
flags &= ~NOJAUNT
new /obj/effect/temp_visual/revenant(loc)
/turf/simulated/wall/defile()
..()
if(prob(15))
new/obj/effect/temp_visual/revenant(loc)
ChangeTurf(/turf/simulated/wall/rust)
/turf/simulated/wall/indestructible/defile()
return
/turf/simulated/wall/r_wall/defile()
..()
if(prob(15))
new/obj/effect/temp_visual/revenant(loc)
ChangeTurf(/turf/simulated/wall/r_wall/rust)
/mob/living/carbon/human/defile()
to_chat(src, "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>")
adjustStaminaLoss(25)
adjustToxLoss(5)
AdjustConfused(20, bound_lower = 0, bound_upper = 30)
new /obj/effect/temp_visual/revenant(loc)
/obj/structure/window/defile()
take_damage(rand(30,80))
if(fulltile)
new /obj/effect/temp_visual/revenant/cracks(loc)
/obj/structure/closet/defile()
open()
/turf/simulated/floor/defile()
..()
if(prob(15))
if(intact && floor_tile)
new floor_tile(src)
broken = 0
burnt = 0
make_plating(1)
/turf/simulated/floor/plating/defile()
if(flags & NOJAUNT)
flags &= ~NOJAUNT
new /obj/effect/temp_visual/revenant(loc)
/turf/simulated/floor/engine/cult/defile()
if(flags & NOJAUNT)
flags &= ~NOJAUNT
new /obj/effect/temp_visual/revenant(loc)
/obj/machinery/light/defile()
flicker(30)
@@ -115,6 +115,12 @@
speed = 0
boost = world.time + 60
// Midround slaughter demon, less tanky
/mob/living/simple_animal/slaughter/lesser
maxHealth = 130
health = 130
// Cult slaughter demon
/mob/living/simple_animal/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter"
name = "harbinger of the slaughter"
+9
View File
@@ -205,6 +205,15 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/protect/mindslave //subytpe for mindslave implants
/datum/objective/protect/mindslave/on_target_cryo()
if(owner?.current)
to_chat(owner.current, "<BR><span class='userdanger'>You notice that your master has entered cryogenic storage, and revert to your normal self, until they return again. You are no longer a mindslave!</span>")
SEND_SOUND(owner.current, sound('sound/ambience/alarm4.ogg'))
owner.remove_antag_datum(/datum/antagonist/mindslave)
SSticker.mode.implanted.Remove(owner)
log_admin("[key_name(owner.current)]'s mindslave master has cryo'd, and is no longer a mindslave.")
message_admins("[key_name_admin(owner.current)]'s mindslave master has cryo'd, and is no longer a mindslave.") //Since they were on antag hud earlier, this feels important to log
qdel(src)
/datum/objective/hijack
martyr_compatible = 0 //Technically you won't get both anyway.
+4
View File
@@ -33,6 +33,10 @@
var/list/possible_traitors = get_players_for_role(ROLE_TRAITOR)
for(var/datum/mind/candidate in possible_traitors)
if(candidate.special_role == SPECIAL_ROLE_VAMPIRE) // no traitor vampires
possible_traitors.Remove(candidate)
// stop setup if no possible traitors
if(!possible_traitors.len)
return 0
+1 -1
View File
@@ -13,7 +13,7 @@
/datum/game_mode/traitor/vampire/announce()
to_chat(world, "<B>The current game mode is - Traitor+Vampire!</B>")
to_chat(world, "<B>There is a Vampire from Space Transylvania on the station along with some syndicate operatives out for their own gain! Do not let the vampire and the traitors succeed!</B>")
to_chat(world, "<B>There are Bluespace Vampires infesting your fellow crew on the station along with some syndicate operatives out for their own gain! Do not let the vampires and the traitors succeed!</B>")
/datum/game_mode/traitor/vampire/pre_setup()
+137 -97
View File
@@ -1,9 +1,7 @@
//This is the gamemode file for the ported goon gamemode vampires.
//They get a traitor objective and a blood sucking objective
/datum/game_mode
var/list/datum/mind/vampires = list()
var/list/datum/mind/vampire_enthralled = list() //those controlled by a vampire
var/list/vampire_thralls = list() //vammpires controlling somebody
var/list/vampire_thralls = list() //vampires controlling somebody
/datum/game_mode/vampire
name = "vampire"
@@ -36,7 +34,7 @@
/datum/game_mode/vampire/announce()
to_chat(world, "<B>The current game mode is - Vampires!</B>")
to_chat(world, "<B>There are Vampires from Space Transylvania on the station, keep your blood close and neck safe!</B>")
to_chat(world, "<B>There are Bluespace Vampires infesting your fellow crewmates, keep your blood close and neck safe!</B>")
/datum/game_mode/vampire/pre_setup()
@@ -84,8 +82,8 @@
text += "died"
else
text += "survived"
if(vampire.current.real_name != vampire.name)
text += " as [vampire.current.real_name]"
if(vampire.vampire.subclass)
text += " as a [vampire.vampire.subclass.name]"
else
text += "body destroyed"
text += ")"
@@ -120,15 +118,15 @@
/datum/game_mode/proc/auto_declare_completion_enthralled()
if(vampire_enthralled.len)
var/text = "<FONT size = 2><B>The Enthralled were:</B></FONT>"
for(var/datum/mind/Mind in vampire_enthralled)
text += "<br>[Mind.key] was [Mind.name] ("
if(Mind.current)
if(Mind.current.stat == DEAD)
for(var/datum/mind/mind in vampire_enthralled)
text += "<br>[mind.key] was [mind.name] ("
if(mind.current)
if(mind.current.stat == DEAD)
text += "died"
else
text += "survived"
if(Mind.current.real_name != Mind.name)
text += " as [Mind.current.real_name]"
if(mind.current.real_name != mind.name)
text += " as [mind.current.real_name]"
else
text += "body destroyed"
text += ")"
@@ -168,9 +166,18 @@
return
/datum/game_mode/proc/grant_vampire_powers(mob/living/carbon/vampire_mob)
if(!istype(vampire_mob))
if(!istype(vampire_mob) || !vampire_mob.mind)
return
vampire_mob.make_vampire()
var/datum/vampire/vamp
if(!vampire_mob.mind.vampire)
vamp = new /datum/vampire()
vamp.owner = vampire_mob
vampire_mob.mind.vampire = vamp
else
vamp = vampire_mob.mind.vampire
QDEL_LIST(vamp.powers)
vamp.check_vampire_upgrade(FALSE)
/datum/game_mode/proc/greet_vampire(datum/mind/vampire, you_are=1)
var/dat
@@ -178,7 +185,7 @@
SEND_SOUND(vampire.current, sound('sound/ambience/antag/vampalert.ogg'))
dat = "<span class='danger'>You are a Vampire!</span><br>"
dat += {"To bite someone, target the head and use harm intent with an empty hand. Drink blood to gain new powers.
You are weak to holy things and starlight. Don't go into space and avoid the Chaplain, the chapel and especially Holy Water."}
You are weak to holy things, starlight and fire. Don't go into space and avoid the Chaplain, the chapel and especially Holy Water."}
to_chat(vampire.current, dat)
to_chat(vampire.current, "<B>You must complete the following tasks:</B>")
@@ -195,42 +202,51 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
obj_count++
to_chat(vampire.current, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Vampire)</span>")
return
/datum/vampire
var/bloodtotal = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
var/bloodusable = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
var/bloodtotal = 0
var/bloodusable = 0
/// the mob tied to the vampire
var/mob/living/owner = null
var/gender = FEMALE
var/iscloaking = 0 // handles the vampire cloak toggle
var/list/powers = list() // list of available powers and passives
var/mob/living/carbon/human/draining // who the vampire is draining of blood
var/nullified = 0 //Nullrod makes them useless for a short while.
var/list/upgrade_tiers = list(
/obj/effect/proc_holder/spell/vampire/self/rejuvenate = 0,
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise = 0,
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare = 0,
/datum/vampire_passive/vision = 100,
/obj/effect/proc_holder/spell/vampire/self/shapeshift = 100,
/obj/effect/proc_holder/spell/vampire/self/cloak = 150,
/obj/effect/proc_holder/spell/vampire/targetted/disease = 150,
/obj/effect/proc_holder/spell/vampire/bats = 200,
/obj/effect/proc_holder/spell/vampire/self/screech = 200,
/datum/vampire_passive/regen = 200,
/obj/effect/proc_holder/spell/vampire/shadowstep = 250,
/obj/effect/proc_holder/spell/vampire/self/jaunt = 300,
/obj/effect/proc_holder/spell/vampire/targetted/enthrall = 300,
/datum/vampire_passive/full = 500)
/// what vampire subclass the vampire is.
var/datum/vampire_subclass/subclass
/// handles the vampire cloak toggle
var/iscloaking = FALSE
/// list of available powers and passives
var/list/powers = list()
/// who the vampire is draining of blood
var/mob/living/carbon/human/draining
/// Nullrods and holywater make their abilities cost more
var/nullified = 0
/// a list of powers that all vampires unlock and at what blood level they unlock them, the rest of their powers are found in the vampire_subclass datum
var/list/upgrade_tiers = list(/obj/effect/proc_holder/spell/self/vampire/rejuvenate = 0,
/obj/effect/proc_holder/spell/mob_aoe/glare = 0,
/datum/vampire_passive/vision = 100,
/obj/effect/proc_holder/spell/self/vampire/specialize = 150,
/datum/vampire_passive/regen = 200,
/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step = 250)
/// list of the peoples UIDs that we have drained, and how much blood from each one
var/list/drained_humans = list()
/datum/vampire/Destroy(force, ...)
owner = null
draining = null
QDEL_NULL(subclass)
QDEL_LIST(powers)
return ..()
/datum/vampire/proc/adjust_nullification(base, extra)
// First hit should give full nullification, while subsequent hits increase the value slower
nullified = max(nullified + extra, base)
/datum/vampire/New(gend = FEMALE)
gender = gend
nullified = clamp(nullified + extra, base, VAMPIRE_NULLIFICATION_CAP)
/datum/vampire/proc/force_add_ability(path)
var/spell = new path(owner)
if(istype(spell, /obj/effect/proc_holder/spell))
owner.mind.AddSpell(spell)
if(istype(spell, /datum/vampire_passive))
var/datum/vampire_passive/passive = spell
passive.owner = owner
powers += spell
owner.update_sight() // Life updates conditionally, so we need to update sight here in case the vamp gets new vision based on his powers. Maybe one day refactor to be more OOP and on the vampire's ability datum.
@@ -256,20 +272,6 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
if(current.mind && current.mind.vampire && current.mind.vampire.owner && (current.mind.vampire.owner != current))
current.mind.vampire.owner = current
/mob/proc/make_vampire()
if(!mind)
return
var/datum/vampire/vamp
if(!mind.vampire)
vamp = new /datum/vampire(gender)
vamp.owner = src
mind.vampire = vamp
else
vamp = mind.vampire
vamp.powers.Cut()
vamp.check_vampire_upgrade(0)
/datum/vampire/proc/remove_vampire_powers()
for(var/P in powers)
remove_ability(P)
@@ -278,12 +280,14 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
if(hud.vampire_blood_display)
hud.remove_vampire_hud()
owner.alpha = 255
REMOVE_TRAITS_IN(owner, "vampire")
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H)
#define BLOOD_GAINED_MODIFIER 0.5
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H, suck_rate = 5 SECONDS)
draining = H
var/unique_suck_id = H.UID()
var/blood = 0
var/old_bloodtotal = 0 //used to see if we increased our blood total
var/old_bloodusable = 0 //used to see if we increased our blood usable
var/blood_volume_warning = 9999 //Blood volume threshold for warnings
if(owner.is_muzzled())
to_chat(owner, "<span class='warning'>[owner.wear_mask] prevents you from biting [H]!</span>")
@@ -295,25 +299,24 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
H.LAssailant = null
else
H.LAssailant = owner
while(do_mob(owner, H, 50))
while(do_mob(owner, H, suck_rate))
if(!(owner.mind in SSticker.mode.vampires))
to_chat(owner, "<span class='userdanger'>Your fangs have disappeared!</span>")
return
old_bloodtotal = bloodtotal
old_bloodusable = bloodusable
owner.do_attack_animation(H, ATTACK_EFFECT_BITE)
if(unique_suck_id in drained_humans)
if(drained_humans[unique_suck_id] >= BLOOD_DRAIN_LIMIT)
to_chat(owner, "<span class='warning'>You have drained most of the life force from [H]'s blood, and you will get no more useable blood from them!</span>")
H.blood_volume = max(H.blood_volume - 25, 0)
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + 5))
continue
if(H.stat < DEAD)
if(H.ckey || H.player_ghosted) //Requires ckey regardless if monkey or humanoid, or the body has been ghosted before it died
blood = min(20, H.blood_volume) // if they have less than 20 blood, give them the remnant else they get 20 blood
bloodtotal += blood / 2 //divide by 2 to counted the double suction since removing cloneloss -Melandor0
bloodusable += blood / 2
else
if(H.ckey || H.player_ghosted)
blood = min(5, H.blood_volume) // The dead only give 5 blood
bloodtotal += blood
if(old_bloodtotal != bloodtotal)
if(H.ckey || H.player_ghosted) // Requires ckey regardless if monkey or human, and has not ghosted, otherwise no power
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].</b></span>")
check_vampire_upgrade()
blood = min(20, H.blood_volume)
adjust_blood(H, blood * BLOOD_GAINED_MODIFIER)
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] unit\s of blood, and have [bloodusable] left to use.</b></span>")
H.blood_volume = max(H.blood_volume - 25, 0)
//Blood level warnings (Code 'borrowed' from Fulp)
if(H.blood_volume)
@@ -325,20 +328,18 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
else
to_chat(owner, "<span class='warning'>You have bled your victim dry!</span>")
break
if(ishuman(owner))
var/mob/living/carbon/human/V = owner
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
to_chat(V, "<span class='notice'><b>Feeding on [H] reduces your thirst, but you get no usable blood from them.</b></span>")
V.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, V.nutrition + 5))
else
V.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, V.nutrition + (blood / 2)))
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
to_chat(owner, "<span class='notice'><b>Feeding on [H] reduces your thirst, but you get no usable blood from them.</b></span>")
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + 5))
else
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + (blood / 2)))
draining = null
to_chat(owner, "<span class='notice'>You stop draining [H.name] of blood.</span>")
/datum/vampire/proc/check_vampire_upgrade(announce = 1)
#undef BLOOD_GAINED_MODIFIER
/datum/vampire/proc/check_vampire_upgrade(announce = TRUE)
var/list/old_powers = powers.Copy()
for(var/ptype in upgrade_tiers)
@@ -346,18 +347,30 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
if(bloodtotal >= level)
add_ability(ptype)
if(!subclass)
return
subclass.add_subclass_ability(src)
check_full_power_upgrade()
if(announce)
announce_new_power(old_powers)
/datum/vampire/proc/check_full_power_upgrade()
if(length(drained_humans) >= FULLPOWER_DRAINED_REQUIREMENT && bloodtotal >= FULLPOWER_BLOODTOTAL_REQUIREMENT)
subclass.add_full_power_abilities(src)
/datum/vampire/proc/announce_new_power(list/old_powers)
for(var/p in powers)
if(!(p in old_powers))
if(istype(p, /obj/effect/proc_holder/spell/vampire))
var/obj/effect/proc_holder/spell/vampire/power = p
to_chat(owner, "<span class='notice'>[power.gain_desc]</span>")
if(istype(p, /obj/effect/proc_holder/spell))
var/obj/effect/proc_holder/spell/power = p
to_chat(owner, "<span class='boldnotice'>[power.gain_desc]</span>")
else if(istype(p, /datum/vampire_passive))
var/datum/vampire_passive/power = p
to_chat(owner, "<span class='notice'>[power.gain_desc]</span>")
to_chat(owner, "<span class='boldnotice'>[power.gain_desc]</span>")
/datum/game_mode/proc/remove_vampire(datum/mind/vampire_mind)
if(vampire_mind in vampires)
@@ -414,6 +427,9 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
var/turf/T = locate(round(ax, 0.5), round(ay, 0.5), owner.z)
if(!T)
return
if(T.x == 1 || T.x == world.maxx || T.y == 1 || T.y == world.maxy)
break
@@ -427,6 +443,8 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
to_chat(owner, "<span class='userdanger'>Your body is turning to ash, get out of the light now!</span>")
owner.adjustCloneLoss(10) //I'm melting!
vamp_burn(85)
if(owner.cloneloss >= 100)
owner.dust()
/datum/vampire/proc/handle_vampire()
if(owner.hud_used)
@@ -440,31 +458,49 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
hud.show_hud(hud.hud_version)
hud.vampire_blood_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font face='Small Fonts' color='#ce0202'>[bloodusable]</font></div>"
handle_vampire_cloak()
if(istype(owner.loc, /turf/space))
if(istype(get_turf(owner), /turf/space))
check_sun()
if(istype(owner.loc.loc, /area/chapel) && !get_ability(/datum/vampire_passive/full))
if(istype(get_area(owner), /area/chapel) && !get_ability(/datum/vampire_passive/full))
vamp_burn(7)
nullified = max(0, nullified - 1)
nullified = max(0, nullified - 2)
/datum/vampire/proc/handle_vampire_cloak()
if(!ishuman(owner))
owner.alpha = 255
return
var/turf/simulated/T = get_turf(owner)
var/light_available = T.get_lumcount(0.5) * 10
var/light_available = T.get_lumcount() * 10
if(!istype(T))
return 0
return
if(!iscloaking)
if(!iscloaking || owner.on_fire)
owner.alpha = 255
return 0
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
return
if(light_available <= 2)
owner.alpha = round((255 * 0.15))
return 1
else
owner.alpha = round((255 * 0.80))
owner.alpha = 38 // round(255 * 0.15)
ADD_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
return
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
owner.alpha = 204 // 255 * 0.80
/datum/vampire/proc/adjust_blood(mob/living/carbon/C, blood_amount = 0)
if(C)
var/unique_suck_id = C.UID()
if(!(unique_suck_id in drained_humans))
drained_humans[unique_suck_id] = 0
if(drained_humans[unique_suck_id] >= BLOOD_DRAIN_LIMIT)
return
drained_humans[unique_suck_id] += blood_amount
bloodtotal += blood_amount
bloodusable += blood_amount
check_vampire_upgrade(TRUE)
for(var/obj/effect/proc_holder/spell/S in powers)
if(S.action)
S.action.UpdateButtonIcon()
/datum/vampire/proc/vamp_burn(burn_chance)
if(prob(burn_chance) && owner.health >= 50)
@@ -491,3 +527,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
static_inventory -= vampire_blood_display
QDEL_NULL(vampire_blood_display)
show_hud(hud_version)
/datum/vampire/vv_edit_var(var_name, var_value)
. = ..()
check_vampire_upgrade(TRUE)
@@ -1,611 +0,0 @@
//This should hold all the vampire related powers
/obj/effect/proc_holder/spell/vampire
panel = "Vampire"
school = "vampire"
clothes_req = 0
range = 1
charge_max = 1800
action_background_icon_state = "bg_vampire"
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
var/required_blood = 0
var/gain_desc = null
var/deduct_blood_on_cast = TRUE //Do we want to take the blood when this is cast, or at a later point?
/obj/effect/proc_holder/spell/vampire/New()
..()
if(!gain_desc)
gain_desc = "You have gained \the [src] ability."
/obj/effect/proc_holder/spell/vampire/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!user.mind)
return 0
if(!ishuman(user))
to_chat(user, "<span class='warning'>You are in too weak of a form to do this!</span>")
return 0
var/datum/vampire/vampire = user.mind.vampire
if(!vampire)
return 0
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
if(user.stat >= DEAD)
to_chat(user, "<span class='warning'>Not when you're dead!</span>")
return 0
if(vampire.nullified && !fullpower)
to_chat(user, "<span class='warning'>Something is blocking your powers!</span>")
return 0
if(vampire.bloodusable < required_blood)
to_chat(user, "<span class='warning'>You require at least [required_blood] units of usable blood to do that!</span>")
return 0
return ..()
/obj/effect/proc_holder/spell/vampire/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
if(!user.mind)
return 0
if(!ishuman(user))
return 0
var/datum/vampire/vampire = user.mind.vampire
if(!vampire)
return 0
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
if(user.stat >= DEAD)
return 0
if(vampire.nullified && !fullpower)
return 0
if(vampire.bloodusable < required_blood)
return 0
if(istype(loc.loc, /area/chapel) && !fullpower)
return 0
return ..()
/obj/effect/proc_holder/spell/vampire/proc/affects(mob/target, mob/user = usr)
//Other vampires aren't affected
if(target.mind && target.mind.vampire)
return 0
//Vampires who have reached their full potential can affect nearly everything
if(user.mind.vampire.get_ability(/datum/vampire_passive/full))
return 1
//Holy characters are resistant to vampire powers
if(target.mind && target.mind.isholy)
return 0
return 1
/obj/effect/proc_holder/spell/vampire/proc/can_reach(mob/M as mob)
if(M.loc == usr.loc)
return 1 //target and source are in the same thing
return M in oview_or_orange(range, usr, selection_type)
/obj/effect/proc_holder/spell/vampire/before_cast(list/targets)
// sanity check before we cast
if(!usr.mind || !usr.mind.vampire)
targets.Cut()
return
if(!required_blood)
return
// enforce blood
var/datum/vampire/vampire = usr.mind.vampire
if(required_blood <= vampire.bloodusable)
if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
return
vampire.bloodusable -= required_blood
else
// stop!!
targets.Cut()
if(targets.len)
to_chat(usr, "<span class='notice'><b>You have [vampire.bloodusable] left to use.</b></span>")
/obj/effect/proc_holder/spell/vampire/targetted/choose_targets(mob/user = usr)
var/list/possible_targets[0]
for(var/mob/living/carbon/C in oview_or_orange(range, user, selection_type))
possible_targets += C
var/mob/living/carbon/T = input(user, "Choose your victim.", name) as null|mob in possible_targets
if(!T || !can_reach(T))
revert_cast(user)
return
perform(list(T), user = user)
/obj/effect/proc_holder/spell/vampire/self/choose_targets(mob/user = usr)
perform(list(user))
/obj/effect/proc_holder/spell/vampire/mob_aoe/choose_targets(mob/user = usr)
var/list/targets[0]
for(var/mob/living/carbon/C in oview_or_orange(range, user, selection_type))
targets += C
if(!targets.len)
revert_cast(user)
return
perform(targets, user = user)
/datum/vampire_passive
var/gain_desc
/datum/vampire_passive/New()
..()
if(!gain_desc)
gain_desc = "You have gained \the [src] ability."
////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/effect/proc_holder/spell/vampire/self/rejuvenate
name = "Rejuvenate"
desc= "Use reserve blood to enliven your body, removing any incapacitating effects."
action_icon_state = "vampire_rejuvinate"
charge_max = 200
stat_allowed = 1
/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast(list/targets, mob/user = usr)
var/mob/living/U = user
user.SetWeakened(0)
user.SetStunned(0)
user.SetParalysis(0)
user.SetSleeping(0)
U.adjustStaminaLoss(-75)
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
spawn(1)
if(usr.mind.vampire.get_ability(/datum/vampire_passive/regen))
for(var/i = 1 to 5)
U.adjustBruteLoss(-2)
U.adjustOxyLoss(-5)
U.adjustToxLoss(-2)
U.adjustFireLoss(-2)
sleep(35)
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise
name = "Hypnotise (20)"
desc= "A piercing stare that incapacitates your victim for a good length of time."
action_icon_state = "vampire_hypnotise"
required_blood = 20
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
user.visible_message("<span class='warning'>[user]'s eyes flash briefly as [user.p_they()] stare[user.p_s()] into [target]'s eyes</span>")
if(do_mob(user, target, 50))
if(!affects(target))
to_chat(user, "<span class='warning'>Your piercing gaze fails to knock out [target].</span>")
to_chat(target, "<span class='notice'>[user]'s feeble gaze is ineffective.</span>")
else
to_chat(user, "<span class='warning'>Your piercing gaze knocks out [target].</span>")
to_chat(target, "<span class='warning'>You find yourself unable to move and barely able to speak.</span>")
target.Weaken(10)
target.Stun(10)
target.stuttering = 10
else
revert_cast(usr)
to_chat(usr, "<span class='warning'>You broke your gaze.</span>")
/obj/effect/proc_holder/spell/vampire/targetted/disease
name = "Diseased Touch (100)"
desc = "Touches your victim with infected blood giving them Grave Fever, which will, left untreated, causes toxic building and frequent collapsing."
gain_desc = "You have gained the Diseased Touch ability which causes those you touch to become weak unless treated medically."
action_icon_state = "vampire_disease"
required_blood = 100
/obj/effect/proc_holder/spell/vampire/targetted/disease/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/target in targets)
to_chat(user, "<span class='warning'>You stealthily infect [target] with your diseased touch.</span>")
target.help_shake_act(user)
if(!affects(target))
to_chat(user, "<span class='warning'>They seem to be unaffected.</span>")
continue
var/datum/disease/D = new /datum/disease/vampire
target.ForceContractDisease(D)
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare
name = "Glare"
desc = "A scary glare that incapacitates people for a short while around you."
action_icon_state = "vampire_glare"
charge_max = 300
stat_allowed = 1
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare/cast(list/targets, mob/user = usr)
user.visible_message("<span class='warning'>[user]'s eyes emit a blinding flash!</span>")
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
var/obj/item/clothing/glasses/sunglasses/blindfold/B = H.glasses
if(B.tint)
to_chat(user, "<span class='warning'>You're blindfolded!</span>")
return
for(var/mob/living/target in targets)
if(!affects(target))
continue
target.Stun(5)
target.Weaken(5)
target.stuttering = 20
to_chat(target, "<span class='warning'>You are blinded by [user]'s glare.</span>")
add_attack_logs(user, target, "(Vampire) Glared at")
/obj/effect/proc_holder/spell/vampire/self/shapeshift
name = "Shapeshift (50)"
desc = "Changes your name and appearance at the cost of 50 blood and has a cooldown of 3 minutes."
gain_desc = "You have gained the shapeshifting ability, at the cost of stored blood you can change your form permanently."
action_icon_state = "genetic_poly"
required_blood = 50
/obj/effect/proc_holder/spell/vampire/self/shapeshift/cast(list/targets, mob/user = usr)
user.visible_message("<span class='warning'>[user] transforms!</span>")
if(ishuman(user))
var/mob/living/carbon/human/H = user
scramble(1, H, 100)
H.real_name = random_name(H.gender, H.dna.species.name) //Give them a name that makes sense for their species.
H.sync_organ_dna(assimilate = 1)
H.update_body()
H.reset_hair() //No more winding up with hairstyles you're not supposed to have, and blowing your cover.
H.reset_markings() //...Or markings.
H.dna.ResetUIFrom(H)
H.flavor_text = ""
user.update_icons()
/obj/effect/proc_holder/spell/vampire/self/screech
name = "Chiropteran Screech (30)"
desc = "An extremely loud shriek that stuns nearby humans and breaks windows as well."
gain_desc = "You have gained the Chiropteran Screech ability which stuns anything with ears in a large radius and shatters glass in the process."
action_icon_state = "vampire_screech"
required_blood = 30
/obj/effect/proc_holder/spell/vampire/self/screech/cast(list/targets, mob/user = usr)
user.visible_message("<span class='warning'>[user] lets out an ear piercing shriek!</span>", "<span class='warning'>You let out a loud shriek.</span>", "<span class='warning'>You hear a loud painful shriek!</span>")
for(var/mob/living/carbon/C in hearers(4))
if(C == user)
continue
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL)
continue
if(!affects(C))
continue
to_chat(C, "<span class='warning'><font size='3'><b>You hear a ear piercing shriek and your senses dull!</font></b></span>")
C.Weaken(4)
C.AdjustEarDamage(0, 20)
C.Stuttering(20)
C.Stun(4)
C.Jitter(150)
for(var/obj/structure/window/W in view(4))
W.deconstruct(FALSE)
playsound(user.loc, 'sound/effects/creepyshriek.ogg', 100, 1)
/proc/isvampirethrall(mob/living/M as mob)
return istype(M) && M.mind && SSticker && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
/obj/effect/proc_holder/spell/vampire/targetted/enthrall
name = "Enthrall (300)"
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
gain_desc = "You have gained the Enthrall ability which at a heavy blood cost allows you to enslave a human that is not loyal to any other for a random period of time."
action_icon_state = "vampire_enthrall"
required_blood = 300
deduct_blood_on_cast = FALSE
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/cast(list/targets, mob/user = usr)
var/datum/vampire/vampire = user.mind.vampire
for(var/mob/living/target in targets)
user.visible_message("<span class='warning'>[user] bites [target]'s neck!</span>", "<span class='warning'>You bite [target]'s neck and begin the flow of power.</span>")
to_chat(target, "<span class='warning'>You feel the tendrils of evil invade your mind.</span>")
if(!ishuman(target))
to_chat(user, "<span class='warning'>You can only enthrall humans.</span>")
break
if(do_mob(user, target, 50))
if(can_enthrall(user, target))
handle_enthrall(user, target)
vampire.bloodusable -= required_blood //we take the blood after enthralling, not before
else
revert_cast(user)
to_chat(user, "<span class='warning'>You or your target either moved or you dont have enough usable blood.</span>")
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
var/enthrall_safe = 0
for(var/obj/item/implant/mindshield/L in C)
if(L && L.implanted)
enthrall_safe = 1
break
for(var/obj/item/implant/traitor/T in C)
if(T && T.implanted)
enthrall_safe = 1
break
if(!C)
log_runtime(EXCEPTION("something bad happened on enthralling a mob, attacker is [user] [user.key] \ref[user]"), user)
return 0
if(!C.mind)
to_chat(user, "<span class='warning'>[C.name]'s mind is not there for you to enthrall.</span>")
return 0
if(enthrall_safe || ( C.mind in SSticker.mode.vampires )||( C.mind.vampire )||( C.mind in SSticker.mode.vampire_enthralled ))
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You feel a familiar sensation in your skull that quickly dissipates.</span>")
return 0
if(!affects(C))
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>Your faith of [SSticker.Bible_deity_name] has kept your mind clear of all evil.</span>")
return 0
if(!ishuman(C))
to_chat(user, "<span class='warning'>You can only enthrall humans!</span>")
return 0
return 1
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H as mob)
if(!istype(H))
return 0
var/ref = "\ref[user.mind]"
if(!(ref in SSticker.mode.vampire_thralls))
SSticker.mode.vampire_thralls[ref] = list(H.mind)
else
SSticker.mode.vampire_thralls[ref] += H.mind
SSticker.mode.update_vampire_icons_added(H.mind)
SSticker.mode.update_vampire_icons_added(user.mind)
var/datum/mindslaves/slaved = user.mind.som
H.mind.som = slaved
slaved.serv += H
slaved.add_serv_hud(user.mind, "vampire")//handles master servent icons
slaved.add_serv_hud(H.mind, "vampthrall")
SSticker.mode.vampire_enthralled.Add(H.mind)
SSticker.mode.vampire_enthralled[H.mind] = user.mind
H.mind.special_role = SPECIAL_ROLE_VAMPIRE_THRALL
var/datum/objective/protect/serve_objective = new
serve_objective.owner = user.mind
serve_objective.target = H.mind
serve_objective.explanation_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
H.mind.objectives += serve_objective
to_chat(H, "<span class='biggerdanger'>You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.</span>")
to_chat(user, "<span class='warning'>You have successfully Enthralled [H]. <i>If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.</i></span>")
H.Stun(2)
add_attack_logs(user, H, "Vampire-thralled")
/obj/effect/proc_holder/spell/vampire/self/cloak
name = "Cloak of Darkness"
desc = "Toggles whether you are currently cloaking yourself in darkness."
gain_desc = "You have gained the Cloak of Darkness ability which when toggled makes you near invisible in the shroud of darkness."
action_icon_state = "vampire_cloak"
charge_max = 10
/obj/effect/proc_holder/spell/vampire/self/cloak/New()
..()
update_name()
/obj/effect/proc_holder/spell/vampire/self/cloak/proc/update_name()
var/mob/living/user = loc
if(!ishuman(user) || !user.mind || !user.mind.vampire)
return
name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
/obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr)
var/datum/vampire/V = user.mind.vampire
V.iscloaking = !V.iscloaking
update_name()
to_chat(user, "<span class='notice'>You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.</span>")
/obj/effect/proc_holder/spell/vampire/bats
name = "Summon Bats (75)"
desc = "You summon a pair of space bats who attack nearby targets until they or their target is dead."
gain_desc = "You have gained the Summon Bats ability."
action_icon_state = "vampire_bats"
charge_max = 1200
required_blood = 75
var/num_bats = 2
/obj/effect/proc_holder/spell/vampire/bats/choose_targets(mob/user = usr)
var/list/turf/locs = new
for(var/direction in GLOB.alldirs) //looking for bat spawns
if(locs.len == num_bats) //we found 2 locations and thats all we need
break
var/turf/T = get_step(usr, direction) //getting a loc in that direction
if(AStar(user, T, /turf/proc/Distance, 1, simulated_only = 0)) // if a path exists, so no dense objects in the way its valid salid
locs += T
// pad with player location
for(var/i = locs.len + 1 to num_bats)
locs += user.loc
perform(locs, user = user)
/obj/effect/proc_holder/spell/vampire/bats/cast(list/targets, mob/user = usr)
for(var/T in targets)
new /mob/living/simple_animal/hostile/scarybat(T, user)
/obj/effect/proc_holder/spell/vampire/self/jaunt
name = "Mist Form (30)"
desc = "You take on the form of mist for a short period of time."
gain_desc = "You have gained the Mist Form ability which allows you to take on the form of mist for a short period and pass over any obstacle in your path."
action_icon_state = "mist"
charge_max = 600
required_blood = 30
centcom_cancast = 0
var/jaunt_duration = 50 //in deciseconds
/obj/effect/proc_holder/spell/vampire/self/jaunt/cast(list/targets, mob/user = usr)
spawn(0)
var/mob/living/U = user
var/originalloc = get_turf(user.loc)
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt(originalloc)
var/atom/movable/overlay/animation = new /atom/movable/overlay(originalloc)
animation.name = "blood"
animation.density = 0
animation.anchored = 1
animation.icon = 'icons/mob/mob.dmi'
animation.icon_state = "empty"
animation.layer = 5
animation.master = holder
U.ExtinguishMob()
flick("mist", animation)
user.forceMove(holder)
user.client.eye = holder
sleep(jaunt_duration)
var/mobloc = get_turf(user.loc)
animation.loc = mobloc
user.canmove = 0
sleep(20)
flick("mist_reappear", animation)
sleep(5)
if(!user.Move(mobloc))
for(var/turf/T in orange(7, mobloc))
if(T)
if(user.Move(T))
break
user.canmove = 1
user.client.eye = user
qdel(animation)
qdel(holder)
// Blink for vamps
// Less smoke spam.
/obj/effect/proc_holder/spell/vampire/shadowstep
name = "Shadowstep (30)"
desc = "Vanish into the shadows."
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
action_icon_state = "shadowblink"
charge_max = 20
required_blood = 30
centcom_cancast = 0
// Teleport radii
var/inner_tele_radius = 0
var/outer_tele_radius = 6
// Maximum lighting_lumcount.
var/max_lum = 1
/obj/effect/proc_holder/spell/vampire/shadowstep/choose_targets(mob/user = usr)
var/list/turfs = new/list()
for(var/turf/T in range(user, outer_tele_radius))
if(T in range(user, inner_tele_radius))
continue
if(istype(T, /turf/space))
continue
if(T.density)
continue
if(T.x > world.maxx-outer_tele_radius || T.x < outer_tele_radius)
continue //putting them at the edge is dumb
if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius)
continue
var/lightingcount = T.get_lumcount(0.5) * 10
// LIGHTING CHECK
if(lightingcount > max_lum)
continue
turfs += T
if(!turfs.len)
revert_cast(user)
to_chat(user, "<span class='warning'>You cannot find darkness to step to.</span>")
return
turfs = list(pick(turfs)) // Pick a single turf for the vampire to jump to.
perform(turfs, user = user)
// `targets` should only ever contain the 1 valid turf we're jumping to, even though its a list, that's just how the cast() proc works.
/obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr)
spawn(0)
if(!LAZYLEN(targets)) // If for some reason the turf got deleted.
return
var/mob/living/U = user
U.ExtinguishMob()
var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(user))
animation.name = user.name
animation.density = 0
animation.anchored = 1
animation.icon = user.icon
animation.alpha = 127
animation.layer = 5
//animation.master = src
user.forceMove(targets[1])
spawn(10)
qdel(animation)
/datum/vampire_passive/regen
gain_desc = "Your rejuvination abilities have improved and will now heal you over time when used."
/datum/vampire_passive/vision
gain_desc = "Your vampiric vision has improved."
/datum/vampire_passive/full
gain_desc = "You have reached your full potential and are no longer weak to the effects of anything holy and your vision has been improved greatly."
/obj/effect/proc_holder/spell/targeted/raise_vampires
name = "Raise Vampires"
desc = "Summons deadly vampires from bluespace."
school = "transmutation"
charge_max = 100
clothes_req = 0
human_req = 1
invocation = "none"
invocation_type = "none"
max_targets = 0
range = 3
cooldown_min = 20
action_icon_state = "revive_thrall"
sound = 'sound/magic/wandodeath.ogg'
/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
new /obj/effect/temp_visual/cult/sparks(user.loc)
var/turf/T = get_turf(user)
to_chat(user, "<span class='warning'>You call out within bluespace, summoning more vampiric spirits to aid you!</span>")
for(var/mob/living/carbon/human/H in targets)
T.Beam(H, "sendbeam", 'icons/effects/effects.dmi', time=30, maxdistance=7, beam_type=/obj/effect/ebeam)
new /obj/effect/temp_visual/cult/sparks(H.loc)
H.raise_vampire(user)
/mob/living/carbon/human/proc/raise_vampire(mob/M)
if(!istype(M))
log_debug("human/proc/raise_vampire called with invalid argument.")
return
if(!mind)
visible_message("[src] looks to be too stupid to understand what is going on.")
return
if(dna && (NO_BLOOD in dna.species.species_traits) || dna.species.exotic_blood || !blood_volume)
visible_message("[src] looks unfazed!")
return
if(mind.vampire || mind.special_role == SPECIAL_ROLE_VAMPIRE || mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
visible_message("<span class='notice'>[src] looks refreshed!</span>")
adjustBruteLoss(-60)
adjustFireLoss(-60)
for(var/obj/item/organ/external/E in bodyparts)
if(prob(25))
E.mend_fracture()
return
if(stat != DEAD)
if(IsWeakened())
visible_message("<span class='warning'>[src] looks to be in pain!</span>")
adjustBrainLoss(60)
else
visible_message("<span class='warning'>[src] looks to be stunned by the energy!</span>")
Weaken(20)
return
for(var/obj/item/implant/mindshield/L in src)
if(L && L.implanted)
qdel(L)
for(var/obj/item/implant/traitor/T in src)
if(T && T.implanted)
qdel(T)
visible_message("<span class='warning'>[src] gets an eerie red glow in their eyes!</span>")
var/datum/objective/protect/protect_objective = new
protect_objective.owner = mind
protect_objective.target = M.mind
protect_objective.explanation_text = "Protect [M.real_name]."
mind.objectives += protect_objective
add_attack_logs(M, src, "Vampire-sired")
mind.make_Vampire()
revive()
Weaken(20)
@@ -0,0 +1,79 @@
/obj/effect/proc_holder/spell/self/vampire/blood_swell
name = "Blood Swell (30)"
desc = "You infuse your body with blood, making you highly resistant to stuns and physical damage. However, this makes you unable to fire ranged weapons while it is active."
gain_desc = "You have gained the ability to temporarly resist large amounts of stuns and physical damage."
charge_max = 40 SECONDS
required_blood = 30
action_icon_state = "blood_swell"
/obj/effect/proc_holder/spell/self/vampire/blood_swell/cast(list/targets, mob/user)
var/mob/living/target = targets[1]
if(ishuman(target))
var/mob/living/carbon/human/H = target
H.apply_status_effect(STATUS_EFFECT_BLOOD_SWELL)
/datum/vampire_passive/blood_swell_upgrade
gain_desc = "While blood swell is active all of your melee attacks deal increased damage."
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force
name = "Overwhelming Force"
desc = "When toggled you will automatically pry open doors that you bump into if you do not have access."
gain_desc = "You have gained the ability to force open doors at a small blood cost."
charge_max = 2 SECONDS
action_icon_state = "OH_YEAAAAH"
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force/cast(list/targets, mob/user)
if(!HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
to_chat(user, "<span class='warning'>You feel MIGHTY!</span>")
ADD_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
user.status_flags &= ~CANPUSH
user.move_resist = MOVE_FORCE_STRONG
else
REMOVE_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
user.move_resist = MOVE_FORCE_DEFAULT
user.status_flags |= CANPUSH
/obj/effect/proc_holder/spell/self/vampire/blood_rush
name = "Blood Rush (30)"
desc = "Infuse yourself with blood magic to boost your movement speed."
gain_desc = "You have gained the ability to temporarily move at high speeds."
charge_max = 30 SECONDS
required_blood = 30
action_icon_state = "blood_rush"
/obj/effect/proc_holder/spell/self/vampire/blood_rush/cast(list/targets, mob/user)
var/mob/living/target = targets[1]
if(ishuman(target))
var/mob/living/carbon/human/H = target
to_chat(H, "<span class='notice'>You feel a rush of energy!</span>")
H.apply_status_effect(STATUS_EFFECT_BLOOD_RUSH)
/obj/effect/proc_holder/spell/targeted/click/charge
name = "Charge (30)"
desc = "You charge at wherever you click on screen, dealing large amounts of damage, stunning and destroying walls and other objects."
gain_desc = "You can now charge at a target on screen, dealing massive damage and destroying structures."
required_blood = 30
charge_max = 30 SECONDS
vampire_ability = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
action_icon_state = "vampire_charge"
allowed_type = /atom
range = 7
auto_target_single = FALSE
click_radius = -1
/obj/effect/proc_holder/spell/targeted/click/charge/can_cast(mob/user, charge_check, show_message)
var/mob/living/L = user
if(L.IsWeakened() || L.resting)
return FALSE
return ..()
/obj/effect/proc_holder/spell/targeted/click/charge/cast(list/targets, mob/user)
var/target = targets[1]
if(isliving(user))
var/mob/living/L = user
L.apply_status_effect(STATUS_EFFECT_CHARGING)
L.throw_at(target, range, 1, L, FALSE, callback = CALLBACK(L, /mob/living/.proc/remove_status_effect, STATUS_EFFECT_CHARGING))
@@ -0,0 +1,243 @@
/obj/effect/proc_holder/spell/self/vampire/vamp_claws
name = "Vampiric Claws (30)"
desc = "You channel blood magics to forge deadly vampiric claws that leech blood and strike rapidly. Cannot be used if you are holding something that cannot be dropped."
gain_desc = "You have gained the ability to forge your hands into vampiric claws."
charge_max = 30 SECONDS
required_blood = 30
action_icon_state = "vampire_claws"
/obj/effect/proc_holder/spell/self/vampire/vamp_claws/cast(mob/user)
if(user.l_hand || user.r_hand)
to_chat(user, "<span class='notice'>You drop what was in your hands as large blades spring from your fingers!</span>")
user.drop_l_hand()
user.drop_r_hand()
else
to_chat(user, "<span class='notice'>Large blades of blood spring from your fingers!</span>")
var/obj/item/twohanded/required/vamp_claws/claws = new /obj/item/twohanded/required/vamp_claws(user.loc)
user.put_in_hands(claws)
/obj/effect/proc_holder/spell/self/vampire/vamp_claws/can_cast(mob/user, charge_check, show_message)
var/mob/living/L = user
if(L.canUnEquip(L.l_hand) && L.canUnEquip(L.r_hand))
return ..()
/obj/item/twohanded/required/vamp_claws
name = "vampiric claws"
desc = "A pair of eldritch claws made of living blood, they seem to flow yet they are solid"
icon = 'icons/effects/vampire_effects.dmi'
icon_state = "vamp_claws"
w_class = WEIGHT_CLASS_BULKY
flags = ABSTRACT | NODROP | DROPDEL
force = 10
force_wielded = 10
armour_penetration = 20
block_chance = 50
sharp = TRUE
attack_effect_override = ATTACK_EFFECT_CLAW
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "savaged", "clawed")
sprite_sheets_inhand = list("Vox" = 'icons/mob/clothing/species/vox/held.dmi', "Drask" = 'icons/mob/clothing/species/drask/held.dmi')
var/durability = 20
var/blood_drain_amount = 15
var/blood_absorbed_amount = 5
/obj/item/twohanded/required/vamp_claws/afterattack(atom/target, mob/user, proximity)
if(!user.mind?.vampire)
return
if(iscarbon(target))
var/mob/living/carbon/C = target
if(C.ckey && C.stat != DEAD && C.affects_vampire() && !(NO_BLOOD in C.dna.species.species_traits))
C.bleed(blood_drain_amount)
user.mind.vampire.adjust_blood(C, blood_absorbed_amount)
durability -= 1
if(durability <= 0)
qdel(src)
to_chat(user, "<span class='warning'>Your claws shatter!</span>")
/obj/item/twohanded/required/vamp_claws/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/twohanded/required/vamp_claws/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/twohanded/required/vamp_claws/process()
durability -= 1
if(durability <= 0)
qdel(src)
/obj/item/twohanded/required/vamp_claws/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type)
if(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0
return ..()
/obj/item/twohanded/required/vamp_claws/melee_attack_chain(mob/user, atom/target, params)
..()
if(wielded)
user.changeNext_move(CLICK_CD_MELEE * 0.5)
/obj/item/twohanded/required/vamp_claws/attack_self(mob/user)
to_chat(user, "<span class='notice'>You dispel your claws!</span>")
qdel(src)
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils
name = "Blood Tendrils (10)"
desc = "You summon blood tendrils from bluespace after a delay to ensnare people in an area, slowing them down."
gain_desc = "You have gained the ability to summon blood tendrils to slow people down in an area that you target."
required_blood = 10
vampire_ability = TRUE
click_radius = 1
charge_max = 30 SECONDS
allowed_type = /atom
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
action_icon_state = "blood_tendrils"
sound = 'sound/misc/enter_blood.ogg'
var/area_of_affect = 1
selection_activated_message = "<span class='notice'>You channel blood magics to weaken the bluespace veil. <B>Left-click to cast at a target area!</B></span>"
selection_deactivated_message = "<span class='notice'>Your magics subside.</span>"
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/cast(list/targets, mob/user)
var/turf/T = get_turf(targets[1]) // there should only ever be one entry in targets for this spell
for(var/turf/simulated/blood_turf in view(area_of_affect, T))
if(blood_turf.density)
continue
new /obj/effect/temp_visual/blood_tendril(blood_turf)
addtimer(CALLBACK(src, .proc/apply_slowdown, T, area_of_affect, 3, user), 0.5 SECONDS)
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/proc/apply_slowdown(turf/T, distance, slowed_amount, mob/user)
for(var/mob/living/L in view(distance, T))
if(L.affects_vampire(user))
L.AdjustSlowed(slowed_amount)
L.visible_message("<span class='warning'>[L] gets ensared in blood tendrils, restricting [L.p_their()] movement!</span>")
new /obj/effect/temp_visual/blood_tendril/long(get_turf(L))
/obj/effect/temp_visual/blood_tendril
icon = 'icons/effects/vampire_effects.dmi'
icon_state = "blood_tendril"
duration = 1 SECONDS
/obj/effect/temp_visual/blood_tendril/long
duration = 2 SECONDS
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool
name = "Sanguine Pool (50)"
desc = "You shift your form into a pool of blood, making you invulnerable and able to move through anything that's not a wall or space. You leave a trail of blood behind you when you do this."
gain_desc = "You have gained the ability to shift into a pool of blood, allowing you to evade pursuers with great mobility."
vampire_ability = TRUE
required_blood = 50
jaunt_duration = 3 SECONDS
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
action_icon_state = "blood_pool"
jaunt_type_path = /obj/effect/dummy/spell_jaunt/blood_pool
jaunt_water_effect = FALSE
jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out
jaunt_in_type = /obj/effect/temp_visual/dir_setting/cult/phase
jaunt_in_time = 0
sound1 = 'sound/misc/enter_blood.ogg'
/obj/effect/proc_holder/spell/blood_eruption
name = "Blood Eruption (100)"
desc = "Every pool of blood in 4 tiles erupts with a spike of living blood, damaging anyone stood on it."
gain_desc = "You have gained the ability to weaponise pools of blood to damage those stood on them."
vampire_ability = TRUE
required_blood = 100
charge_max = 200 SECONDS
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
action_icon_state = "blood_spikes"
/obj/effect/proc_holder/spell/blood_eruption/cast(list/targets, mob/user)
for(var/mob/living/L in targets)
var/turf/T = get_turf(L)
var/obj/effect/decal/cleanable/blood/B = locate(/obj/effect/decal/cleanable/blood) in T
var/obj/effect/temp_visual/blood_spike/spike = new /obj/effect/temp_visual/blood_spike(T)
spike.color = B.basecolor
playsound(L, 'sound/misc/demon_attack1.ogg', 50, TRUE)
L.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
L.visible_message("<span class='warning'><b>[L] gets impaled by a spike of living blood!</b></span>")
/obj/effect/proc_holder/spell/blood_eruption/choose_targets(mob/user)
var/list/targets = list()
for(var/mob/living/L in view(4, user))
var/turf/T = get_turf(L)
if(locate(/obj/effect/decal/cleanable/blood) in T)
if(L.affects_vampire(user) && !isLivingSSD(L))
targets.Add(L)
if(!length(targets))
revert_cast(user)
return
perform(targets)
/obj/effect/temp_visual/blood_spike
icon = 'icons/effects/vampire_effects.dmi'
icon_state = "bloodspike_white"
duration = 0.3 SECONDS
/obj/effect/proc_holder/spell/self/vampire/blood_spill
name = "The Blood Bringers Rite"
desc = "When toggled, everyone around you begins to bleed profusely."
gain_desc = "You have gained the ability to rip the very life force out of people and absorb it, healing you."
charge_max = 10 SECONDS
action_icon_state = "blood_bringers_rite"
required_blood = 10
/obj/effect/proc_holder/spell/self/vampire/blood_spill/cast(list/targets, mob/user)
var/mob/target = targets[1]
if(!target.mind.vampire.get_ability(/datum/vampire_passive/blood_spill))
target.mind.vampire.force_add_ability(/datum/vampire_passive/blood_spill)
else
for(var/datum/vampire_passive/blood_spill/B in target.mind.vampire.powers)
target.mind.vampire.remove_ability(B)
/datum/vampire_passive/blood_spill
var/max_beams = 10
/datum/vampire_passive/blood_spill/New()
..()
START_PROCESSING(SSobj, src)
/datum/vampire_passive/blood_spill/Destroy(force, ...)
STOP_PROCESSING(SSobj, src)
return ..()
/datum/vampire_passive/blood_spill/process()
var/beam_number = 0
var/turf/T = get_turf(owner)
for(var/mob/living/carbon/human/H in view(7, T))
if(NO_BLOOD in H.dna.species.species_traits)
continue
if(!H.affects_vampire(owner) || H.stat)
continue
var/drain_amount = rand(5, 10)
beam_number++
H.bleed(drain_amount)
H.Beam(owner, icon_state = "drainbeam", time = 2 SECONDS)
H.adjustBruteLoss(2)
owner.heal_overall_damage(8, 2, TRUE)
owner.adjustStaminaLoss(-15)
owner.AdjustStunned(-1)
owner.AdjustWeakened(-1)
if(drain_amount == 10)
to_chat(H, "<span class='warning'>You feel your life force draining!</b></span>")
if(beam_number >= max_beams)
break
owner.mind.vampire.bloodusable = max(owner.mind.vampire.bloodusable - 10, 0)
if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
owner.mind.vampire.remove_ability(src)
@@ -0,0 +1,188 @@
/obj/effect/proc_holder/spell/self/vampire/cloak
name = "Cloak of Darkness"
desc = "Toggles whether you are currently cloaking yourself in darkness. When in darkness and toggled on, you move at increased speeds."
gain_desc = "You have gained the Cloak of Darkness ability, which when toggled makes you nearly invisible and highly agile in the shroud of darkness."
action_icon_state = "vampire_cloak"
charge_max = 2 SECONDS
/obj/effect/proc_holder/spell/self/vampire/cloak/New()
..()
update_name()
/obj/effect/proc_holder/spell/self/vampire/cloak/proc/update_name()
var/mob/living/user = loc
if(!ishuman(user) || !user.mind || !user.mind.vampire)
return
action.button.name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
/obj/effect/proc_holder/spell/self/vampire/cloak/cast(list/targets, mob/user = usr)
var/datum/vampire/V = user.mind.vampire
V.iscloaking = !V.iscloaking
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(V.iscloaking)
H.physiology.burn_mod *= 1.3
user.RegisterSignal(user, COMSIG_LIVING_IGNITED, /mob/living.proc/update_vampire_cloak)
else
user.UnregisterSignal(user, COMSIG_LIVING_IGNITED)
H.physiology.burn_mod /= 1.3
update_name()
to_chat(user, "<span class='notice'>You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.</span>")
/mob/living/proc/update_vampire_cloak()
SIGNAL_HANDLER
mind.vampire.handle_vampire_cloak()
/obj/effect/proc_holder/spell/targeted/click/shadow_snare
name = "Shadow Snare (20)"
desc = "You summon a trap on the ground. When crossed it will blind the target, extinguish any lights they may have, and ensnare them."
gain_desc = "You have gained the ability to summon a trap that will blind, ensnare, and turn off the lights of anyone who crosses it."
charge_max = 20 SECONDS
required_blood = 20
vampire_ability = TRUE
allowed_type = /turf/simulated
click_radius = -1
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
action_icon_state = "shadow_snare"
/obj/effect/proc_holder/spell/targeted/click/shadow_snare/cast(list/targets, mob/user)
var/turf/target = targets[1]
new /obj/item/restraints/legcuffs/beartrap/shadow_snare(target)
/obj/item/restraints/legcuffs/beartrap/shadow_snare
name = "shadow snare"
desc = "An almost transparent trap that melts into the shadows."
alpha = 60
armed = TRUE
anchored = TRUE
breakouttime = 5 SECONDS
flags = DROPDEL
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Crossed(AM, oldloc)
if(!iscarbon(AM) || !armed)
return
var/mob/living/carbon/C = AM
if(!C.affects_vampire()) // no parameter here so holy always protects
return
C.extinguish_light()
C.EyeBlind(10)
STOP_PROCESSING(SSobj, src) // won't wither away once you are trapped
..()
if(!iscarbon(loc)) // if it fails to latch onto someone for whatever reason, delete itself, we don't want unarmed ones lying around.
qdel(src)
/obj/item/restraints/legcuffs/beartrap/shadow_snare/attack_hand(mob/user)
Crossed(user)
/obj/item/restraints/legcuffs/beartrap/shadow_snare/attack_tk(mob/user)
if(iscarbon(user))
to_chat(user, "<span class='userdanger'>The snare sends a psychic backlash!</span>")
user.EyeBlind(10)
/obj/item/restraints/legcuffs/beartrap/shadow_snare/process()
var/turf/T = get_turf(src)
var/lighting_count = T.get_lumcount() * 10
if(lighting_count > 2)
obj_integrity -= 50
if(obj_integrity <= 0)
visible_message("<span class='notice'>[src] withers away.</span>")
qdel(src)
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/proc_holder/spell/targeted/click/dark_passage
name = "Dark Passage (30)"
desc = "You teleport to a targeted turf."
gain_desc = "You have gained the ability to blink a short distance towards a targeted turf."
charge_max = 40 SECONDS
required_blood = 30
vampire_ability = TRUE
allowed_type = /turf/simulated
click_radius = 0
centcom_cancast = FALSE
action_icon_state = "dark_passage"
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
/obj/effect/proc_holder/spell/targeted/click/dark_passage/cast(list/targets, mob/user)
var/turf/target = get_turf(targets[1])
new /obj/effect/temp_visual/vamp_mist_out(get_turf(user))
user.forceMove(target)
/obj/effect/temp_visual/vamp_mist_out
duration = 2 SECONDS
icon = 'icons/mob/mob.dmi'
icon_state = "mist"
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish
name = "Extinguish"
desc = "You extinguish any light source in an area around you."
gain_desc = "You have gained the ability to extinguish nearby light sources."
charge_max = 20 SECONDS
vampire_ability = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
action_icon_state = "vampire_extinguish"
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
T.extinguish_light()
for(var/atom/A in T.contents)
A.extinguish_light()
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness
name = "Eternal Darkness"
desc = "When toggled, you shroud the area around you in darkness and slowly lower the body temperature of people nearby."
gain_desc = "You have gained the ability to shroud the area around you in darkness, only the strongest of lights can pierce your unholy powers."
charge_max = 10 SECONDS
action_icon_state = "eternal_darkness"
required_blood = 5
var/shroud_power = -4
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness/cast(list/targets, mob/user)
var/mob/target = targets[1]
if(!target.mind.vampire.get_ability(/datum/vampire_passive/eternal_darkness))
target.mind.vampire.force_add_ability(/datum/vampire_passive/eternal_darkness)
target.set_light(6, shroud_power, "#AAD84B")
else
for(var/datum/vampire_passive/eternal_darkness/E in target.mind.vampire.powers)
target.mind.vampire.remove_ability(E)
/datum/vampire_passive/eternal_darkness
gain_desc = "You surround yourself in a unnatural darkness, freezing those around you."
/datum/vampire_passive/eternal_darkness/New()
..()
START_PROCESSING(SSobj, src)
/datum/vampire_passive/eternal_darkness/Destroy(force, ...)
owner.remove_light()
STOP_PROCESSING(SSobj, src)
return ..()
/datum/vampire_passive/eternal_darkness/process()
for(var/mob/living/L in view(6, owner))
if(L.affects_vampire(owner))
L.adjust_bodytemperature(-20 * TEMPERATURE_DAMAGE_COEFFICIENT)
owner.mind.vampire.bloodusable = max(owner.mind.vampire.bloodusable - 5, 0)
if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
owner.mind.vampire.remove_ability(src)
/datum/vampire_passive/xray
gain_desc = "You can now see through walls, incase you hadn't noticed."
@@ -0,0 +1,464 @@
//This should hold all the vampire related powers
/mob/living/proc/affects_vampire(mob/user)
//Other vampires aren't affected
if(mind?.vampire)
return FALSE
//Vampires who have reached their full potential can affect nearly everything
if(user?.mind.vampire.get_ability(/datum/vampire_passive/full))
return TRUE
//Holy characters are resistant to vampire powers
if(mind?.isholy)
return FALSE
return TRUE
/obj/effect/proc_holder/spell/self/choose_targets(mob/user = usr)
perform(list(user))
/obj/effect/proc_holder/spell/mob_aoe/choose_targets(mob/user = usr)
var/list/targets[0]
for(var/mob/living/L in view(range, user))
if(L == user)
continue
targets += L
if(!length(targets))
revert_cast(user)
return
perform(targets, user = user)
/obj/effect/proc_holder/spell/proc/before_cast_vampire(list/targets)
// sanity check before we cast
if(!usr.mind || !usr.mind.vampire)
targets.Cut()
return FALSE
if(!required_blood)
return
// enforce blood
var/datum/vampire/vampire = usr.mind.vampire
var/blood_cost_modifier = 1 + vampire.nullified / 100
var/blood_cost = round(required_blood * blood_cost_modifier)
if(blood_cost <= vampire.bloodusable)
if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
return
vampire.bloodusable -= blood_cost
SSblackbox.record_feedback("tally", "vampire_powers_used", 1, "[name]")
to_chat(usr, "<span class='boldnotice'>You have [vampire.bloodusable] left to use.</span>")
return TRUE
else
// stop!!
targets.Cut()
return FALSE
/datum/vampire_passive
var/gain_desc
var/mob/living/owner = null
/datum/vampire_passive/New()
..()
if(!gain_desc)
gain_desc = "You can now use [src]."
/datum/vampire_passive/Destroy(force, ...)
owner = null
return ..()
/obj/effect/proc_holder/spell/self/vampire
vampire_ability = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
/obj/effect/proc_holder/spell/self/vampire/rejuvenate
name = "Rejuvenate"
desc = "Use reserve blood to enliven your body, removing any incapacitating effects."
action_icon_state = "vampire_rejuvinate"
charge_max = 200
stat_allowed = 1
/obj/effect/proc_holder/spell/self/vampire/rejuvenate/cast(list/targets, mob/user = usr)
var/mob/living/U = user
U.SetWeakened(0)
U.SetStunned(0)
U.SetParalysis(0)
U.SetSleeping(0)
U.SetConfused(0)
U.adjustStaminaLoss(-100)
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
var/rejuv_bonus = U.mind.vampire.get_rejuv_bonus()
if(rejuv_bonus)
INVOKE_ASYNC(src, .proc/heal, U, rejuv_bonus)
/obj/effect/proc_holder/spell/self/vampire/rejuvenate/proc/heal(mob/living/user, rejuv_bonus)
for(var/i in 1 to 5)
user.adjustBruteLoss(-2 * rejuv_bonus)
user.adjustOxyLoss(-5 * rejuv_bonus)
user.adjustToxLoss(-2 * rejuv_bonus)
user.adjustFireLoss(-2 * rejuv_bonus)
for(var/datum/reagent/R in user.reagents.reagent_list)
if(!R.harmless)
user.reagents.remove_reagent(R.id, 2 * rejuv_bonus)
sleep(35)
/datum/vampire/proc/get_rejuv_bonus()
var/rejuv_multiplier = 0
if(!get_ability(/datum/vampire_passive/regen))
return rejuv_multiplier
if(subclass?.improved_rejuv_healing)
rejuv_multiplier = clamp((100 - owner.health) / 20, 1, 5) // brute and burn healing between 5 and 50
return rejuv_multiplier
return 1
/obj/effect/proc_holder/spell/self/vampire/specialize
name = "Choose Specialization"
desc = "Choose what sub-class of vampire you want to evolve into."
gain_desc = "You can now choose what specialization of vampire you want to evolve into."
charge_max = 2 SECONDS
action_icon_state = "select_class"
/obj/effect/proc_holder/spell/self/vampire/specialize/cast(mob/user)
ui_interact(user)
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "SpecMenu", "Specialisation Menu", 900, 600, master_ui, state)
ui.set_autoupdate(FALSE)
ui.open()
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_data(mob/user)
var/datum/vampire/vamp = user.mind.vampire
var/list/data = list("subclasses" = vamp.subclass)
return data
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_act(action, list/params)
if(..())
return
var/datum/vampire/vamp = usr.mind.vampire
if(vamp.subclass)
vamp.upgrade_tiers -= type
vamp.remove_ability(src)
return
switch(action)
if("umbrae")
vamp.add_subclass(SUBCLASS_UMBRAE)
vamp.upgrade_tiers -= type
vamp.remove_ability(src)
if("hemomancer")
vamp.add_subclass(SUBCLASS_HEMOMANCER)
vamp.upgrade_tiers -= type
vamp.remove_ability(src)
if("gargantua")
vamp.add_subclass(SUBCLASS_GARGANTUA)
vamp.upgrade_tiers -= type
vamp.remove_ability(src)
/datum/vampire/proc/add_subclass(subclass_to_add, announce = TRUE)
var/datum/vampire_subclass/new_subclass = new subclass_to_add
subclass = new_subclass
check_vampire_upgrade(announce)
SSblackbox.record_feedback("nested tally", "vampire_subclasses", 1, list("[new_subclass.name]"))
/obj/effect/proc_holder/spell/mob_aoe/glare
name = "Glare"
desc = "Your eyes flash, stunning and silencing anyone infront of you. It has lesser effects for those around you."
action_icon_state = "vampire_glare"
charge_max = 30 SECONDS
stat_allowed = 1
range = 1
vampire_ability = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
/// No deviation at all. Flashed from the front or front-left/front-right. Alternatively, flashed in direct view.
#define DEVIATION_NONE 3
/// Partial deviation. Flashed from the side. Alternatively, flashed out the corner of your eyes.
#define DEVIATION_PARTIAL 2
/// Full deviation. Flashed from directly behind or behind-left/behind-rack. Not flashed at all.
#define DEVIATION_FULL 1
/obj/effect/proc_holder/spell/mob_aoe/glare/cast(list/targets, mob/living/user = usr)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
var/obj/item/clothing/glasses/sunglasses/blindfold/B = H.glasses
if(B.tint)
to_chat(user, "<span class='warning'>You're blindfolded!</span>")
return
user.mob_light(LIGHT_COLOR_BLOOD_MAGIC, 3, _duration = 2)
user.visible_message("<span class='warning'>[user]'s eyes emit a blinding flash!</span>")
for(var/mob/living/target in targets)
if(!target.affects_vampire(user))
continue
var/deviation
if(user.weakened || user.resting)
deviation = DEVIATION_PARTIAL
else
deviation = calculate_deviation(target, user)
if(deviation == DEVIATION_FULL)
target.AdjustConfused(3)
target.adjustStaminaLoss(40)
else if(deviation == DEVIATION_PARTIAL)
target.Weaken(1)
target.AdjustConfused(3)
target.adjustStaminaLoss(40)
else
target.adjustStaminaLoss(120)
target.Weaken(6)
target.AdjustSilence(3)
target.flash_eyes(1, TRUE, TRUE)
to_chat(target, "<span class='warning'>You are blinded by [user]'s glare.</span>")
add_attack_logs(user, target, "(Vampire) Glared at")
/obj/effect/proc_holder/spell/mob_aoe/glare/proc/calculate_deviation(mob/victim, mob/attacker)
// Are they on the same tile? We'll return partial deviation. This may be someone flashing while lying down
if(victim.loc == attacker.loc)
return DEVIATION_PARTIAL
// If the victim was looking at the attacker, this is the direction they'd have to be facing.
var/attacker_to_victim = get_dir(attacker, victim)
// The victim's dir is necessarily a cardinal value.
var/attacker_dir = attacker.dir
// - - -
// - V - Attacker facing south
// # # #
// Attacker within 45 degrees of where the victim is facing.
if(attacker_dir & attacker_to_victim)
return DEVIATION_NONE
// # # #
// - V - Attacker facing south
// - - -
// Victim at 135 or more degrees of where the victim is facing.
if(attacker_dir & GetOppositeDir(attacker_to_victim))
return DEVIATION_FULL
// - - -
// # V # Attacker facing south
// - - -
// Victim lateral to the victim.
return DEVIATION_PARTIAL
#undef DEVIATION_NONE
#undef DEVIATION_PARTIAL
#undef DEVIATION_FULL
/datum/vampire_passive/regen
gain_desc = "Your rejuvenation abilities have improved and will now heal you over time when used."
/datum/vampire_passive/vision
gain_desc = "Your vampiric vision has improved."
/datum/vampire_passive/full
gain_desc = "You have reached your full potential. You are no longer weak to the effects of anything holy and your vision has improved greatly."
/obj/effect/proc_holder/spell/targeted/raise_vampires
name = "Raise Vampires"
desc = "Summons deadly vampires from bluespace."
school = "transmutation"
charge_max = 100
clothes_req = 0
human_req = 1
invocation = "none"
invocation_type = "none"
max_targets = 0
range = 3
cooldown_min = 20
action_icon_state = "revive_thrall"
vampire_ability = TRUE
sound = 'sound/magic/wandodeath.ogg'
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
gain_desc = "You have gained the ability to Raise Vampires. This extremely powerful AOE ability affects all humans near you. Vampires/thralls are healed. Corpses are raised as vampires. Others are stunned, then brain damaged, then killed."
/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
new /obj/effect/temp_visual/cult/sparks(user.loc)
var/turf/T = get_turf(user)
to_chat(user, "<span class='warning'>You call out within bluespace, summoning more vampiric spirits to aid you!</span>")
for(var/mob/living/carbon/human/H in targets)
T.Beam(H, "sendbeam", 'icons/effects/effects.dmi', time = 30, maxdistance = 7, beam_type = /obj/effect/ebeam)
new /obj/effect/temp_visual/cult/sparks(H.loc)
raise_vampire(user, H)
/obj/effect/proc_holder/spell/targeted/raise_vampires/proc/raise_vampire(mob/M, mob/living/carbon/human/H)
if(!istype(M) || !istype(H))
return
if(!H.mind)
visible_message("[H] looks to be too stupid to understand what is going on.")
return
if(H.dna && (NO_BLOOD in H.dna.species.species_traits) || H.dna.species.exotic_blood || !H.blood_volume)
visible_message("[H] looks unfazed!")
return
if(H.mind.vampire || H.mind.special_role == SPECIAL_ROLE_VAMPIRE || H.mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
visible_message("<span class='notice'>[H] looks refreshed!</span>")
H.adjustBruteLoss(-60)
H.adjustFireLoss(-60)
for(var/obj/item/organ/external/E in H.bodyparts)
if(prob(25))
E.mend_fracture()
E.internal_bleeding = FALSE
return
if(H.stat != DEAD)
if(H.IsWeakened())
visible_message("<span class='warning'>[H] looks to be in pain!</span>")
H.adjustBrainLoss(60)
else
visible_message("<span class='warning'>[H] looks to be stunned by the energy!</span>")
H.Weaken(20)
return
for(var/obj/item/implant/mindshield/L in H)
if(L && L.implanted)
qdel(L)
for(var/obj/item/implant/traitor/T in H)
if(T && T.implanted)
qdel(T)
visible_message("<span class='warning'>[H] gets an eerie red glow in their eyes!</span>")
var/datum/objective/protect/protect_objective = new
protect_objective.owner = H.mind
protect_objective.target = M.mind
protect_objective.explanation_text = "Protect [M.real_name]."
H.mind.objectives += protect_objective
add_attack_logs(M, H, "Vampire-sired")
H.mind.make_vampire()
H.revive()
H.Weaken(20)
/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step
name = "Shadow Step (30)"
desc = "Teleport to a nearby dark region"
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
action_icon_state = "shadowblink"
charge_max = 20
required_blood = 30
centcom_cancast = FALSE
vampire_ability = TRUE
include_space = FALSE
range = -1
include_user = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
// Teleport radii
inner_tele_radius = 0
outer_tele_radius = 6
include_light_turfs = FALSE
sound1 = null
sound2 = null
// pure adminbus at the moment
/proc/isvampirethrall(mob/living/M)
return istype(M) && M.mind && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
/obj/effect/proc_holder/spell/targeted/enthrall
name = "Enthrall (150)"
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
gain_desc = "You have gained the ability to thrall people to your will."
action_icon_state = "vampire_enthrall"
required_blood = 150
deduct_blood_on_cast = FALSE
vampire_ability = TRUE
humans_only = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets, mob/user = usr)
var/datum/vampire/vampire = user.mind.vampire
for(var/mob/living/target in targets)
user.visible_message("<span class='warning'>[user] bites [target]'s neck!</span>", "<span class='warning'>You bite [target]'s neck and begin the flow of power.</span>")
to_chat(target, "<span class='warning'>You feel the tendrils of evil invade your mind.</span>")
if(do_mob(user, target, 50))
if(can_enthrall(user, target))
handle_enthrall(user, target)
var/blood_cost_modifier = 1 + vampire.nullified/100
var/blood_cost = round(required_blood * blood_cost_modifier)
vampire.bloodusable -= blood_cost //we take the blood after enthralling, not before
else
revert_cast(user)
to_chat(user, "<span class='warning'>You or your target either moved or you dont have enough usable blood.</span>")
/obj/effect/proc_holder/spell/targeted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
var/enthrall_safe = 0
for(var/obj/item/implant/mindshield/L in C)
if(L && L.implanted)
enthrall_safe = 1
break
for(var/obj/item/implant/traitor/T in C)
if(T && T.implanted)
enthrall_safe = 1
break
if(!C)
log_runtime(EXCEPTION("something bad happened on enthralling a mob, attacker is [user] [user.key] \ref[user]"), user)
return FALSE
if(!C.mind)
to_chat(user, "<span class='warning'>[C.name]'s mind is not there for you to enthrall.</span>")
return FALSE
if(enthrall_safe || (C.mind in SSticker.mode.vampires) || (C.mind.vampire) || (C.mind in SSticker.mode.vampire_enthralled))
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You feel a familiar sensation in your skull that quickly dissipates.</span>")
return FALSE
if(!C.affects_vampire(user))
if(C.mind.isholy)
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>Your faith in [SSticker.Bible_deity_name] has kept your mind clear of all evil.</span>")
else
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You resist the attack on your mind.</span>")
return FALSE
if(!ishuman(C))
to_chat(user, "<span class='warning'>You can only enthrall sentient humanoids!</span>")
return FALSE
return TRUE
/obj/effect/proc_holder/spell/targeted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H)
if(!istype(H))
return 0
var/ref = "\ref[user.mind]"
if(!(ref in SSticker.mode.vampire_thralls))
SSticker.mode.vampire_thralls[ref] = list(H.mind)
else
SSticker.mode.vampire_thralls[ref] += H.mind
SSticker.mode.update_vampire_icons_added(H.mind)
SSticker.mode.update_vampire_icons_added(user.mind)
var/datum/mindslaves/slaved = user.mind.som
if(!slaved)
slaved = new()
slaved.masters = user.mind
H.mind.som = slaved
slaved.serv += H
slaved.add_serv_hud(user.mind, "vampire")//handles master servent icons
slaved.add_serv_hud(H.mind, "vampthrall")
SSticker.mode.vampire_enthralled.Add(H.mind)
SSticker.mode.vampire_enthralled[H.mind] = user.mind
H.mind.special_role = SPECIAL_ROLE_VAMPIRE_THRALL
var/datum/objective/protect/serve_objective = new
serve_objective.owner = user.mind
serve_objective.target = H.mind
serve_objective.explanation_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
H.mind.objectives += serve_objective
to_chat(H, "<span class='biggerdanger'>You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.</span>")
to_chat(user, "<span class='warning'>You have successfully Enthralled [H]. <i>If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.</i></span>")
H.Stun(2)
add_attack_logs(user, H, "Vampire-thralled")
@@ -0,0 +1,70 @@
/datum/vampire_subclass
/// The subclass' name. Used for blackbox logging.
var/name = "yell at coderbus"
/// A list of powers that a vampire unlocks. The value of the list entry is equal to the blood total required for the vampire to unlock it.
var/list/standard_powers
/// A list of the powers a vampire unlocks when it reaches full power.
var/list/fully_powered_abilities
/// Whether or not a vampire heals more based on damage taken.
var/improved_rejuv_healing = FALSE
/datum/vampire_subclass/proc/add_subclass_ability(datum/vampire/vamp)
for(var/thing in standard_powers)
if(vamp.bloodtotal >= standard_powers[thing])
vamp.add_ability(thing)
/datum/vampire_subclass/proc/add_full_power_abilities(datum/vampire/vamp)
for(var/thing in fully_powered_abilities)
vamp.add_ability(thing)
/datum/vampire_subclass/umbrae
name = "umbrae"
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/cloak = 150,
/obj/effect/proc_holder/spell/targeted/click/shadow_snare = 250,
/obj/effect/proc_holder/spell/targeted/click/dark_passage = 400,
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
/datum/vampire_passive/xray)
/datum/vampire_subclass/hemomancer
name = "hemomancer"
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws = 150,
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils = 250,
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool = 400,
/obj/effect/proc_holder/spell/blood_eruption = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/self/vampire/blood_spill)
/datum/vampire_subclass/gargantua
name = "gargantua"
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/blood_swell = 150,
/obj/effect/proc_holder/spell/self/vampire/blood_rush = 250,
/datum/vampire_passive/blood_swell_upgrade = 400,
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/targeted/click/charge)
improved_rejuv_healing = TRUE
/datum/vampire_subclass/ancient
name = "ancient"
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws,
/obj/effect/proc_holder/spell/self/vampire/blood_swell,
/obj/effect/proc_holder/spell/self/vampire/cloak,
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils,
/obj/effect/proc_holder/spell/self/vampire/blood_rush,
/obj/effect/proc_holder/spell/targeted/click/shadow_snare,
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool,
/datum/vampire_passive/blood_swell_upgrade,
/obj/effect/proc_holder/spell/targeted/click/dark_passage,
/obj/effect/proc_holder/spell/blood_eruption,
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force,
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish,
/obj/effect/proc_holder/spell/targeted/raise_vampires,
/obj/effect/proc_holder/spell/targeted/enthrall,
/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/self/vampire/blood_spill,
/obj/effect/proc_holder/spell/targeted/click/charge,
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
/datum/vampire_passive/xray)
improved_rejuv_healing = TRUE
+4
View File
@@ -83,6 +83,10 @@
if(!ishuman(M)) //If target is not a human
return ..()
if(!M.mind)
to_chat(user, "<span class='warning'>This being has no soul!</span>")
return ..()
if(M.has_brain_worms()) //Borer stuff - RR
to_chat(user, "<span class='warning'>This being is corrupted by an alien intelligence and cannot be soul trapped.</span>")
return ..()
+15
View File
@@ -343,6 +343,21 @@
playsound(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
return TRUE
/datum/spellbook_entry/summon/slience_ghosts
name = "Silence Ghosts"
desc = "Tired of people talking behind your back, and spooking you? Why not silence them, and make the dead deader."
cost = 2
log_name = "SLG"
is_ragin_restricted = TRUE //Salt needs to flow here, to be honest
/datum/spellbook_entry/summon/slience_ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
new /datum/event/wizard/ghost_mute()
active = TRUE
to_chat(user, "<span class='notice'>You have silenced all ghosts!</span>")
playsound(get_turf(user), 'sound/effects/ghost.ogg', 50, 1)
message_admins("[key_name_admin(usr)] silenced all ghosts as a wizard! (Deadchat is now DISABLED)")
return TRUE
/datum/spellbook_entry/summon/guns
name = "Summon Guns"
desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. There is a good chance that they will shoot each other first."