//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
/datum/game_mode/vampire
name = "vampire"
config_tag = "vampire"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Blueshield", "Nanotrasen Representative", "Security Pod Pilot", "Magistrate", "Chaplain", "Brig Physician", "Internal Affairs Agent", "Nanotrasen Navy Officer", "Special Operations Officer")
protected_species = list("Machine")
required_players = 15
required_enemies = 1
recommended_enemies = 4
var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time
var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target
var/const/prob_int_item = 50 // intercept names the theft target half the time
var/const/prob_right_item_l = 25 // lower bound on probability of naming right theft target
var/const/prob_right_item_h = 50 // upper bound on probability of naming the right theft target
var/const/prob_int_sab_target = 50 // intercept names the sabotage target half the time
var/const/prob_right_sab_target_l = 25 // lower bound on probability of naming right sabotage target
var/const/prob_right_sab_target_h = 50 // upper bound on probability of naming right sabotage target
var/const/prob_right_killer_l = 25 //lower bound on probability of naming the right operative
var/const/prob_right_killer_h = 50 //upper bound on probability of naming the right operative
var/const/prob_right_objective_l = 25 //lower bound on probability of determining the objective correctly
var/const/prob_right_objective_h = 50 //upper bound on probability of determining the objective correctly
var/vampire_amount = 4
/datum/game_mode/vampire/announce()
to_chat(world, "The current game mode is - Vampires!")
to_chat(world, "There are Vampires from Space Transylvania on the station, keep your blood close and neck safe!")
/datum/game_mode/vampire/pre_setup()
if(config.protect_roles_from_antagonist)
restricted_jobs += protected_jobs
var/list/datum/mind/possible_vampires = get_players_for_role(ROLE_VAMPIRE)
vampire_amount = 1 + round(num_players() / 10)
if(possible_vampires.len>0)
for(var/i = 0, i < vampire_amount, i++)
if(!possible_vampires.len) break
var/datum/mind/vampire = pick(possible_vampires)
possible_vampires -= vampire
vampires += vampire
vampire.restricted_roles = restricted_jobs
modePlayer += vampires
var/datum/mindslaves/slaved = new()
slaved.masters += vampire
vampire.som = slaved //we MIGT want to mindslave someone
vampire.special_role = "Vampire" // Needs to be done in pre-setup to prevent role bugs
return 1
else
return 0
/datum/game_mode/vampire/post_setup()
for(var/datum/mind/vampire in vampires)
grant_vampire_powers(vampire.current)
forge_vampire_objectives(vampire)
greet_vampire(vampire)
update_vampire_icons_added(vampire)
..()
/datum/game_mode/proc/auto_declare_completion_vampire()
if(vampires.len)
var/text = "The vampires were:"
for(var/datum/mind/vampire in vampires)
var/traitorwin = 1
text += "
[vampire.key] was [vampire.name] ("
if(vampire.current)
if(vampire.current.stat == DEAD)
text += "died"
else
text += "survived"
if(vampire.current.real_name != vampire.name)
text += " as [vampire.current.real_name]"
else
text += "body destroyed"
text += ")"
if(vampire.objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in vampire.objectives)
if(objective.check_completion())
text += "
Objective #[count]: [objective.explanation_text] Success!"
feedback_add_details("traitor_objective","[objective.type]|SUCCESS")
else
text += "
Objective #[count]: [objective.explanation_text] Fail."
feedback_add_details("traitor_objective","[objective.type]|FAIL")
traitorwin = 0
count++
var/special_role_text
if(vampire.special_role)
special_role_text = lowertext(vampire.special_role)
else
special_role_text = "antagonist"
if(traitorwin)
text += "
The [special_role_text] was successful!"
feedback_add_details("traitor_success","SUCCESS")
else
text += "
The [special_role_text] has failed!"
feedback_add_details("traitor_success","FAIL")
to_chat(world, text)
return 1
/datum/game_mode/proc/auto_declare_completion_enthralled()
if(vampire_enthralled.len)
var/text = "The Enthralled were:"
for(var/datum/mind/Mind in vampire_enthralled)
text += "
[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]"
else
text += "body destroyed"
text += ")"
to_chat(world, text)
return 1
/datum/game_mode/proc/forge_vampire_objectives(var/datum/mind/vampire)
//Objectives are traitor objectives plus blood objectives
var/datum/objective/blood/blood_objective = new
blood_objective.owner = vampire
blood_objective.gen_amount_goal(150, 400)
vampire.objectives += blood_objective
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = vampire
kill_objective.find_target()
vampire.objectives += kill_objective
var/datum/objective/steal/steal_objective = new
steal_objective.owner = vampire
steal_objective.find_target()
vampire.objectives += steal_objective
switch(rand(1,100))
if(1 to 80)
if(!(locate(/datum/objective/escape) in vampire.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = vampire
vampire.objectives += escape_objective
else
if(!(locate(/datum/objective/survive) in vampire.objectives))
var/datum/objective/survive/survive_objective = new
survive_objective.owner = vampire
vampire.objectives += survive_objective
return
/datum/game_mode/proc/grant_vampire_powers(mob/living/carbon/vampire_mob)
if(!istype(vampire_mob))
return
vampire_mob.make_vampire()
/datum/game_mode/proc/greet_vampire(var/datum/mind/vampire, var/you_are=1)
var/dat
if(you_are)
dat = "You are a Vampire!
"
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."}
to_chat(vampire.current, dat)
to_chat(vampire.current, "You must complete the following tasks:")
if(vampire.current.mind)
if(vampire.current.mind.assigned_role == "Clown")
to_chat(vampire.current, "Your lust for blood has allowed you to overcome your clumsy nature allowing you to wield weapons without harming yourself.")
vampire.current.mutations.Remove(CLUMSY)
var/obj_count = 1
for(var/datum/objective/objective in vampire.objectives)
to_chat(vampire.current, "Objective #[obj_count]: [objective.explanation_text]")
obj_count++
return
/datum/vampire
var/bloodtotal = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
var/bloodusable = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
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)
/datum/vampire/New(gend = FEMALE)
gender = gend
/datum/vampire/proc/force_add_ability(path)
var/spell = new path(owner)
if(istype(spell, /obj/effect/proc_holder/spell))
owner.mind.AddSpell(spell)
powers += spell
/datum/vampire/proc/get_ability(path)
for(var/P in powers)
var/datum/power = P
if(power.type == path)
return power
return null
/datum/vampire/proc/add_ability(path)
if(!get_ability(path))
force_add_ability(path)
/datum/vampire/proc/remove_ability(ability)
if(ability && (ability in powers))
powers -= ability
owner.mind.spell_list.Remove(ability)
qdel(ability)
/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)
if(owner.hud_used)
var/datum/hud/hud = owner.hud_used
if(hud.vampire_blood_display)
hud.remove_vampire_hud()
owner.alpha = 255
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H)
draining = H
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
owner.attack_log += text("\[[time_stamp()]\] Bit [H] ([H.ckey]) in the neck and draining their blood")
H.attack_log += text("\[[time_stamp()]\] Has been bit in the neck by [owner] ([owner.ckey])")
log_attack("[owner] ([owner.ckey]) bit [H] ([H.ckey]) in the neck")
owner.visible_message("[owner] bites [H]'s neck!", "You bite [H]'s neck and begin to drain their blood.", "You hear a soft puncture and a wet sucking noise.")
if(!iscarbon(owner))
H.LAssailant = null
else
H.LAssailant = owner
while(do_mob(owner, H, 50))
if(!(owner.mind in ticker.mode.vampires))
to_chat(owner, "Your fangs have disappeared!")
return
old_bloodtotal = bloodtotal
old_bloodusable = bloodusable
if(!H.vessel.get_reagent_amount("blood"))
to_chat(owner, "They've got no blood left to give.")
break
if(H.stat < DEAD)
blood = min(20, H.vessel.get_reagent_amount("blood")) // 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
blood = min(5, H.vessel.get_reagent_amount("blood")) // The dead only give 5 bloods
bloodtotal += blood
if(old_bloodtotal != bloodtotal)
to_chat(owner, "You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].")
check_vampire_upgrade()
H.vessel.remove_reagent("blood", 25)
if(ishuman(owner))
var/mob/living/carbon/human/V = owner
V.nutrition = min(450, V.nutrition + (blood / 2))
draining = null
to_chat(owner, "You stop draining [H.name] of blood.")
/datum/vampire/proc/check_vampire_upgrade(announce = 1)
var/list/old_powers = powers.Copy()
for(var/ptype in upgrade_tiers)
var/level = upgrade_tiers[ptype]
if(bloodtotal >= level)
add_ability(ptype)
if(announce)
announce_new_power(old_powers)
/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, "[power.gain_desc]")
else if(istype(p, /datum/vampire_passive))
var/datum/vampire_passive/power = p
to_chat(owner, "[power.gain_desc]")
//prepare for copypaste
/datum/game_mode/proc/update_vampire_icons_added(datum/mind/vampire_mind)
var/datum/atom_hud/antag/vamp_hud = huds[ANTAG_HUD_VAMPIRE]
vamp_hud.join_hud(vampire_mind.current)
set_antag_hud(vampire_mind.current, ((vampire_mind in vampires) ? "hudvampire" : "hudvampirethrall"))
/datum/game_mode/proc/update_vampire_icons_removed(datum/mind/vampire_mind)
var/datum/atom_hud/antag/vampire_hud = huds[ANTAG_HUD_VAMPIRE]
vampire_hud.leave_hud(vampire_mind.current)
set_antag_hud(vampire_mind.current, null)
/datum/game_mode/proc/remove_vampire_mind(datum/mind/vampire_mind, datum/mind/head)
//var/list/removal
if(!istype(head))
head = vampire_mind //workaround for removing a thrall's control over the enthralled
var/ref = "\ref[head]"
if(ref in vampire_thralls)
vampire_thralls[ref] -= vampire_mind
vampire_enthralled -= vampire_mind
vampire_mind.special_role = null
var/datum/mindslaves/slaved = vampire_mind.som
slaved.serv -= vampire_mind
vampire_mind.som = null
slaved.leave_serv_hud(vampire_mind)
update_vampire_icons_removed(vampire_mind)
vampire_mind.current.visible_message("[vampire_mind.current] looks as though a burden has been lifted!", "The dark fog in your mind clears as you regain control of your own faculties, you are no longer a vampire thrall!")
if(vampire_mind.current.hud_used)
vampire_mind.current.hud_used.remove_vampire_hud()
/datum/vampire/proc/check_sun()
var/ax = owner.x
var/ay = owner.y
for(var/i = 1 to 20)
ax += sun.dx
ay += sun.dy
var/turf/T = locate(round(ax, 0.5), round(ay, 0.5), owner.z)
if(T.x == 1 || T.x == world.maxx || T.y == 1 || T.y == world.maxy)
break
if(T.density)
return
vamp_burn(1)
/datum/vampire/proc/handle_vampire()
if(owner.hud_used)
var/datum/hud/hud = owner.hud_used
if(!hud.vampire_blood_display)
hud.vampire_blood_display = new /obj/screen()
hud.vampire_blood_display.name = "Usable Blood"
hud.vampire_blood_display.icon_state = "power_display"
hud.vampire_blood_display.screen_loc = "WEST:6,CENTER-1:15"
hud.static_inventory += hud.vampire_blood_display
hud.show_hud(hud.hud_version)
hud.vampire_blood_display.maptext = "