mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2025-12-21 07:42:21 +00:00
445 lines
16 KiB
Plaintext
445 lines
16 KiB
Plaintext
//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, "<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>")
|
|
|
|
/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 = "<FONT size = 2><B>The vampires were:</B></FONT>"
|
|
for(var/datum/mind/vampire in vampires)
|
|
var/traitorwin = 1
|
|
|
|
text += "<br>[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 += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font>"
|
|
feedback_add_details("traitor_objective","[objective.type]|SUCCESS")
|
|
else
|
|
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font>"
|
|
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 += "<br><font color='green'><B>The [special_role_text] was successful!</B></font>"
|
|
feedback_add_details("traitor_success","SUCCESS")
|
|
else
|
|
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
|
|
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 = "<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)
|
|
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 = "<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."}
|
|
to_chat(vampire.current, dat)
|
|
to_chat(vampire.current, "<B>You must complete the following tasks:</B>")
|
|
|
|
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, "<B>Objective #[obj_count]</B>: [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()]\] <font color='red'>Bit [H] ([H.ckey]) in the neck and draining their blood</font>")
|
|
H.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been bit in the neck by [owner] ([owner.ckey])</font>")
|
|
log_attack("[owner] ([owner.ckey]) bit [H] ([H.ckey]) in the neck")
|
|
owner.visible_message("<span class='danger'>[owner] bites [H]'s neck!</span>", "<span class='danger'>You bite [H]'s neck 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 = owner
|
|
while(do_mob(owner, H, 50))
|
|
if(!(owner.mind in ticker.mode.vampires))
|
|
to_chat(owner, "<span class='warning'>Your fangs have disappeared!</span>")
|
|
return
|
|
old_bloodtotal = bloodtotal
|
|
old_bloodusable = bloodusable
|
|
if(!H.vessel.get_reagent_amount("blood"))
|
|
to_chat(owner, "<span class='warning'>They've got no blood left to give.</span>")
|
|
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, "<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()
|
|
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, "<span class='notice'>You stop draining [H.name] of blood.</span>")
|
|
|
|
/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, "<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>")
|
|
|
|
//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("<span class='userdanger'>[vampire_mind.current] looks as though a burden has been lifted!</span>", "<span class='userdanger'>The dark fog in your mind clears as you regain control of your own faculties, you are no longer a vampire thrall!</span>")
|
|
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 = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#dd66dd'>[bloodusable]</font></div>"
|
|
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, "<span class='warning'>Your skin flakes away...</span>")
|
|
if(50 to 75)
|
|
to_chat(owner, "<span class='warning'>Your skin sizzles!</span>")
|
|
owner.adjustFireLoss(3)
|
|
else if(owner.health < 50)
|
|
if(!owner.on_fire)
|
|
to_chat(owner, "<span class='danger'>Your skin catches fire!</span>")
|
|
owner.emote("scream")
|
|
else
|
|
to_chat(owner, "<span class='danger'>You continue to burn!</span>")
|
|
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)
|