diff --git a/baystation12.dme b/baystation12.dme
index 9be3fc79cc8..efde1247b12 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -249,6 +249,8 @@
#include "code\game\gamemodes\revolution\revolution.dm"
#include "code\game\gamemodes\revolution\rp_revolution.dm"
#include "code\game\gamemodes\traitor\traitor.dm"
+#include "code\game\gamemodes\vampire\vampire.dm"
+#include "code\game\gamemodes\vampire\vampire_powers.dm"
#include "code\game\gamemodes\vox\vox.dm"
#include "code\game\gamemodes\vox\heist\heist.dm"
#include "code\game\gamemodes\vox\trade\trade.dm"
@@ -1078,6 +1080,7 @@
#include "code\modules\mob\living\simple_animal\friendly\spiderbot.dm"
#include "code\modules\mob\living\simple_animal\friendly\tomato.dm"
#include "code\modules\mob\living\simple_animal\hostile\alien.dm"
+#include "code\modules\mob\living\simple_animal\hostile\bat.dm"
#include "code\modules\mob\living\simple_animal\hostile\bear.dm"
#include "code\modules\mob\living\simple_animal\hostile\carp.dm"
#include "code\modules\mob\living\simple_animal\hostile\creature.dm"
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 0ed504fbcaa..4f93aad29ce 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -52,7 +52,7 @@ datum/mind
var/datum/faction/faction //associated faction
var/datum/changeling/changeling //changeling holder
-
+ var/datum/vampire/vampire //vampire holder
var/rev_cooldown = 0
// the world.time since the mob has been brigged, or -1 if not at all
@@ -128,6 +128,7 @@ datum/mind
"cult",
"wizard",
"changeling",
+ "vampire",
"nuclear",
"traitor", // "traitorchan",
"monkey",
@@ -222,6 +223,20 @@ datum/mind
// text += "
All the changelings are dead! Restart in [round((changeling.TIME_TO_GET_REVIVED-(world.time-changeling.changelingdeathtime))/10)] seconds."
sections["changeling"] = text
+ /** VAMPIRE ***/
+ text = "vampire"
+ if (ticker.mode.config_tag=="vampire")
+ text = uppertext(text)
+ text = "[text]: "
+ if (src in ticker.mode.vampires)
+ text += "YES|no"
+ if (objectives.len==0)
+ text += "
Objectives are empty! Randomize!"
+ else
+ text += "yes|NO"
+ sections["vampire"] = text
+
+
/** NUCLEAR ***/
text = "nuclear"
if (ticker.mode.config_tag=="nuclear")
@@ -387,7 +402,7 @@ datum/mind
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
- var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "custom")
+ var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type) return
var/datum/objective/new_objective = null
@@ -455,7 +470,7 @@ datum/mind
if (!steal.select_target())
return
- if("download","capture","absorb")
+ if("download","capture","absorb", "blood")
var/def_num
if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]"))
def_num = objective.target_amount
@@ -474,6 +489,9 @@ datum/mind
if("absorb")
new_objective = new /datum/objective/absorb
new_objective.explanation_text = "Absorb [target_number] compatible genomes."
+ if("blood")
+ new_objective = new /datum/objective/blood
+ new_objective.explanation_text = "Accumulate atleast [target_number] units of blood in total."
new_objective.owner = src
new_objective.target_amount = target_number
@@ -735,6 +753,28 @@ datum/mind
updateappearance(current, current.dna.uni_identity)
domutcheck(current, null)
+ else if (href_list["vampire"])
+ switch(href_list["vampire"])
+ if("clear")
+ if(src in ticker.mode.vampires)
+ ticker.mode.vampires -= src
+ special_role = null
+ current.remove_vampire_powers()
+ if(vampire) del(vampire)
+ current << "You grow weak and lose your powers! You are no longer a vampire and are stuck in your current form!"
+ log_admin("[key_name_admin(usr)] has de-vampired [current].")
+ if("vampire")
+ if(!(src in ticker.mode.vampires))
+ ticker.mode.vampires += src
+ ticker.mode.grant_vampire_powers(current)
+ special_role = "Vampire"
+ current << "Your powers are awoken. Your lust for blood grows... You are a Vampire!"
+ log_admin("[key_name_admin(usr)] has vampired [current].")
+ if("autoobjectives")
+ ticker.mode.forge_vampire_objectives(src)
+ usr << "\blue The objectives for vampire [key] have been generated. You can edit them and announce manually."
+
+
else if (href_list["nuclear"])
switch(href_list["nuclear"])
if("clear")
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index f262818d656..3302cbe5abe 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -745,3 +745,15 @@ datum/objective/absorb
/*-------ENDOF CULTIST------*/
*/
+datum/objective/blood
+ proc/gen_amount_goal(low = 150, high = 400)
+ target_amount = rand(low,high)
+ target_amount = round(round(target_amount/5)*5)
+ explanation_text = "Accumulate atleast [target_amount] units of blood in total."
+ return target_amount
+
+ check_completion()
+ if(owner && owner.vampire && owner.vampire.bloodtotal && owner.vampire.bloodtotal >= target_amount)
+ return 1
+ else
+ return 0
diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm
new file mode 100644
index 00000000000..35ccec0392d
--- /dev/null
+++ b/code/game/gamemodes/vampire/vampire.dm
@@ -0,0 +1,409 @@
+//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/enthralled = list() //those controlled by a vampire
+ var/list/thralls = list() //vammpires controlling somebody
+/datum/game_mode/vampire
+ name = "vampire"
+ config_tag = "vampire"
+ restricted_jobs = list("AI", "Cyborg", "Mobile MMI", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain") //Consistent screening has filtered all infiltration attempts on high value jobs
+ protected_jobs = list()
+ required_players = 1
+ required_players_secret = 15
+ required_enemies = 1
+ recommended_enemies = 4
+
+ uplink_welcome = "Syndicate Uplink Console:"
+ uplink_uses = 10
+
+ 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/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds)
+ var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds)
+
+ var/vampire_amount = 4
+
+
+/datum/game_mode/vampire/announce()
+ world << "The current game mode is - Vampires!"
+ 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(BE_VAMPIRE)
+
+ for(var/datum/mind/player in possible_vampires)
+ for(var/job in restricted_jobs)//Removing robots from the list
+ if(player.assigned_role == job)
+ possible_vampires -= player
+
+ 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
+ modePlayer += vampires
+ return 1
+ else
+ return 0
+
+/datum/game_mode/vampire/post_setup()
+ for(var/datum/mind/vampire in vampires)
+ grant_vampire_powers(vampire.current)
+ vampire.special_role = "Vampire"
+ forge_vampire_objectives(vampire)
+ greet_vampire(vampire)
+
+ spawn (rand(waittime_l, waittime_h))
+ send_intercept()
+ ..()
+ return
+
+/datum/game_mode/proc/auto_declare_completion_vampire()
+ if(traitors.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")
+ world << text
+ return 1
+
+/datum/game_mode/proc/auto_declare_completion_enthralled()
+ if(traitors.len)
+ var/text = "The Enthralled were:"
+ for(var/datum/mind/enthralled in enthralled)
+ text += "
[enthralled.key] was [enthralled.name] ("
+ if(enthralled.current)
+ if(enthralled.current.stat == DEAD)
+ text += "died"
+ else
+ text += "survived"
+ if(enthralled.current.real_name != enthralled.name)
+ text += " as [enthralled.current.real_name]"
+ else
+ text += "body destroyed"
+ text += ")"
+ 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 = "\red You are a Vampire! \black"
+ 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."}
+ vampire.current << dat
+ vampire.current << "You must complete the following tasks:"
+
+ if (vampire.current.mind)
+ if (vampire.current.mind.assigned_role == "Clown")
+ 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)
+ 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, see defines in setup.dm
+ var/mob/living/carbon/human/draining // who the vampire is draining of blood
+/datum/vampire/New(gend = FEMALE)
+ gender = gend
+
+/mob/proc/make_vampire()
+ if(!mind) return
+ if(!mind.vampire)
+ mind.vampire = new /datum/vampire(gender)
+ mind.vampire.owner = src
+ verbs += /client/proc/vampire_rejuvinate
+ verbs += /client/proc/vampire_hypnotise
+ verbs += /client/proc/vampire_glare
+ //testing purposes REMOVE BEFORE PUSH TO MASTER
+ /*for(var/handler in typesof(/client/proc))
+ if(findtext("[handler]","vampire_"))
+ verbs += handler*/
+ for(var/i = 1; i <= 3; i++) // CHANGE TO 3 RATHER THAN 12 AFTER TESTING IS DONE
+ mind.vampire.powers.Add(i)
+
+/mob/proc/remove_vampire_powers()
+ for(var/handler in typesof(/client/proc))
+ if(findtext("[handler]","vampire_"))
+ verbs -= handler
+
+/mob/proc/handle_bloodsucking(mob/living/carbon/human/H)
+ src.mind.vampire.draining = H
+ var/blood = 0
+ var/bloodtotal = 0 //used to see if we increased our blood total
+ var/bloodusable = 0 //used to see if we increased our blood usable
+ src.attack_log += text("\[[time_stamp()]\] Bit [src.name] ([src.ckey]) in the neck and draining their blood")
+ H.attack_log += text("\[[time_stamp()]\] Has been bit in the neck by [src.name] ([src.ckey])")
+ log_attack("[src.name] ([src.ckey]) bit [H.name] ([H.ckey]) in the neck")
+ src.visible_message("\red [src.name] bites [H.name]'s neck!", "\red You bite [H.name]'s neck and begin to drain their blood.", "\blue You hear a soft puncture and a wet sucking noise")
+ while(do_mob(src, H, 50))
+ if(!mind.vampire || !(mind in ticker.mode.vampires))
+ src << "\red Your fangs have disappeared!"
+ return 0
+ bloodtotal = src.mind.vampire.bloodtotal
+ bloodusable = src.mind.vampire.bloodusable
+ if(!H.vessel.get_reagent_amount("blood"))
+ src << "\red They've got no blood left to give."
+ break
+ if(H.stat < 2) //alive
+ blood = min(10, H.vessel.get_reagent_amount("blood"))// if they have less than 10 blood, give them the remnant else they get 10 blood
+ src.mind.vampire.bloodtotal += blood
+ src.mind.vampire.bloodusable += blood
+ H.adjustCloneLoss(5) // beep boop 10 damage
+ else
+ blood = min(5, H.vessel.get_reagent_amount("blood"))// The dead only give 5 bloods
+ src.mind.vampire.bloodtotal += blood
+ if(bloodtotal != src.mind.vampire.bloodtotal)
+ src << "\blue You have accumulated [src.mind.vampire.bloodtotal] [src.mind.vampire.bloodtotal > 1 ? "units" : "unit"] of blood[src.mind.vampire.bloodusable != bloodusable ?", and have [src.mind.vampire.bloodusable] left to use" : "."]"
+ check_vampire_upgrade(mind)
+ H.vessel.remove_reagent("blood",25)
+
+ src.mind.vampire.draining = null
+ src << "\blue You stop draining [H.name] of blood."
+ return 1
+
+/mob/proc/check_vampire_upgrade(datum/mind/v)
+ if(!v) return
+ if(!v.vampire) return
+ var/datum/vampire/vamp = v.vampire
+ var/list/old_powers = vamp.powers.Copy()
+
+ // This used to be a switch statement.
+ // Don't use switch statements for shit like this, since blood can be any random-ass value.
+ // if(100) requires the blood to be at EXACTLY 100 units to trigger.
+ // if(blud >= 100) activates when blood is at or over 100 units.
+ // TODO: Make this modular.
+
+ // TIER 1
+ if(vamp.bloodtotal >= 100)
+ if(!(VAMP_VISION in vamp.powers))
+ vamp.powers.Add(VAMP_VISION)
+ if(!(VAMP_SHAPE in vamp.powers))
+ vamp.powers.Add(VAMP_SHAPE)
+
+ // TIER 2
+ if(vamp.bloodtotal >= 150)
+ if(!(VAMP_CLOAK in vamp.powers))
+ vamp.powers.Add(VAMP_CLOAK)
+ if(!(VAMP_DISEASE in vamp.powers))
+ vamp.powers.Add(VAMP_DISEASE)
+
+ // TIER 3
+ if(vamp.bloodtotal >= 200)
+ if(!(VAMP_BATS in vamp.powers))
+ vamp.powers.Add(VAMP_BATS)
+ if(!(VAMP_SCREAM in vamp.powers))
+ vamp.powers.Add(VAMP_SCREAM)
+ // Commented out until we can figured out a way to stop this from spamming.
+ //src << "\blue Your rejuvination abilities have improved and will now heal you over time when used."
+
+ // TIER 4
+ if(vamp.bloodtotal >= 300)
+ if(!(VAMP_JAUNT in vamp.powers))
+ vamp.powers.Add(VAMP_JAUNT)
+ if(!(VAMP_SLAVE in vamp.powers))
+ vamp.powers.Add(VAMP_SLAVE)
+
+ // TIER 5
+ if(vamp.bloodtotal >= 500)
+ if(!(VAMP_FULL in vamp.powers))
+ vamp.powers.Add(VAMP_FULL)
+
+ announce_new_power(old_powers, vamp.powers)
+
+/mob/proc/announce_new_power(list/old_powers, list/new_powers)
+ for(var/n in new_powers)
+ if(!(n in old_powers))
+ switch(n)
+ if(VAMP_SHAPE)
+ src << "\blue You have gained the shapeshifting ability, at the cost of stored blood you can change your form permanently."
+ verbs += /client/proc/vampire_shapeshift
+ if(VAMP_VISION)
+ src << "\blue Your vampiric vision has improved."
+ //no verb
+ if(VAMP_DISEASE)
+ src << "\blue You have gained the Diseased Touch ability which causes those you touch to die shortly after unless treated medically."
+ verbs += /client/proc/vampire_disease
+ if(VAMP_CLOAK)
+ src << "\blue You have gained the Cloak of Darkness ability which when toggled makes you near invisible in the shroud of darkness."
+ verbs += /client/proc/vampire_cloak
+ if(VAMP_BATS)
+ src << "\blue You have gained the Summon Bats ability."
+ verbs += /client/proc/vampire_bats // work in progress
+ if(VAMP_SCREAM)
+ src << "\blue You have gained the Chriopteran Screech ability which stuns anything with ears in a large radius and shatters glass in the process."
+ verbs += /client/proc/vampire_screech
+ if(VAMP_JAUNT)
+ src << "\blue 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."
+ verbs += /client/proc/vampire_jaunt
+ if(VAMP_SLAVE)
+ src << "\blue You have gained the Enthrall ability which at a heavy blood cost allows you to enslave a human that is not loyal to any other for a random period of time."
+ verbs += /client/proc/vampire_enthrall
+ if(VAMP_FULL)
+ src << "\blue You have reached your full potential and are no longer weak to the effects of anything holy and your vision has been improved greatyl."
+ //no verb
+//prepare for copypaste
+/datum/game_mode/proc/update_vampire_icons_added(datum/mind/vampire_mind)
+ var/ref = "\ref[vampire_mind]"
+ if(ref in thralls)
+ if(vampire_mind.current)
+ if(vampire_mind.current.client)
+ var/I = image('icons/mob/mob.dmi', loc = vampire_mind.current, icon_state = "vampire")
+ vampire_mind.current.client.images += I
+ for(var/headref in thralls)
+ for(var/datum/mind/t_mind in thralls[headref])
+ var/datum/mind/head = locate(headref)
+ if(head)
+ if(head.current)
+ if(head.current.client)
+ var/I = image('icons/mob/mob.dmi', loc = t_mind.current, icon_state = "vampthrall")
+ head.current.client.images += I
+ if(t_mind.current)
+ if(t_mind.current.client)
+ var/I = image('icons/mob/mob.dmi', loc = head.current, icon_state = "vampire")
+ t_mind.current.client.images += I
+ if(t_mind.current)
+ if(t_mind.current.client)
+ var/I = image('icons/mob/mob.dmi', loc = t_mind.current, icon_state = "vampthrall")
+ t_mind.current.client.images += I
+
+/datum/game_mode/proc/update_vampire_icons_removed(datum/mind/vampire_mind)
+ for(var/headref in thralls)
+ var/datum/mind/head = locate(headref)
+ for(var/datum/mind/t_mind in thralls[headref])
+ if(t_mind.current)
+ if(t_mind.current.client)
+ for(var/image/I in t_mind.current.client.images)
+ if((I.icon_state == "vampthrall" || I.icon_state == "vampire") && I.loc == vampire_mind.current)
+ //world.log << "deleting [vampire_mind] overlay"
+ del(I)
+ if(head)
+ //world.log << "found [head.name]"
+ if(head.current)
+ if(head.current.client)
+ for(var/image/I in head.current.client.images)
+ if((I.icon_state == "vampthrall" || I.icon_state == "vampire") && I.loc == vampire_mind.current)
+ //world.log << "deleting [vampire_mind] overlay"
+ del(I)
+ if(vampire_mind.current)
+ if(vampire_mind.current.client)
+ for(var/image/I in vampire_mind.current.client.images)
+ if(I.icon_state == "vampthrall" || I.icon_state == "vampire")
+ del(I)
+
+/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 thralls)
+ thralls[ref] -= vampire_mind
+ enthralled -= vampire_mind
+ vampire_mind.special_role = null
+ update_vampire_icons_removed(vampire_mind)
+ //world << "Removed [vampire_mind.current.name] from vampire shit"
+ vampire_mind.current << "\red The fog clouding your mind clears. You remember nothing from the moment you were enthralled until now."
\ No newline at end of file
diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm
new file mode 100644
index 00000000000..efe60907559
--- /dev/null
+++ b/code/game/gamemodes/vampire/vampire_powers.dm
@@ -0,0 +1,370 @@
+//This should hold all the vampire related powers
+
+
+/mob/proc/vampire_power(required_blood=0, max_stat=0)
+
+ if(!src.mind) return 0
+ if(!ishuman(src))
+ src << "You are in too weak of a form to do this!"
+ return 0
+
+ var/datum/vampire/vampire = src.mind.vampire
+ if(!vampire)
+ world.log << "[src] has vampire verbs but isn't a vampire."
+ return 0
+
+ if(src.stat > max_stat)
+ src << "You are incapacitated."
+ return 0
+
+ if(vampire.bloodusable < required_blood)
+ src << "You require at least [required_blood] units of usable blood to do that!"
+ return 0
+
+ return 1
+
+/mob/proc/vampire_can_reach(mob/M as mob, active_range = 1)
+ if(M.loc == src.loc) return 1 //target and source are in the same thing
+ if(!isturf(src.loc) || !isturf(M.loc)) return 0 //One is inside, the other is outside something.
+ if(AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, active_range)) //If a path exists, good!
+ return 1
+ return 0
+
+/mob/proc/vampire_active(required_blood=0, max_stat=0, active_range=1)
+ var/pass = vampire_power(required_blood, max_stat)
+ if(!pass) return
+ var/datum/vampire/vampire = mind.vampire
+ if(!vampire) return
+ var/list/victims = list()
+ for(var/mob/living/carbon/C in oview(active_range))
+ victims += C
+ var/mob/living/carbon/T = input(src, "Victim?") as null|anything in victims
+
+ if(!T) return
+ if(!(T in view(active_range))) return
+ if(!vampire_can_reach(T, active_range)) return
+ if(!vampire_power(required_blood, max_stat)) return
+ return T
+
+/client/proc/vampire_rejuvinate()
+ set category = "Vampire"
+ set name = "Rejuvinate "
+ set desc= "Flush your system with spare blood to remove any incapacitating effects"
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ if(M.current.vampire_power(0, 1))
+ M.current.weakened = 0
+ M.current.stunned = 0
+ M.current.paralysis = 0
+ //M.vampire.bloodusable -= 10
+ M.current << "\blue You flush your system with clean blood and remove any incapacitating effects."
+ M.current.verbs -= /client/proc/vampire_rejuvinate
+ spawn(200)
+ M.current.verbs += /client/proc/vampire_rejuvinate
+
+/client/proc/vampire_hypnotise()
+ set category = "Vampire"
+ set name = "Hypnotise (20)"
+ set desc= "A piercing stare that incapacitates your victim for a good length of time."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+
+ var/mob/living/carbon/C = M.current.vampire_active(20, 0, 1)
+
+ if(!C) return
+ M.current.visible_message("[M]'s eyes flash briefly as he stares into [C.name]'s eyes")
+ M.current.remove_vampire_blood(20)
+ M.current.verbs -= /client/proc/vampire_hypnotise
+ spawn(1800)
+ M.current.verbs += /client/proc/vampire_hypnotise
+ if(do_mob(M.current, C, 50))
+ if(C.mind && C.mind.vampire)
+ M.current << "\red Your piercing gaze fails to knock out [C.name]."
+ C << "\blue [M.current]'s feeble gaze is ineffective."
+ return
+ else
+ M.current << "\red Your piercing gaze knocks out [C.name]."
+ C << "\red You find yourself unable to move and barely able to speak"
+ C.Weaken(20)
+ C.Stun(20)
+ C.stuttering = 20
+ else
+ M.current << "\red You broke your gaze."
+ return
+
+/client/proc/vampire_disease()
+ set category = "Vampire"
+ set name = "Diseased Touch (100)"
+ set desc = "Touches your victim with infected blood giving them the Shutdown Syndrome which quickly shutsdown their major organs resulting in a quick painful death."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+
+ var/mob/living/carbon/C = M.current.vampire_active(100, 0, 1)
+ if(!C) return
+ if(!M.current.vampire_can_reach(C, 1))
+ M.current << "\red You cannot touch [C.name] from where you are standing!"
+ return
+ M.current << "\red You stealthily infect [C.name] with your diseased touch."
+ /*var/t_him = "it"
+ if (src.gender == MALE)
+ t_him = "him"
+ else if (src.gender == FEMALE)
+ t_him = "her"
+ M.current.visible_message("\blue [M] shakes [src] trying to wake [t_him] up!" )
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)*/
+ C.help_shake_act(M.current) // i use da colon
+ var/datum/disease2/disease/shutdown = new /datum/disease2/disease
+ var/datum/disease2/effectholder/holder = new /datum/disease2/effectholder
+ var/datum/disease2/effect/organs/vampire/O = new /datum/disease2/effect/organs/vampire
+ holder.effect += O
+ holder.chance = 10
+ shutdown.infectionchance = 100
+ shutdown.antigen |= text2num(pick(ANTIGENS))
+ shutdown.antigen |= text2num(pick(ANTIGENS))
+ shutdown.spreadtype = "None"
+ shutdown.uniqueID = rand(0,10000)
+ shutdown.effects += holder
+ shutdown.speed = 10
+ infect_virus2(C,shutdown,0)
+ M.current.remove_vampire_blood(100)
+ M.current.verbs -= /client/proc/vampire_disease
+ spawn(1800) M.current.verbs += /client/proc/vampire_disease
+
+/client/proc/vampire_glare()
+ set category = "Vampire"
+ set name = "Glare"
+ set desc= "A scary glare that incapacitates people for a short while around you."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ if(M.current.vampire_power(0, 1))
+ M.current.visible_message("\red [M.current]'s eyes emit a blinding flash!")
+ //M.vampire.bloodusable -= 10
+ M.current.verbs -= /client/proc/vampire_glare
+ spawn(300)
+ M.current.verbs += /client/proc/vampire_glare
+ if(istype(M.current:glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
+ M.current << "You're blindfolded"
+ return
+ for(var/mob/living/carbon/C in oview(1))
+ if(C.mind && C.mind.vampire) continue
+ if(!M.current.vampire_can_reach(C, 1)) continue
+ C.Stun(8)
+ C.Weaken(8)
+ C.stuttering = 20
+ C << "\red You are blinded by [M.current]'s glare"
+
+/client/proc/vampire_shapeshift()
+ set category = "Vampire"
+ set name = "Shapeshift (50)"
+ set desc = "Changes your name and appearance at the cost of 50 blood and has a cooldown of 3 minutes."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ if(M.current.vampire_power(50, 0))
+ M.current.visible_message("[M.current] transforms!")
+ M.current.client.prefs.real_name = random_name(M.current.gender)
+ M.current.client.prefs.randomize_appearance_for(M.current)
+ M.current.regenerate_icons()
+ M.current.remove_vampire_blood(50)
+ M.current.verbs -= /client/proc/vampire_shapeshift
+ spawn(1800) M.current.verbs += /client/proc/vampire_shapeshift
+
+/client/proc/vampire_screech()
+ set category = "Vampire"
+ set name = "Chiroptean Screech (30)"
+ set desc = "An extremely loud shriek that stuns nearby humans and breaks windows as well."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ if(M.current.vampire_power(30, 0))
+ M.current.visible_message("\red [M.current.name] lets out an ear piercing shriek!", "\red You let out a loud shriek.", "\red You hear a loud painful shriek!")
+ for(var/mob/living/carbon/C in ohearers(4, M.current))
+ if(C == M.current) continue
+ if(ishuman(C) && (C:l_ear || C:r_ear) && istype((C:l_ear || C:r_ear), /obj/item/clothing/ears/earmuffs)) continue
+ C << "You hear a ear piercing shriek and your senses dull!"
+ C.Weaken(8)
+ C.ear_deaf = 20
+ C.stuttering = 20
+ C.Stun(8)
+ C.make_jittery(150)
+ for(var/obj/structure/window/W in oview(3))
+ new W.shardtype(W.loc)
+ if(W.reinf) new /obj/item/stack/rods(W.loc)
+ del(W)
+ playsound(M.current.loc, 'sound/effects/creepyshriek.ogg', 100, 1)
+ M.current.remove_vampire_blood(30)
+ M.current.verbs -= /client/proc/vampire_screech
+ spawn(1800) M.current.verbs += /client/proc/vampire_screech
+
+/client/proc/vampire_enthrall()
+ set category = "Vampire"
+ set name = "Enthrall (300)"
+ set desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ var/mob/living/carbon/C = M.current.vampire_active(300, 0, 1)
+ if(!C) return
+ M.current.visible_message("\red [M.current.name] bites [C.name]'s neck!", "\red You bite [C.name]'s neck and begin the flow of power.")
+ C << "You feel the tendrils of evil invade your mind."
+ if(!ishuman(C))
+ M.current << "\red You can only enthrall humans"
+ return
+
+ if(do_mob(M.current, C, 50))
+ if(M.current.can_enthrall(C) && M.current.vampire_power(300, 0)) // recheck
+ M.current.handle_enthrall(C)
+ M.current.remove_vampire_blood(300)
+ else
+ M.current << "\red You or your target either moved or you dont have enough usable blood."
+ return
+ M.current.verbs -= /client/proc/vampire_enthrall
+ spawn(1800) M.current.verbs += /client/proc/vampire_enthrall
+
+
+/client/proc/vampire_cloak()
+ set category = "Vampire"
+ set name = "Cloak of Darkness (toggle)"
+ set desc = "Toggles whether you are currently cloaking yourself in darkness."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ if(M.current.vampire_power(0, 0))
+ M.vampire.iscloaking = !M.vampire.iscloaking
+ M.current << "\blue You will now be [M.vampire.iscloaking ? "hidden" : "seen"] in darkness."
+
+/mob/proc/handle_vampire_cloak()
+ if(!mind || !mind.vampire || !ishuman(src))
+ alpha = 255
+ return
+ var/turf/simulated/T = get_turf(src)
+
+ if(!istype(T))
+ return 0
+
+ if(!mind.vampire.iscloaking)
+ alpha = 255
+ return 0
+ if(T.lighting_lumcount <= 2)
+ alpha = round((255 * 0.15))
+ return 1
+ else
+ alpha = round((255 * 0.80))
+
+/mob/proc/can_enthrall(mob/living/carbon/C)
+ if(!C)
+ world.log << "something bad happened on enthralling a mob src is [src] [src.key] \ref[src]"
+ return 0
+ if(!C.mind)
+ src << "\red [C.name]'s mind is not there for you to enthrall."
+ return 0
+ if(/obj/item/weapon/implant/traitor in C.contents || /obj/item/weapon/implant/loyalty in C.contents || C.mind in ticker.mode.vampires || C.mind.vampire || C.mind in ticker.mode.enthralled)
+ C.visible_message("[C] seems to resist the takeover!", "You feel a familiar sensation in your skull that quickly dissipates.")
+ return 0
+ if(!ishuman(C))
+ src << "\red You can only enthrall humans!"
+ return 0
+ return 1
+
+/mob/proc/handle_enthrall(mob/living/carbon/human/H as mob)
+ if(!istype(H))
+ src << "\red SOMETHING WENT WRONG, YELL AT POMF OR NEXIS"
+ return 0
+ var/ref = "\ref[src.mind]"
+ if(!(ref in ticker.mode.thralls))
+ ticker.mode.thralls[ref] = list(H.mind)
+ ticker.mode.enthralled.Add(H.mind)
+ ticker.mode.enthralled[H.mind] = src.mind
+ H.mind.special_role = "VampThrall"
+ H << "\red You have been Enthralled by [name]. Follow their every command."
+ src << "\red You have successfully Enthralled [H.name]. If they refuse to do as you say just adminhelp."
+ ticker.mode.update_vampire_icons_added(H.mind)
+ ticker.mode.update_vampire_icons_added(src.mind)
+ log_admin("[ckey(src.key)] has mind-slaved [ckey(H.key)].")
+
+/client/proc/vampire_bats()
+ set category = "Vampire"
+ set name = "Summon Bats (75)"
+ set desc = "You summon a pair of space bats who attack nearby targets until they or their target is dead."
+ var/datum/mind/M = usr.mind
+ if(!M) return
+ if(M.current.vampire_power(75, 0))
+ var/list/turf/locs = new
+ var/number = 0
+ for(var/direction in alldirs) //looking for bat spawns
+ if(locs.len == 2) //we found 2 locations and thats all we need
+ break
+ var/turf/T = get_step(M.current,direction) //getting a loc in that direction
+ if(AStar(M.current.loc, T, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 1)) // if a path exists, so no dense objects in the way its valid salid
+ locs += T
+ if(locs.len)
+ for(var/turf/tospawn in locs)
+ number++
+ new /mob/living/simple_animal/hostile/scarybat(tospawn, M.current)
+ if(number != 2) //if we only found one location, spawn one on top of our tile so we dont get stacked bats
+ new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current)
+ else // we had no good locations so make two on top of us
+ new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current)
+ new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current)
+ M.current.remove_vampire_blood(75)
+ M.current.verbs -= /client/proc/vampire_bats
+ spawn(1200) M.current.verbs += /client/proc/vampire_bats
+
+/client/proc/vampire_jaunt()
+ //AHOY COPY PASTE INCOMING
+ set category = "Vampire"
+ set name = "Mist Form (30)"
+ set desc = "You take on the form of mist for a short period of time."
+ var/jaunt_duration = 50 //in deciseconds
+ var/datum/mind/M = usr.mind
+ if(!M) return
+
+ if(M.current.vampire_power(30, 0))
+ if(M.current.buckled) M.current.buckled.unbuckle()
+ spawn(0)
+ var/mobloc = get_turf(M.current.loc)
+ var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( mobloc )
+ var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc )
+ animation.name = "water"
+ animation.density = 0
+ animation.anchored = 1
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.icon_state = "liquify"
+ animation.layer = 5
+ animation.master = holder
+ M.current.ExtinguishMob()
+ if(M.current.buckled)
+ M.current.buckled.unbuckle()
+ flick("liquify",animation)
+ M.current.loc = holder
+ M.current.client.eye = holder
+ var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread()
+ steam.set_up(10, 0, mobloc)
+ steam.start()
+ sleep(jaunt_duration)
+ mobloc = get_turf(M.current.loc)
+ animation.loc = mobloc
+ steam.location = mobloc
+ steam.start()
+ M.current.canmove = 0
+ sleep(20)
+ flick("reappear",animation)
+ sleep(5)
+ if(!M.current.Move(mobloc))
+ for(var/direction in list(1,2,4,8,5,6,9,10))
+ var/turf/T = get_step(mobloc, direction)
+ if(T)
+ if(M.current.Move(T))
+ break
+ M.current.canmove = 1
+ M.current.client.eye = M.current
+ del(animation)
+ del(holder)
+ M.current.remove_vampire_blood(30)
+ M.current.verbs -= /client/proc/vampire_jaunt
+ spawn(600) M.current.verbs += /client/proc/vampire_jaunt
+
+/mob/proc/remove_vampire_blood(amount = 0)
+ var/bloodold
+ if(!mind || !mind.vampire)
+ return
+ bloodold = mind.vampire.bloodusable
+ mind.vampire.bloodusable = max(0, (mind.vampire.bloodusable - amount))
+ if(bloodold != mind.vampire.bloodusable)
+ src << "\blue You have [mind.vampire.bloodusable] left to use."
\ No newline at end of file
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 6cbdea01e46..0b76e21c88f 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -227,20 +227,21 @@
var/datum/gas_mixture/gas = location.remove_air(0.25*environment.total_moles)
var/heat_capacity = 0
+ var/energy_used
if(gas)
heat_capacity = gas.heat_capacity()
- var/energy_used = min( abs( heat_capacity*(gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
+ energy_used = min( abs( heat_capacity*(gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
- //Use power. Assuming that each power unit represents 1000 watts....
- use_power(energy_used/1000, ENVIRON)
+ //Use power. Assuming that each power unit represents 1000 watts....
+ use_power(energy_used/1000, ENVIRON)
- //We need to cool ourselves.
- if(environment.temperature > target_temperature)
- gas.temperature -= energy_used/heat_capacity
- else
- gas.temperature += energy_used/heat_capacity
+ //We need to cool ourselves.
+ if(environment.temperature > target_temperature)
+ gas.temperature -= energy_used/heat_capacity
+ else
+ gas.temperature += energy_used/heat_capacity
- environment.merge(gas)
+ environment.merge(gas)
if(abs(environment.temperature - target_temperature) <= 0.5)
regulating_temperature = 0
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 0e6eb04874f..2eea7058c5d 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -17,6 +17,7 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
"ninja" = "true", // 10
"vox raider" = IS_MODE_COMPILED("heist"), // 11
"diona" = 1, // 12
+ "vampire" = IS_MODE_COMPILED("vampire") // 13
)
var/const/MAX_SAVE_SLOTS = 10
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 027b2c9082a..fd720510e3d 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -168,6 +168,10 @@ Works together with spawning an observer, noted above.
U.client.images += image(tempHud,target,"huddeathsquad")
if("Ninja")
U.client.images += image(tempHud,target,"hudninja")
+ if("Vampire")
+ U.client.images += image(tempHud,target,"vampire")
+ if("VampThrall")
+ U.client.images += image(tempHud,target,"vampthrall")
else//If we don't know what role they have but they have one.
U.client.images += image(tempHud,target,"hudunknown1")
else//If the silicon mob has no law datum, no inherent laws, or a law zero, add them to the hud.
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
index dc4c601a6bf..4d020dedc8f 100644
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ b/code/modules/mob/living/carbon/human/human_attackhand.dm
@@ -90,6 +90,24 @@
if("hurt")
+ //Vampire code
+ if(M.zone_sel && M.zone_sel.selecting == "head" && src != M)
+ if(M.mind && M.mind.vampire && (M.mind in ticker.mode.vampires) && !M.mind.vampire.draining)
+ if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH)))
+ M << "\red Remove their mask!"
+ return 0
+ if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH)))
+ M << "\red Remove your mask!"
+ return 0
+ if(mind && mind.vampire && (mind in ticker.mode.vampires))
+ M << "\red Your fangs fail to pierce [src.name]'s cold flesh"
+ return 0
+ //we're good to suck the blood, blaah
+ M.handle_bloodsucking(src)
+ return
+ //end vampire codes
+
+
M.attack_log += text("\[[time_stamp()]\] [M.species.attack_verb]ed [src.name] ([src.ckey])")
src.attack_log += text("\[[time_stamp()]\] Has been [M.species.attack_verb]ed by [M.name] ([M.ckey])")
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 22c85d1c797..e0838aa2930 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -125,6 +125,9 @@
for(var/obj/item/weapon/grab/G in src)
G.process()
+ if(mind && mind.vampire)
+ handle_vampire_cloak()
+
/mob/living/carbon/human/calculate_affecting_pressure(var/pressure)
..()
@@ -403,6 +406,11 @@
internals.icon_state = "internal0"
return null
+// USED IN DEATHWHISPERS
+ proc/isInCrit()
+ // Health is in deep shit and we're not already dead
+ return health <= 0 && stat != 2
+
proc/handle_breath(datum/gas_mixture/breath)
if(status_flags & GODMODE)
@@ -1222,6 +1230,13 @@
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_ONE
+ if(mind && mind.vampire)
+ if((VAMP_VISION in mind.vampire.powers) && !(VAMP_FULL in mind.vampire.powers))
+ sight |= SEE_MOBS
+ if((VAMP_FULL in mind.vampire.powers))
+ sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
+ see_in_dark = 8
+ if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO
if(XRAY in mutations)
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
see_in_dark = 8
diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm
index ede4b95973b..e8ab1a3f944 100644
--- a/code/modules/mob/living/carbon/human/whisper.dm
+++ b/code/modules/mob/living/carbon/human/whisper.dm
@@ -89,7 +89,7 @@
var/list/heard_a = list() // understood us
var/list/heard_b = list() // didn't understand us
var/and_passes_on=""
- if(!said_last_words)
+ if(!said_last_words && src.isInCrit())
and_passes_on=" - and passes on"
said_last_words=src.stat
@@ -153,6 +153,6 @@
M.show_message(rendered, 2)
if(said_last_words)
src.stat = 2
- src.death()
+ src.death(0)
src.regenerate_icons()
diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm
new file mode 100644
index 00000000000..ed8d291ffdb
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/bat.dm
@@ -0,0 +1,59 @@
+/mob/living/simple_animal/hostile/scarybat
+ name = "space bat"
+ desc = "A cute little blood sucking bat that looks pretty pissed."
+ icon_state = "scarybat"
+ icon_living = "scarybat"
+ icon_dead = "scarybat-dead"
+ icon_gib = "scarybat-dead"
+ speak_chance = 0
+ turns_per_move = 3
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+ response_help = "pets the"
+ response_disarm = "gently pushes aside the"
+ response_harm = "hits the"
+ speed = 4
+ maxHealth = 20
+ health = 20
+
+ harm_intent_damage = 8
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ attacktext = "bites"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ //Space carp aren't affected by atmos.
+ 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
+
+// break_stuff_probability = 2
+
+ faction = "scarybat"
+ var/mob/living/owner
+
+/mob/living/simple_animal/hostile/scarybat/New(loc, mob/living/L as mob)
+ ..()
+ if(istype(L))
+ owner = L
+
+/mob/living/simple_animal/hostile/scarybat/Process_Spacemove(var/check_drift = 0)
+ return ..() //No drifting in space for space carp! //original comments do not steal
+
+/mob/living/simple_animal/hostile/scarybat/FindTarget()
+ . = ..()
+ if(.)
+ emote("flutters towards [.]")
+
+/mob/living/simple_animal/hostile/scarybat/AttackingTarget()
+ . =..()
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(15))
+ L.Stun(1)
+ L.visible_message("\the [src] scares \the [L]!")
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index f8262ce8832..7fa0463c5b3 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -26,6 +26,8 @@
if(isliving(A))
var/mob/living/L = A
+ if(istype(src, /mob/living/simple_animal/hostile/scarybat))
+ if(src:owner == L) continue
if(L.faction == src.faction && !attack_same)
continue
else if(L in friends)
diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm
index 0a072a74fd8..2cfc22ceb8e 100644
--- a/code/modules/reagents/Chemistry-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents.dm
@@ -225,6 +225,14 @@ datum
if(!istype(M, /mob/living))
return
+ // Put out fire
+ if(method == TOUCH)
+ M.adjust_fire_stacks(-(volume / 10))
+ if(M.fire_stacks <= 0)
+ M.ExtinguishMob()
+ return
+
+
// Grays treat water like acid.
if(ishuman(M))
var/mob/living/carbon/human/H = M
@@ -297,14 +305,6 @@ datum
if(!cube.wrapped)
cube.Expand()
return
- reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)//Splashing people with water can help put them out!
- if(!istype(M, /mob/living))
- return
- if(method == TOUCH)
- M.adjust_fire_stacks(-(volume / 10))
- if(M.fire_stacks <= 0)
- M.ExtinguishMob()
- return
lube
name = "Space Lube"
@@ -600,7 +600,39 @@ datum
ticker.mode.remove_cultist(M.mind)
for(var/mob/O in viewers(M, null))
O.show_message(text("\blue []'s eyes blink and become clearer.", M), 1) // So observers know it worked.
+ // Vamps react to this like acid
+ if((M.mind in ticker.mode.vampires) && prob(10))
+ if(!M) M = holder.my_atom
+ M.adjustToxLoss(1*REM)
+ M.take_organ_damage(0, 1*REM)
holder.remove_reagent(src.id, 10 * REAGENTS_METABOLISM) //high metabolism to prevent extended uncult rolls.
+
+
+ reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)//Splashing people with water can help put them out!
+ // Vamps react to this like acid
+ if(ishuman(M))
+ if((M.mind in ticker.mode.vampires))
+ var/mob/living/carbon/human/H=M
+ if(method == TOUCH)
+ if(H.wear_mask)
+ H << "\red Your mask protects you from the holy water!"
+ return
+ if(H.head)
+ H << "\red Your helmet protects you from the holy water!"
+ return
+ if(!M.unacidable)
+ if(prob(15) && volume >= 30)
+ var/datum/organ/external/affecting = H.get_organ("head")
+ if(affecting)
+ if(affecting.take_damage(25, 0))
+ H.UpdateDamageIcon()
+ H.status_flags |= DISFIGURED
+ H.emote("scream")
+ else
+ M.take_organ_damage(min(15, volume * 2)) // uses min() and volume to make sure they aren't being sprayed in trace amounts (1 unit != insta rape) -- Doohl
+ else
+ if(!M.unacidable)
+ M.take_organ_damage(min(15, volume * 2))
return
serotrotium
diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm
index ac5ef88843d..a43ec5bffdd 100644
--- a/code/modules/virus2/disease2.dm
+++ b/code/modules/virus2/disease2.dm
@@ -100,6 +100,8 @@
disease.stageprob = stageprob
disease.antigen = antigen
disease.uniqueID = uniqueID
+ disease.speed = speed
+ disease.stage = stage
for(var/datum/disease2/effectholder/holder in effects)
var/datum/disease2/effectholder/newholder = new /datum/disease2/effectholder
newholder.effect = new holder.effect.type
diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm
index ab17cbc9a67..923b2cf7d0e 100644
--- a/code/modules/virus2/effect.dm
+++ b/code/modules/virus2/effect.dm
@@ -141,7 +141,11 @@
H << "You can't feel your [E.display_name] anymore..."
for (var/datum/organ/external/C in E.children)
C.status |= ORGAN_DEAD
- mob.adjustToxLoss(15*multiplier)
+ H.update_body(1)
+ if(multiplier < 1) multiplier = 1
+ H.adjustToxLoss(10*multiplier)
+ vampire
+ stage = 3
deactivate(var/mob/living/carbon/mob,var/multiplier)
if(istype(mob, /mob/living/carbon/human))
diff --git a/code/setup.dm b/code/setup.dm
index 76357df62b6..38cf78a402c 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -665,6 +665,7 @@ var/list/TAGGERLOCATIONS = list("Disposals",
#define BE_NINJA 1024
#define BE_VOX 2048
#define BE_PLANT 4096
+#define BE_VAMPIRE 8192
var/list/be_special_flags = list(
"Traitor" = BE_TRAITOR,
@@ -679,7 +680,8 @@ var/list/be_special_flags = list(
"Monkey" = BE_MONKEY,
"Ninja" = BE_NINJA,
"Vox" = BE_VOX,
- "Diona" = BE_PLANT
+ "Diona" = BE_PLANT,
+ "Vampire" = BE_VAMPIRE
)
#define AGE_MIN 17 //youngest a character can be
@@ -771,4 +773,18 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse
//Flags for zone sleeping
#define ZONE_ACTIVE 1
-#define ZONE_SLEEPING 0
\ No newline at end of file
+#define ZONE_SLEEPING 0
+
+// Vampire power defines
+#define VAMP_REJUV 1
+#define VAMP_GLARE 2
+#define VAMP_HYPNO 3
+#define VAMP_SHAPE 4
+#define VAMP_VISION 5
+#define VAMP_DISEASE 6
+#define VAMP_CLOAK 7
+#define VAMP_BATS 8
+#define VAMP_SCREAM 9
+#define VAMP_JAUNT 10
+#define VAMP_SLAVE 11
+#define VAMP_FULL 12
\ No newline at end of file
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index f249d5ce6ff..29c366ecab0 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/bats.dmi b/icons/mob/bats.dmi
new file mode 100644
index 00000000000..74466935077
Binary files /dev/null and b/icons/mob/bats.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index 9853c592755..75235912414 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 4d16add44d2..0d588a9c0a6 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/sound/effects/creepyshriek.ogg b/sound/effects/creepyshriek.ogg
new file mode 100644
index 00000000000..86933130d5d
Binary files /dev/null and b/sound/effects/creepyshriek.ogg differ