Vampire Gamemode

This commit is contained in:
Fluffe9911
2018-08-31 19:44:53 -04:00
parent d310d49857
commit 7b7d5a1da6
28 changed files with 1290 additions and 25 deletions

View File

@@ -6,26 +6,34 @@
//These are synced with the Database, if you change the values of the defines
//then you MUST update the database!
#define ROLE_SYNDICATE "Syndicate"
#define ROLE_TRAITOR "traitor"
#define ROLE_OPERATIVE "operative"
#define ROLE_CHANGELING "changeling"
#define ROLE_WIZARD "wizard"
#define ROLE_MALF "malf AI"
#define ROLE_REV "revolutionary"
#define ROLE_REV_HEAD "Head Revolutionary"
#define ROLE_ALIEN "xenomorph"
#define ROLE_PAI "pAI"
#define ROLE_CULTIST "cultist"
#define ROLE_BLOB "blob"
#define ROLE_NINJA "space ninja"
#define ROLE_MONKEY "monkey"
#define ROLE_ABDUCTOR "abductor"
#define ROLE_REVENANT "revenant"
#define ROLE_DEVIL "devil"
#define ROLE_SERVANT_OF_RATVAR "servant of Ratvar"
#define ROLE_BROTHER "blood brother"
#define ROLE_BRAINWASHED "brainwashed victim"
#define ROLE_SYNDICATE "Syndicate"
#define ROLE_TRAITOR "traitor"
#define ROLE_OPERATIVE "operative"
#define ROLE_CHANGELING "changeling"
#define ROLE_WIZARD "wizard"
#define ROLE_MALF "malf AI"
#define ROLE_REV "revolutionary"
#define ROLE_REV_HEAD "Head Revolutionary"
#define ROLE_ALIEN "xenomorph"
#define ROLE_PAI "pAI"
#define ROLE_CULTIST "cultist"
#define ROLE_BLOB "blob"
#define ROLE_NINJA "space ninja"
#define ROLE_MONKEY "monkey"
#define ROLE_ABDUCTOR "abductor"
#define ROLE_REVENANT "revenant"
#define ROLE_DEVIL "devil"
#define ROLE_SERVANT_OF_RATVAR "servant of Ratvar"
#define ROLE_BROTHER "blood brother"
#define ROLE_VAMPIRE "vampire" // Yogs
#define ROLE_BRAINWASHED "brainwashed victim"
#define ROLE_OVERTHROW "syndicate mutineer"
#define ROLE_SENTIENCE "sentience potion spawn"
#define ROLE_MIND_TRANSFER "mind transfer potion"
#define ROLE_POSIBRAIN "posibrain"
#define ROLE_DRONE "drone"
#define ROLE_DEATHSQUAD "deathsquad"
#define ROLE_LAVALAND "lavaland"
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
@@ -47,7 +55,10 @@ GLOBAL_LIST_INIT(special_roles, list(
ROLE_REVENANT,
ROLE_ABDUCTOR,
ROLE_DEVIL = /datum/game_mode/devil,
ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockwork_cult
ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockwork_cult,
ROLE_VAMPIRE = /datum/game_mode/vampire, // Yogs
ROLE_OVERTHROW = /datum/game_mode/overthrow,
ROLE_SENTIENCE
))
//Job defines for what happens when you fail to qualify for any job during job selection

View File

@@ -0,0 +1 @@
#define ANTAG_DATUM_VAMPIRE /datum/antagonist/vampire

View File

@@ -0,0 +1 @@
#define ANTAG_HUD_VAMPIRE 20

View File

@@ -1,2 +1,3 @@
#define COMSIG_ALT_CLICK_ON "alt_click_on" //from base of mob/AltClickOn: (atom/A)
#define COMSIG_ATOM_POINTED_AT "atom_pointed_at" //from base of atom/pointed_at(): (mob/user)
#define COMSIG_ALT_CLICK_ON "alt_click_on" //from base of mob/AltClickOn(): (atom/A)
#define COMSIG_ATOM_POINTED_AT "atom_pointed_at" //from base of atom/pointed_at(): (mob/user)
#define COMSIG_PROCESS_MOVE "process_move" //from base of client/Move(): (num/direction)

View File

@@ -0,0 +1,3 @@
//pass_flags
#define PASSDOOR (1<<13)

View File

@@ -27,6 +27,7 @@ GLOBAL_LIST_INIT(huds, list(
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_VAMPIRE = new/datum/atom_hud/antag/hidden(), // Yogs
))
/datum/atom_hud

View File

@@ -200,6 +200,8 @@
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.a_intent == INTENT_HARM && handle_vamp_biting(H)) // yogs start -- vampire biting
return // yogs end
dna.species.spec_attack_hand(H, src)
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)

View File

@@ -77,6 +77,8 @@ ALERT_DELTA Destruction of the station is imminent. All crew are instructed to o
PROBABILITY TRAITOR 5
PROBABILITY TRAITORBRO 2
PROBABILITY TRAITORCHAN 4
PROBABILITY TRAITORVAMP 3
PROBABILITY VAMPIRE 3
PROBABILITY INTERNAL_AFFAIRS 3
PROBABILITY NUCLEAR 2
PROBABILITY REVOLUTION 2

View File

@@ -0,0 +1,6 @@
/obj/screen/vampire
icon = 'icons/mob/screen_gen.dmi'
icon_state = "power_display"
name = "usable blood"
screen_loc = ui_lingchemdisplay
invisibility = INVISIBILITY_ABSTRACT

View File

@@ -0,0 +1,350 @@
#define ALL_POWERS_UNLOCKED 800
/datum/antagonist/vampire
name = "Vampire"
antagpanel_category = "Vampire"
roundend_category = "vampires"
job_rank = ROLE_VAMPIRE
var/usable_blood = 0
var/total_blood = 0
var/fullpower = FALSE
var/draining
var/list/objectives_given = list()
var/iscloaking = FALSE
var/list/powers = list() // list of current powers
var/obj/item/clothing/suit/draculacoat/coat
var/list/upgrade_tiers = list(
/obj/effect/proc_holder/spell/self/rejuvenate = 0,
/obj/effect/proc_holder/spell/targeted/hypnotise = 0,
/datum/vampire_passive/vision = 175,
/obj/effect/proc_holder/spell/self/shapeshift = 175,
/obj/effect/proc_holder/spell/self/cloak = 225,
/obj/effect/proc_holder/spell/targeted/disease = 275,
/obj/effect/proc_holder/spell/bats = 350,
/obj/effect/proc_holder/spell/self/batform = 350,
/obj/effect/proc_holder/spell/self/screech = 315,
/datum/vampire_passive/regen = 425,
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/mistform = 500,
/datum/vampire_passive/full = 666,
/obj/effect/proc_holder/spell/self/summon_coat = 666,
/obj/effect/proc_holder/spell/targeted/vampirize = 700,
/obj/effect/proc_holder/spell/self/revive = 800)
/datum/antagonist/vampire/get_admin_commands()
. = ..()
.["Full Power"] = CALLBACK(src,.proc/admin_set_full_power)
.["Set Blood Amount"] = CALLBACK(src,.proc/admin_set_blood)
/datum/antagonist/vampire/proc/admin_set_full_power(mob/admin)
usable_blood = ALL_POWERS_UNLOCKED
total_blood = ALL_POWERS_UNLOCKED
check_vampire_upgrade()
message_admins("[key_name_admin(admin)] made [owner.current] a full power vampire..")
log_admin("[key_name(admin)] made [owner.current] a full power vampire..")
/datum/antagonist/vampire/proc/admin_set_blood(mob/admin)
total_blood = input(admin, "Set Vampire Total Blood", "Total Blood", total_blood) as null|num
usable_blood = min((input(admin, "Set Vampire Usable Blood", "Usable Blood", usable_blood) as null|num), total_blood)
check_vampire_upgrade()
message_admins("[key_name_admin(admin)] set [owner.current]'s total blood to [total_blood], and usable blood to [usable_blood].")
log_admin("[key_name(admin)] set [owner.current]'s total blood to [total_blood], and usable blood to [usable_blood].")
/datum/antagonist/vampire/on_gain()
SSticker.mode.vampires += owner
give_objectives()
check_vampire_upgrade()
owner.special_role = "vampire"
owner.current.faction += "vampire"
SSticker.mode.update_vampire_icons_added(owner)
var/mob/living/carbon/human/C = owner.current
if(istype(C))
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(B)
B.vital = FALSE
B.decoy_override = TRUE
..()
/datum/antagonist/vampire/on_removal()
remove_vampire_powers()
owner.current.faction -= "vampire"
SSticker.mode.vampires -= owner
owner.special_role = null
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
if(owner && H.hud_used && H.hud_used.vamp_blood_display)
H.hud_used.vamp_blood_display.invisibility = INVISIBILITY_ABSTRACT
SSticker.mode.update_vampire_icons_removed(owner)
for(var/O in objectives_given)
owner.objectives -= O
LAZYCLEARLIST(objectives_given)
if(owner.current)
to_chat(owner.current,"<span class='userdanger'>Your powers have been quenched! You are no longer a vampire</span>")
owner.special_role = null
var/mob/living/carbon/human/C = owner.current
if(istype(C))
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(B && (B.decoy_override != initial(B.decoy_override)))
B.vital = TRUE
B.decoy_override = FALSE
..()
/datum/antagonist/vampire/greet()
to_chat(owner, "<span class='userdanger'>You are a Vampire!</span>")
to_chat(owner, "<span class='danger bold'>You are a creature of the night -- holy water, the chapel, and space will cause you to burn.</span>")
to_chat(owner, "<span class='notice bold'>Hit someone in the head with harm intent to start sucking their blood. However, only blood from living creatures is usable!</span>")
to_chat(owner, "<span class='notice bold'>Coffins will heal you.</span>")
if(LAZYLEN(objectives_given))
owner.announce_objectives()
owner.current.playsound_local(get_turf(owner.current), 'yogstation/sound/ambience/antag/vampire.ogg',80,0)
/datum/antagonist/vampire/proc/give_objectives()
var/datum/objective/blood/blood_objective = new
blood_objective.owner = owner
blood_objective.gen_amount_goal()
add_objective(blood_objective)
for(var/i = 1, i < CONFIG_GET(number/traitor_objectives_amount), i++)
forge_single_objective()
if(!(locate(/datum/objective/escape) in owner.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
add_objective(escape_objective)
return
/datum/antagonist/vampire/proc/add_objective(var/datum/objective/O)
owner.objectives += O
objectives_given += O
/datum/antagonist/vampire/proc/forge_single_objective() //Returns how many objectives are added
.=1
if(prob(50))
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = owner
destroy_objective.find_target()
add_objective(destroy_objective)
else if(prob(30))
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = owner
maroon_objective.find_target()
add_objective(maroon_objective)
else
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
else
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
add_objective(steal_objective)
/datum/antagonist/vampire/proc/vamp_burn(var/severe_burn = FALSE)
var/mob/living/L = owner.current
if(!L)
return
var/burn_chance = severe_burn ? 35 : 8
if(prob(burn_chance) && L.health >= 50)
switch(L.health)
if(75 to 100)
L.visible_message("<span class='warning'>[L]'s skin begins to flake!</span>", "<span class='danger'>Your skin flakes away...</span>")
if(50 to 75)
L.visible_message("<span class='warning'>[L]'s skin sizzles loudly!</span>", "<span class='danger'>Your skin sizzles!</span>", "You hear sizzling.")
L.adjustFireLoss(3)
else if(L.health < 50)
if(!L.on_fire)
L.visible_message("<span class='warning'>[L] catches fire!</span>", "<span class='danger'>Your skin catches fire!</span>")
L.emote("scream")
else
L.visible_message("<span class='warning'>[L] continues to burn!</span>", "<span class='danger'>Your continue to burn!</span>")
L.adjust_fire_stacks(5)
L.IgniteMob()
return
/datum/antagonist/vampire/proc/check_sun()
var/mob/living/carbon/C = owner.current
if(!C)
return
var/ax = C.x
var/ay = C.y
for(var/i = 1 to 20)
ax += SSsun.dx
ay += SSsun.dy
var/turf/T = locate(round(ax, 0.5), round(ay, 0.5), C.z)
if(T.x == 1 || T.x == world.maxx || T.y == 1 || T.y == world.maxy)
break
if(T.density)
return
vamp_burn(TRUE)
/datum/antagonist/vampire/proc/vampire_life()
var/mob/living/carbon/C = owner.current
if(!C)
return
if(owner && C.hud_used && C.hud_used.vamp_blood_display)
C.hud_used.vamp_blood_display.invisibility = FALSE
C.hud_used.vamp_blood_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#dd66dd'>[round(usable_blood, 1)]</font></div>"
handle_vampire_cloak()
if(istype(C.loc, /obj/structure/closet/crate/coffin))
C.adjustBruteLoss(-4)
C.adjustFireLoss(-4)
C.adjustToxLoss(-4)
C.adjustOxyLoss(-4)
return
if(!get_ability(/datum/vampire_passive/full) && istype(get_area(C.loc), /area/chapel))
vamp_burn()
if(isspaceturf(C.loc))
check_sun()
/datum/antagonist/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H)
draining = H
var/mob/living/carbon/human/O = owner.current
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
log_attack("[O] ([O.ckey]) bit [H] ([H.ckey]) in the neck")
O.visible_message("<span class='danger'>[O] grabs [H]'s neck harshly and sinks in their fangs!</span>", "<span class='danger'>You sink your fangs into [H] and begin to drain their blood.</span>", "<span class='notice'>You hear a soft puncture and a wet sucking noise.</span>")
if(!iscarbon(owner))
H.LAssailant = null
else
H.LAssailant = O
playsound(O.loc, 'sound/weapons/bite.ogg', 50, 1)
while(do_mob(O, H, 50))
if(!is_vampire(O))
to_chat(O, "<span class='warning'>Your fangs have disappeared!</span>")
return
old_bloodtotal = total_blood
old_bloodusable = usable_blood
if(!H.blood_volume)
to_chat(O, "<span class='warning'>They've got no blood left to give.</span>")
break
if(H.stat != DEAD)
blood = min(20, H.blood_volume)// if they have less than 20 blood, give them the remnant else they get 20 blood
total_blood += blood / 2 //divide by 2 to counted the double suction since removing cloneloss -Melandor0
usable_blood += blood / 2
else
blood = min(5, H.blood_volume) // The dead only give 5 blood
total_blood += blood
check_vampire_upgrade()
if(old_bloodtotal != total_blood)
to_chat(O, "<span class='notice'><b>You have accumulated [total_blood] [total_blood > 1 ? "units" : "unit"] of blood[usable_blood != old_bloodusable ? ", and have [usable_blood] left to use" : ""].</b></span>")
H.blood_volume = max(H.blood_volume - 25, 0)
if(ishuman(O))
O.nutrition = min(O.nutrition + (blood / 2), NUTRITION_LEVEL_WELL_FED)
playsound(O.loc, 'sound/items/eatfood.ogg', 40, 1)
draining = null
to_chat(owner, "<span class='notice'>You stop draining [H.name] of blood.</span>")
/datum/antagonist/vampire/proc/force_add_ability(path)
var/spell = new path(owner)
if(istype(spell, /obj/effect/proc_holder/spell))
owner.AddSpell(spell)
powers += spell
/datum/antagonist/vampire/proc/get_ability(path)
for(var/P in powers)
var/datum/power = P
if(power.type == path)
return power
return null
/datum/antagonist/vampire/proc/add_ability(path)
if(!get_ability(path))
force_add_ability(path)
/datum/antagonist/vampire/proc/remove_ability(ability)
if(ability && (ability in powers))
powers -= ability
owner.spell_list.Remove(ability)
qdel(ability)
/datum/antagonist/vampire/proc/remove_vampire_powers()
for(var/P in powers)
remove_ability(P)
owner.current.alpha = 255
/datum/antagonist/vampire/proc/check_vampire_upgrade(var/announce = TRUE)
var/list/old_powers = powers.Copy()
for(var/ptype in upgrade_tiers)
var/level = upgrade_tiers[ptype]
if(total_blood >= level)
add_ability(ptype)
if(announce)
announce_new_power(old_powers)
owner.current.update_sight() //deal with sight abilities
/datum/antagonist/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))
var/obj/effect/proc_holder/spell/power = p
to_chat(owner.current, "<span class='notice'>[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>")
/datum/antagonist/vampire/proc/handle_vampire_cloak()
if(!ishuman(owner.current))
owner.current.alpha = 255
return
var/mob/living/carbon/human/H = owner.current
var/turf/T = get_turf(H)
var/light_available = T.get_lumcount()
if(!istype(T))
return 0
if(!iscloaking)
H.alpha = 255
return 0
if(light_available <= 0.25)
H.alpha = round((255 * 0.15))
return 1
else
H.alpha = round((255 * 0.80))
/datum/antagonist/vampire/roundend_report()
var/list/result = list()
var/vampwin = TRUE
result += printplayer(owner)
var/objectives_text = ""
if(objectives_given.len)//If the vampire had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in objectives_given)
if(objective.check_completion())
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
vampwin = FALSE
count++
result += objectives_text
if(vampwin)
result += "<span class='greentext'>The vampire was successful!</span>"
else
result += "<span class='redtext'>The vampire has failed!</span>"
SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
return result.Join("<br>")
#undef ALL_POWERS_UNLOCKED

View File

@@ -1,2 +1,49 @@
/datum/mind
var/quiet_round = FALSE //Won't be picked as target in most cases
var/quiet_round = FALSE //Won't be picked as target in most cases
/datum/mind/proc/vampire_hook()
var/text = "vampire"
if(SSticker.mode.config_tag == "vampire")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(is_vampire(current))
text += "<b>VAMPIRE</b> | <a href='?src=\ref[src];vampire=clear'>human</a> | <a href='?src=\ref[src];vampire=full'>full-power</a>"
else
text += "<a href='?src=\ref[src];vampire=vampire'>vampire</a> | <b>HUMAN</b> | <a href='?src=\ref[src];vampire=full'>full-power</a>"
if(current && current.client && (ROLE_VAMPIRE in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
return text
/datum/mind/proc/vampire_href(href, mob/M)
switch(href)
if("clear")
remove_vampire(current)
message_admins("[key_name_admin(usr)] has de-vampired [current].")
log_admin("[key_name(usr)] has de-vampired [current].")
if("vampire")
if(!is_vampire(current))
message_admins("[key_name_admin(usr)] has vampired [current].")
log_admin("[key_name(usr)] has vampired [current].")
add_vampire(current)
else
to_chat(usr, "<span class='warning'>[current] is already a vampire!</span>")
if("full")
message_admins("[key_name_admin(usr)] has full-vampired [current].")
log_admin("[key_name(usr)] has full-vampired [current].")
if(!is_vampire(current))
add_vampire(current)
var/datum/antagonist/vampire/V = has_antag_datum(ANTAG_DATUM_VAMPIRE)
if(V)
V.total_blood = 1500
V.usable_blood = 1500
V.check_vampire_upgrade()
else
var/datum/antagonist/vampire/V = has_antag_datum(ANTAG_DATUM_VAMPIRE)
if(V)
V.total_blood = 1500
V.usable_blood = 1500
V.check_vampire_upgrade()

View File

@@ -0,0 +1,31 @@
/datum/disease/vampire
name = "Grave Fever"
max_stages = 3
stage_prob = 5
spread_text = "Non-Contagious"
spread_flags = DISEASE_SPREAD_SPECIAL
cure_text = "Antibiotics"
cures = list("spaceacillin")
agent = "Grave Dust"
cure_chance = 20
viable_mobtypes = list(/mob/living/carbon/human)
severity = DISEASE_SEVERITY_DANGEROUS
disease_flags = CURABLE
/datum/disease/vampire/stage_act()
..()
var/toxdamage = stage * 2
var/stuntime = (stage * 2) * 10
if(prob(10))
affected_mob.emote(pick("cough","groan", "gasp"))
if(prob(15))
if(prob(33))
to_chat(affected_mob, "<span class='danger'>You feel sickly and weak.</span>")
affected_mob.adjustToxLoss(toxdamage)
if(prob(5))
to_chat(affected_mob, "<span class='danger'>Your joints ache horribly!</span>")
affected_mob.Knockdown(stuntime)
affected_mob.Stun(stuntime)

View File

@@ -0,0 +1,80 @@
/datum/game_mode/traitor/vampire
name = "traitor+vampire"
config_tag = "traitorvamp"
false_report_weight = 10
traitors_possible = 3 //hard limit on traitors if scaling is turned off
restricted_jobs = list("AI", "Cyborg")
required_players = 25
required_enemies = 1 // how many of each type are required
recommended_enemies = 3
reroll_friendly = 1
var/list/possible_vampires = list()
var/const/vampire_amt = 2 //hard limit on vampires if scaling is turned off
var/list/pre_vamps = list()
/datum/game_mode/traitor/vampire/announce()
to_chat(world, "<B>The current game mode is - Traitor+Vampire!</B>")
to_chat(world, "<B>There are vampires 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/can_start()
if(!..())
return 0
possible_vampires = get_players_for_role(ROLE_VAMPIRE)
if(possible_vampires.len < required_enemies)
return 0
return 1
/datum/game_mode/traitor/vampire/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_vamps = get_players_for_role(ROLE_VAMPIRE)
var/num_vamp = 1
if(CONFIG_GET(number/traitor_scaling_coeff))
num_vamp = max(1, min( round(num_players()/(CONFIG_GET(number/traitor_scaling_coeff)*4))+2, round(num_players()/(CONFIG_GET(number/traitor_scaling_coeff)*2)) ))
else
num_vamp = max(1, min(num_players(), vampire_amt/2))
var/list/old_antag_candidates = antag_candidates.Copy()
if(possible_vamps.len>0)
for(var/j = 0, j < num_vamp, j++)
if(!possible_vamps.len) break
var/datum/mind/vamp = pick(possible_vamps)
pre_vamps += vamp
possible_vamps -= vamp
antag_candidates -= vamp
vamp.special_role = "Vampire"
vamp.restricted_roles = restricted_jobs
antag_candidates = old_antag_candidates // So we still have a chance for a traitor vampire.
return ..()
else
return FALSE
/datum/game_mode/traitor/vampire/post_setup()
for(var/datum/mind/vamp in pre_vamps)
vamp.add_antag_datum(/datum/antagonist/vampire)
..()
return
/datum/game_mode/traitor/vampire/make_antag_chance(mob/living/carbon/human/character) //Assigns vampire to latejoiners
var/vampcap = min( round(GLOB.joined_player_list.len/(CONFIG_GET(number/traitor_scaling_coeff)*4))+2, round(GLOB.joined_player_list.len/(CONFIG_GET(number/traitor_scaling_coeff)*2)) )
if(SSticker.mode.vampires.len >= vampcap) //Caps number of latejoin antagonists
..()
return
if(SSticker.mode.vampires.len <= (vampcap - 2) || prob(100 / (CONFIG_GET(number/traitor_scaling_coeff) * 4)))
if(ROLE_VAMPIRE in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_VAMPIRE) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
add_vampire(character)
..()
/datum/game_mode/traitor/vampire/generate_report()
return "We have received some fuzzy reports about the Syndicate cooperating with a bluespace demon.\
Keep a watch out for syndicate agents, and have your Chaplain on standby."

View File

@@ -0,0 +1,142 @@
/datum/game_mode
var/list/datum/mind/vampires = list()
/mob/living/carbon/human/Stat()
. = ..()
var/datum/antagonist/vampire/vamp = mind.has_antag_datum(/datum/antagonist/vampire)
if(vamp && statpanel("Status"))
stat("Total Blood", vamp.total_blood)
stat("Usable Blood", vamp.usable_blood)
/mob/living/carbon/human/Life()
. = ..()
if(is_vampire(src))
var/datum/antagonist/vampire/vamp = mind.has_antag_datum(/datum/antagonist/vampire)
vamp.vampire_life()
/datum/game_mode/vampire
name = "vampire"
config_tag = "vampire"
antag_flag = ROLE_VAMPIRE
false_report_weight = 1
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Head of Security", "Captain", "Security Officer", "Chaplain", "Detective", "Warden", "Head of Personnel")
required_players = 15
required_enemies = 1
recommended_enemies = 3
enemy_minimum_age = 0
announce_text = "There are vampires onboard the station!\n\
+ <span class='danger'>Vampires</span>: Suck the blood of the crew and complete your objectives!\n\
+ <span class='notice'>Crew</span>: Kill the unholy vampires!"
var/vampires_possible = 4 //hard limit on vampires if scaling is turned off
var/num_modifier = 0
var/list/datum/mind/pre_vamps = list()
/datum/game_mode/vampire/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_vamps = 1
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
if(tsc)
num_vamps = max(1, min(round(num_players() / (tsc * 2)) + 2 + num_modifier, round(num_players() / tsc) + num_modifier))
else
num_vamps = max(1, min(num_players(), vampires_possible))
for(var/j = 0, j < num_vamps, j++)
if (!antag_candidates.len)
break
var/datum/mind/vamp = pick(antag_candidates)
pre_vamps += vamp
vamp.special_role = "Vampire"
vamp.restricted_roles = restricted_jobs
log_game("[vamp.key] (ckey) has been selected as a Vampire")
antag_candidates.Remove(vamp)
return pre_vamps.len > 0
/datum/game_mode/vampire/post_setup()
for(var/datum/mind/vamp in pre_vamps)
vamp.add_antag_datum(/datum/antagonist/vampire)
..()
return TRUE
/datum/game_mode/proc/auto_declare_completion_vampire()
if(vampires.len)
var/text = "<br><font size=3><b>The vampires were:</b></font>"
for(var/datum/mind/vamp in vampires)
var/vampwin = 1
if(!vamp.current)
vampwin = 0
var/datum/antagonist/vampire/V = vamp.has_antag_datum(/datum/antagonist/vampire)
if(!V)
continue
text += printplayer(vamp)
//Removed sanity if(vampire) because we -want- a runtime to inform us that the vampire list is incorrect and needs to be fixed.
text += "<br><b>Usable Blood:</b> [V.usable_blood]."
text += "<br><b>Total Blood:</b> [V.total_blood]"
if(vamp.objectives.len)
var/count = 1
for(var/datum/objective/objective in vamp.objectives)
if(objective.check_completion())
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <font color='green'><b>Success!</b></font>"
SSblackbox.record_feedback("tally", "vampire_objective", 1, "[objective.type]|SUCCESS")
else
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='danger'>Fail.</span>"
SSblackbox.record_feedback("tally", "vampire_objective", 1, "[objective.type]|FAIL")
vampwin = 0
count++
if(vampwin)
text += "<br><font color='green'><b>The vampire was successful!</b></font>"
SSblackbox.record_feedback("tally", "vampire_success", 1, "SUCCESS")
else
text += "<br><span class='boldannounce'>The vampire has failed.</span>"
SSblackbox.record_feedback("tally", "vampire_success", 1, "FAIL")
text += "<br>"
to_chat(world, text)
return 1
/proc/add_vampire(mob/living/L)
if(!L || !L.mind || is_vampire(L))
return FALSE
var/datum/antagonist/vampire/vamp = L.mind.add_antag_datum(/datum/antagonist/vampire)
return vamp
/proc/remove_vampire(mob/living/L)
if(!L || !L.mind || !is_vampire(L))
return FALSE
var/datum/antagonist/vamp = L.mind.has_antag_datum(/datum/antagonist/vampire)
vamp.on_removal()
return TRUE
/proc/is_vampire(mob/living/M)
return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/vampire)
/datum/game_mode/proc/update_vampire_icons_added(datum/mind/traitor_mind)
var/datum/atom_hud/antag/vamphud = GLOB.huds[ANTAG_HUD_VAMPIRE]
vamphud.join_hud(traitor_mind.current)
set_antag_hud(traitor_mind.current, "vampire")
/datum/game_mode/proc/update_vampire_icons_removed(datum/mind/traitor_mind)
var/datum/atom_hud/antag/vamphud = GLOB.huds[ANTAG_HUD_VAMPIRE]
vamphud.leave_hud(traitor_mind.current)
set_antag_hud(traitor_mind.current, null)

View File

@@ -0,0 +1,52 @@
/mob/living/simple_animal/hostile/vampire_bat
name = "vampire bat"
desc = "A bat that sucks blood. Keep away from medical bays."
icon_state = "bat"
icon_living = "bat"
icon_dead = "bat_dead"
icon_gib = "bat_dead"
turns_per_move = 1
response_help = "brushes aside"
response_disarm = "flails at"
response_harm = "hits"
speak_chance = 0
maxHealth = 20
health = 20
see_in_dark = 10
harm_intent_damage = 7
melee_damage_lower = 5
melee_damage_upper = 7
attacktext = "bites"
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
pass_flags = PASSTABLE
faction = list("hostile", "vampire")
attack_sound = 'sound/weapons/bite.ogg'
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
movement_type = FLYING
speak_emote = list("squeaks")
var/max_co2 = 0 //to be removed once metastation map no longer use those for Sgt Araneus
var/min_oxy = 0
var/max_tox = 0
var/mob/living/controller
//Space bats need no air to fly in.
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)
minbodytemp = 0
/mob/living/simple_animal/hostile/vampire_bat/CanAttack(atom/the_target)
. = ..()
if(isliving(the_target) && is_vampire(the_target))
return FALSE
/mob/living/simple_animal/hostile/vampire_bat/death()
if(isliving(controller))
controller.forceMove(loc)
mind.transfer_to(controller)
controller.Knockdown(120)
to_chat(controller, "<span class='userdanger'>The force of being exiled from your bat form knocks you down!</span>")
. = ..()

View File

@@ -0,0 +1,20 @@
/mob/living/carbon/human/proc/handle_vamp_biting(var/mob/living/carbon/human/M)
if(!is_vampire(M) || M == src || M.zone_selected != "head")
return FALSE
var/datum/antagonist/vampire/V = M.mind.has_antag_datum(/datum/antagonist/vampire)
if((NOBLOOD in dna.species.species_traits) || dna.species.exotic_blood || !blood_volume)
to_chat(M, "<span class='warning'>They have no blood!</span>")
return FALSE
if(is_vampire(src))
to_chat(M, "<span class='warning'>Your fangs fail to pierce [name]'s cold flesh</span>")
return FALSE
if(dna.species.name == "skeleton")
to_chat(M, "<span class='warning'>There is no blood in a skeleton!</span>")
return FALSE
if(!ckey)
to_chat(M, "<span class='warning'>[src]'s blood is stale and useless.</span>")
return FALSE
if(V.draining)
return FALSE
V.handle_bloodsucking(src)
return TRUE

View File

@@ -0,0 +1,15 @@
/datum/hud
var/obj/screen/vampire/vamp_blood_display
/datum/hud/New(mob/owner, ui_style = 'icons/mob/screen_midnight.dmi')
. = ..()
vamp_blood_display = new /obj/screen/vampire()
/datum/hud/human/New(mob/living/carbon/human/owner, ui_style = 'icons/mob/screen_midnight.dmi')
. = ..()
vamp_blood_display = new /obj/screen/vampire()
infodisplay += vamp_blood_display
/datum/hud/Destroy()
. = ..()
vamp_blood_display = null

View File

@@ -0,0 +1,13 @@
/datum/objective/blood/proc/gen_amount_goal(lowbound = 450, highbound = 700)
target_amount = rand (lowbound,highbound)
explanation_text = "Extract [target_amount] units of blood."
return target_amount
/datum/objective/blood/check_completion()
if(!owner)
return FALSE
var/datum/antagonist/vampire/vamp = owner.has_antag_datum(/datum/antagonist/vampire)
if(vamp && target_amount <= vamp.total_blood)
return TRUE
else
return FALSE

View File

@@ -0,0 +1,31 @@
/*
In this file:
various vampire interactions and items
*/
/obj/item/clothing/suit/draculacoat
name = "Vampire Coat"
desc = "What is a man? A miserable little pile of secrets."
alternate_worn_icon = 'yogstation/icons/mob/suit.dmi'
icon = 'yogstation/icons/obj/clothing/suits.dmi'
icon_state = "draculacoat"
item_state = "draculacoat"
body_parts_covered = CHEST|GROIN|LEGS|ARMS
flags_inv = HIDEJUMPSUIT
armor = list("melee" = 30, "bullet" = 20, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0)
/mob/living/carbon/human/handle_fire()
. = ..()
if(mind)
var/datum/antagonist/vampire/L = mind.has_antag_datum(/datum/antagonist/vampire)
if(on_fire && stat == DEAD && L && !L.get_ability(/datum/vampire_passive/full))
dust()
/obj/item/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE)
. = ..()
if(!(user.mind && user.mind.isholy) && is_vampire(user))
to_chat(user, "<span class='danger'>[deity_name] channels through \the [src] and sets you ablaze for your blasphemy!</span>")
user.fire_stacks += 5
user.IgniteMob()
user.emote("scream", 1)

View File

@@ -0,0 +1,403 @@
/obj/effect/proc_holder/spell
var/gain_desc
var/blood_used = 0
var/vamp_req = FALSE
/obj/effect/proc_holder/spell/cast_check(skipcharge = 0, mob/user = usr)
. = ..(skipcharge, user)
if(vamp_req)
if(!is_vampire(user))
return FALSE
var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
if(!V)
return FALSE
if(V.usable_blood < blood_used)
to_chat(user, "<span class='warning'>You do not have enough blood to cast this!</span>")
return FALSE
/obj/effect/proc_holder/spell/Initialize()
. = ..()
if(vamp_req)
clothes_req = FALSE
range = 1
human_req = FALSE //so we can cast stuff while a bat, too
/obj/effect/proc_holder/spell/before_cast(list/targets)
. = ..()
if(vamp_req)
// sanity check before we cast
if(!is_vampire(usr))
targets.Cut()
return
if(!blood_used)
return
// enforce blood
var/datum/antagonist/vampire/vampire = usr.mind.has_antag_datum(/datum/antagonist/vampire)
if(blood_used <= vampire.usable_blood)
vampire.usable_blood -= blood_used
else
// stop!!
targets.Cut()
if(LAZYLEN(targets))
to_chat(usr, "<span class='notice'><b>You have [vampire.usable_blood] left to use.</b></span>")
/obj/effect/proc_holder/spell/can_target(mob/living/target)
. = ..()
if(vamp_req && is_vampire(target))
return FALSE
/datum/vampire_passive
var/gain_desc
/datum/vampire_passive/New()
..()
if(!gain_desc)
gain_desc = "You have gained \the [src] ability."
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/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/self/rejuvenate
name = "Rejuvenate"
desc= "Flush your system with spare blood to remove any incapacitating effects."
action_icon_state = "rejuv"
charge_max = 200
stat_allowed = 1
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
vamp_req = TRUE
/obj/effect/proc_holder/spell/self/rejuvenate/cast(list/targets, mob/user = usr)
var/mob/living/carbon/U = user
U.stuttering = 0
var/datum/antagonist/vampire/V = U.mind.has_antag_datum(/datum/antagonist/vampire)
if(!V) //sanity check
return
for(var/i = 1 to 5)
U.adjustStaminaLoss(-10)
if(V.get_ability(/datum/vampire_passive/regen))
U.adjustBruteLoss(-1)
U.adjustOxyLoss(-2.5)
U.adjustToxLoss(-1)
U.adjustFireLoss(-1)
sleep(7.5)
/obj/effect/proc_holder/spell/targeted/hypnotise
name = "Hypnotize (20)"
desc= "A piercing stare that incapacitates your victim for a good length of time."
action_icon_state = "hypnotize"
blood_used = 20
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
vamp_req = TRUE
/obj/effect/proc_holder/spell/targeted/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 he stares into [target]'s eyes</span>")
if(do_mob(user, target, 50))
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.Knockdown(150)
target.Stun(150)
target.stuttering = 10
else
revert_cast(usr)
to_chat(usr, "<span class='warning'>You broke your gaze.</span>")
/obj/effect/proc_holder/spell/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"
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
blood_used = 50
vamp_req = TRUE
/obj/effect/proc_holder/spell/self/shapeshift/cast(list/targets, mob/user = usr)
if(ishuman(user))
var/mob/living/carbon/human/H = user
user.visible_message("<span class='warning'>[H] transforms!</span>")
randomize_human(H)
user.regenerate_icons()
/obj/effect/proc_holder/spell/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 = "cloak"
charge_max = 10
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
vamp_req = TRUE
/obj/effect/proc_holder/spell/self/cloak/Initialize()
. = ..()
update_name()
/obj/effect/proc_holder/spell/self/cloak/proc/update_name()
var/mob/living/user = loc
if(!ishuman(user) || !is_vampire(user))
return
var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
name = "[initial(name)] ([V.iscloaking ? "Deactivate" : "Activate"])"
/obj/effect/proc_holder/spell/self/cloak/cast(list/targets, mob/user = usr)
var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
if(!V)
return
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/targeted/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 = "disease"
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
blood_used = 100
vamp_req = TRUE
/obj/effect/proc_holder/spell/targeted/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(is_vampire(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/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 = "reeee"
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
blood_used = 30
vamp_req = TRUE
/obj/effect/proc_holder/spell/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 || (ishuman(C) && C.get_ear_protection()) || is_vampire(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.Knockdown(4)
C.adjustEarDamage(0, 30)
C.stuttering = 250
C.Stun(4)
C.Jitter(150)
for(var/obj/structure/window/W in view(4))
W.take_damage(75)
playsound(user.loc, 'sound/effects/screech.ogg', 100, 1)
/obj/effect/proc_holder/spell/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 = "bats"
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
charge_max = 1200
vamp_req = TRUE
blood_used = 75
var/num_bats = 2
/obj/effect/proc_holder/spell/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/bats/cast(list/targets, mob/user = usr)
for(var/T in targets)
new /mob/living/simple_animal/hostile/vampire_bat(T)
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/mistform
name = "Mist Form (30)"
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."
blood_used = 30
action_background_icon_state = "bg_demon"
vamp_req = TRUE
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/mistform/Initialize()
. = ..()
range = -1
/obj/effect/proc_holder/spell/targeted/vampirize
name = "Lilith's Pact (500)"
desc = "You drain a victim's blood, and fill them with new blood, blessed by Lilith, turning them into a new vampire."
gain_desc = "You have gained the ability to force someone, given time, to become a vampire."
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
action_icon_state = "oath"
blood_used = 500
vamp_req = TRUE
/obj/effect/proc_holder/spell/targeted/vampirize/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/target in targets)
if(is_vampire(target))
to_chat(user, "<span class='warning'>They're already a vampire!</span>")
continue
target.visible_message("<span class='warning'>[user] latches onto [target]'s neck, and a pure dread eminates from them.</span>", "<span class='warning'>You latch onto [target]'s neck, preparing to transfer your unholy blood to them.</span>", "<span class='warning'>A dreadful feeling overcomes you</span>")
target.reagents.add_reagent("salbutamol", 10) //incase you're choking the victim
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
to_chat(target, "<span class='warning'>Visions of dread flood your vision...</span>")
to_chat(user, "<span class='notice'>We begin to drain [target]'s blood in, so Lilith can bless it.</span>")
if(2)
to_chat(target, "<span class='danger'>Demonic whispers fill your mind, and they become irressistible...</span>")
if(3)
to_chat(target, "<span class='danger'>The world blanks out, and you see a demo- no ange- demon- lil- glory- blessing... Lilith.</span>")
to_chat(user, "<span class='notice'>Excitement builds up in you as [target] sees the blessing of Lilith.</span>")
if(!do_mob(user, target, 70))
to_chat(user, "<span class='danger'>The pact has failed! [target] has not became a vampire.</span>")
to_chat(target, "<span class='notice'>The visions stop, and you relax.</span>")
return
if(!QDELETED(user) && !QDELETED(target))
to_chat(user, "<span class='notice'>. . .</span>")
to_chat(target, "<span class='italics'>Come to me, child.</span>")
sleep(10)
to_chat(target, "<span class='italics'>The world hasn't treated you well, has it?</span>")
sleep(15)
to_chat(target, "<span class='italics'>Strike fear into their hearts...</span>")
to_chat(user, "<span class='notice italics bold'>They have signed the pact!</span>")
to_chat(target, "<span class='userdanger'>You sign Lilith's Pact.</span>")
target.mind.store_memory("<B>[user] showed you the glory of Lilith. <I>You are not required to respect or obey [user] in any way</I></B>")
add_vampire(target)
/obj/effect/proc_holder/spell/self/revive
name = "Revive"
gain_desc = "You have gained the ability to revive after death... However you can still be cremated/gibbed, and you will disintergrate if you're in the chapel!"
desc = "Revives you, provided you are not in the chapel!"
blood_used = 0
stat_allowed = TRUE
charge_max = 1000
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_icon_state = "coffin"
action_background_icon_state = "bg_demon"
vamp_req = TRUE
/obj/effect/proc_holder/spell/self/revive/cast(list/targets, mob/user = usr)
if(!is_vampire(user) || !isliving(user))
revert_cast()
return
if(user.stat != DEAD)
to_chat(user, "<span class='notice'>We aren't dead enough to do that yet!</span>")
revert_cast()
return
if(user.reagents.has_reagent("holywater"))
to_chat(user, "<span class='danger'>We cannot revive, holy water is in our system!</span>")
return
var/mob/living/L = user
if(istype(get_area(L.loc), /area/chapel))
L.visible_message("<span class='warning'>[L] disintergrates into dust!</span>", "<span class='userdanger'>Holy energy seeps into our very being, disintergrating us instantly!</span>", "You hear sizzling.")
new /obj/effect/decal/remains/human(L.loc)
L.dust()
to_chat(L, "<span class='notice'>We begin to reanimate... this will take a minute.</span>")
addtimer(CALLBACK(src, .proc/revive, L), 600)
/obj/effect/proc_holder/spell/self/revive/proc/revive(mob/living/user)
if(user.reagents.has_reagent("holywater"))
to_chat(user, "<span class='danger'>We cannot revive, holy water is in our system!</span>")
return
user.revive()
user.visible_message("<span class='warning'>[user] reanimates from death!</span>", "<span class='notice'>We get back up.</span>")
user.fully_heal(TRUE)
/obj/effect/proc_holder/spell/self/summon_coat
name = "Summon Dracula Coat (5)"
gain_desc = "Now that you have reached full power, you can now pull a vampiric coat out of thin air!"
blood_used = 5
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_icon_state = "coat"
action_background_icon_state = "bg_demon"
vamp_req = TRUE
/obj/effect/proc_holder/spell/self/summon_coat/cast(list/targets, mob/user = usr)
if(!is_vampire(user) || !isliving(user))
revert_cast()
return
var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
if(!V)
return
if(QDELETED(V.coat) || !V.coat)
V.coat = new /obj/item/clothing/suit/draculacoat(user.loc)
else if(get_dist(V.coat, user) > 1 || !(V.coat in user.GetAllContents()))
V.coat.forceMove(user.loc)
user.put_in_hands(V.coat)
to_chat(user, "<span class='notice'>You summon your dracula coat.</span>")
/obj/effect/proc_holder/spell/self/batform
name = "Bat Form (15)"
gain_desc = "You now have the Bat Form ability, which allows you to turn into a bat (and back!)"
desc = "Transform into a bat!"
action_icon_state = "bat"
charge_max = 200
blood_used = 0 //this is only 0 so we can do our own custom checks
action_icon = 'yogstation/icons/mob/vampire.dmi'
action_background_icon_state = "bg_demon"
vamp_req = TRUE
var/mob/living/simple_animal/hostile/vampire_bat/bat
/obj/effect/proc_holder/spell/self/batform/cast(list/targets, mob/user = usr)
var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
if(!V)
return FALSE
if(!bat)
if(V.usable_blood < 15)
to_chat(user, "<span class='warning'>You do not have enough blood to cast this!</span>")
return FALSE
bat = new /mob/living/simple_animal/hostile/vampire_bat(user.loc)
user.forceMove(bat)
bat.controller = user
user.status_flags |= GODMODE
user.mind.transfer_to(bat)
charge_counter = charge_max //so you don't need to wait 20 seconds to turn BACK.
recharging = FALSE
action.UpdateButtonIcon()
else
bat.controller.forceMove(bat.loc)
bat.controller.status_flags &= ~GODMODE
bat.mind.transfer_to(bat.controller)
bat.controller = null //just so we don't accidently trigger the death() thing
qdel(bat)

View File

@@ -0,0 +1,7 @@
/datum/admins/proc/hippie_makeVampire(datum/admins/sr)
if(sr.makeVampire())
message_admins("[key_name(usr)] created a vampire.")
log_admin("[key_name(usr)] created a vampire.")
else
message_admins("[key_name_admin(usr)] tried to create a vampire. Unfortunately, there were no candidates available.")
log_admin("[key_name(usr)] failed to create a vampire.")

View File

@@ -0,0 +1,19 @@
/datum/admins/proc/makeVampire()
var/datum/game_mode/vampire/temp = new
if(CONFIG_GET(flag/protect_roles_from_antagonist))
temp.restricted_jobs += temp.protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
temp.restricted_jobs += "Assistant"
var/list/mob/living/carbon/human/candidates = list()
var/mob/living/carbon/human/H
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
if((ROLE_VAMPIRE in applicant.client.prefs.be_special) && !applicant.stat && applicant.mind && !applicant.mind.special_role)
if(!jobban_isbanned(applicant, "vampire") && !jobban_isbanned(applicant, "Syndicate"))
if(temp.age_check(applicant.client) && !(applicant.job in temp.restricted_jobs) && !is_vampire(applicant))
candidates += applicant
if(LAZYLEN(candidates))
H = pick(candidates)
add_vampire(H)
return TRUE
return FALSE

View File

@@ -1,2 +1,12 @@
/atom/proc/pointed_at(var/mob/user)
SEND_SIGNAL(src, COMSIG_ATOM_POINTED_AT, user)
SEND_SIGNAL(src, COMSIG_ATOM_POINTED_AT, user) //why the hell is this here?
/mob
var/client/oobe_client //when someone aghosts/uses a scrying orb, this holds the client while it's somewhere else
/atom/prepare_huds()
hud_list = list()
for(var/hud in hud_possible)
var/image/I = image('yogstation/icons/mob/hud.dmi', src, "")
I.appearance_flags = RESET_COLOR|RESET_TRANSFORM
hud_list[hud] = I

View File

@@ -0,0 +1,17 @@
/datum/reagent/holywater/on_mob_life(mob/living/M)
. = ..()
if(ishuman(M) && is_vampire(M) && prob(80))
var/datum/antagonist/vampire/V = M.mind.has_antag_datum(ANTAG_DATUM_VAMPIRE)
if(!V.get_ability(/datum/vampire_passive/full))
switch(current_cycle)
if(1 to 4)
to_chat(M, "<span class='warning'>Something sizzles in your veins!</span>")
M.adjustFireLoss(0.5)
if(5 to 12)
to_chat(M, "<span class='danger'>You feel an intense burning inside of you!</span>")
M.adjustFireLoss(1)
if(13 to INFINITY)
M.visible_message("<span class='danger'>[M] suddenly bursts into flames!<span>", "<span class='userdanger'>You suddenly ignite in a holy fire!</span>")
M.adjust_fire_stacks(3)
M.IgniteMob() //Only problem with igniting people is currently the commonly availible fire suits make you immune to being on fire
M.adjustFireLoss(3) //Hence the other damages... ain't I a bastard?

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB