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