//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 = "
[bloodusable]
" handle_vampire_cloak() if(istype(owner.loc, /turf/space)) check_sun() if(istype(owner.loc.loc, /area/chapel) && !get_ability(/datum/vampire_passive/full)) vamp_burn(0) nullified = max(0, nullified - 1) /datum/vampire/proc/handle_vampire_cloak() if(!ishuman(owner)) owner.alpha = 255 return var/turf/simulated/T = get_turf(owner) var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T var/light_available if(L) light_available = L.get_clamped_lum(0.5) * 10 else light_available = 10 if(!istype(T)) return 0 if(!iscloaking) owner.alpha = 255 return 0 if(light_available <= 2) owner.alpha = round((255 * 0.15)) return 1 else owner.alpha = round((255 * 0.80)) /datum/vampire/proc/vamp_burn(severe_burn) var/burn_chance = severe_burn ? 35 : 8 if(prob(burn_chance) && owner.health >= 50) switch(owner.health) if(75 to 100) to_chat(owner, "Your skin flakes away...") if(50 to 75) to_chat(owner, "Your skin sizzles!") owner.adjustFireLoss(3) else if(owner.health < 50) if(!owner.on_fire) to_chat(owner, "Your skin catches fire!") owner.emote("scream") else to_chat(owner, "You continue to burn!") owner.adjust_fire_stacks(5) owner.IgniteMob() return /datum/hud/proc/remove_vampire_hud() if(!vampire_blood_display) return static_inventory -= vampire_blood_display qdel(vampire_blood_display) vampire_blood_display = null show_hud(hud_version)