diff --git a/code/game/gamemodes/cult/blood_magic.dm b/code/game/gamemodes/cult/blood_magic.dm index 8f3285653a9..8c63827e308 100644 --- a/code/game/gamemodes/cult/blood_magic.dm +++ b/code/game/gamemodes/cult/blood_magic.dm @@ -735,148 +735,161 @@ . += "Blood orb and blood empower cost [BLOOD_ORB_COST] and [BLOOD_RECHARGE_COST] charges respectively." . += "You have collected [uses] charge\s of blood." +/obj/item/melee/blood_magic/manipulator/proc/restore_blood(mob/living/carbon/human/user, mob/living/carbon/human/H) + if(uses == 0) + return + if(!H.dna || (NO_BLOOD in H.dna.species.species_traits) || !isnull(H.dna.species.exotic_blood)) + return + if(H.blood_volume >= BLOOD_VOLUME_SAFE) + return + var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume + if(uses * 2 < restore_blood) + H.blood_volume += uses * 2 + to_chat(user, "You use the last of your charges to restore what blood you could, and the spell dissipates!") + uses = 0 + else + H.blood_volume = BLOOD_VOLUME_SAFE + uses -= round(restore_blood / 2) + to_chat(user, "Your blood rites have restored [H == user ? "your" : "[H.p_their()]"] blood to safe levels!") + +/obj/item/melee/blood_magic/manipulator/proc/heal_human_damage(mob/living/carbon/human/user, mob/living/carbon/human/H) + if(uses == 0) + return + var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss() + if(overall_damage == 0) + to_chat(user, "[H] doesn't require healing!") + return + + var/ratio = uses / overall_damage + if(H == user) + to_chat(user, "Your blood healing is far less efficient when used on yourself!") + ratio *= 0.35 // Healing is half as effective if you can't perform a full heal + uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal + if(ratio > 1) + ratio = 1 + uses -= round(overall_damage) + H.visible_message("[H] is fully healed by [H == user ? "[H.p_their()]" : "[H]'s"] blood magic!", + "You are fully healed by [H == user ? "your" : "[user]'s"] blood magic!") + else + H.visible_message("[H] is partially healed by [H == user ? "[H.p_their()]" : "[H]'s"] blood magic.", + "You are partially healed by [H == user ? "your" : "[user]'s"] blood magic.") + uses = 0 + ratio *= -1 + H.adjustOxyLoss((overall_damage * ratio) * (H.getOxyLoss() / overall_damage), FALSE, null, TRUE) + H.adjustToxLoss((overall_damage * ratio) * (H.getToxLoss() / overall_damage), FALSE, null, TRUE) + H.adjustFireLoss((overall_damage * ratio) * (H.getFireLoss() / overall_damage), FALSE, null, TRUE) + H.adjustBruteLoss((overall_damage * ratio) * (H.getBruteLoss() / overall_damage), FALSE, null, TRUE) + H.updatehealth() + playsound(get_turf(H), 'sound/magic/staff_healing.ogg', 25) + new /obj/effect/temp_visual/cult/sparks(get_turf(H)) + user.Beam(H, icon_state="sendbeam", time = 15) + +/obj/item/melee/blood_magic/manipulator/proc/heal_cultist(mob/living/carbon/human/user, mob/living/carbon/human/H) + if(H.stat == DEAD) + to_chat(user, "Only a revive rune can bring back the dead!") + return + var/charge_loss = uses + restore_blood(user, H) + heal_human_damage(user, H) + charge_loss = charge_loss - uses + if(!uses) + to_chat(user, "You use the last of your charges to heal [H == user ? "yourself" : "[H]"], and the spell dissipates!") + else + to_chat(user, "You use [charge_loss] charge\s, and have [uses] remaining.") + +/obj/item/melee/blood_magic/manipulator/proc/heal_construct(mob/living/carbon/human/user, mob/living/simple_animal/M) + if(uses == 0) + return + var/missing = M.maxHealth - M.health + if(!missing) + to_chat(user, "[M] doesn't require healing!") + return + if(uses > missing) + M.adjustHealth(-missing) + M.visible_message("[M] is fully healed by [user]'s blood magic!", + "You are fully healed by [user]'s blood magic!") + uses -= missing + else + M.adjustHealth(-uses) + M.visible_message("[M] is partially healed by [user]'s blood magic!", + "You are partially healed by [user]'s blood magic.") + uses = 0 + playsound(get_turf(M), 'sound/magic/staff_healing.ogg', 25) + user.Beam(M, icon_state = "sendbeam", time = 10) + +/obj/item/melee/blood_magic/manipulator/proc/steal_blood(mob/living/carbon/human/user, mob/living/carbon/human/H) + if(H.stat == DEAD) + to_chat(user, "[H.p_their(TRUE)] blood has stopped flowing, you'll have to find another way to extract it.") + return + if(H.AmountCultSlurring()) + to_chat(user, "[H.p_their(TRUE)] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!") + return + if(!H.dna || (NO_BLOOD in H.dna.species.species_traits) || H.dna.species.exotic_blood != null) + to_chat(user, "[H] does not have any usable blood!") + return + if(H.blood_volume <= BLOOD_VOLUME_SAFE) + to_chat(user, "[H] is missing too much blood - you cannot drain [H.p_them()] further!") + return + H.blood_volume -= 100 + uses += 50 + user.Beam(H, icon_state = "drainbeam", time = 10) + playsound(get_turf(H), 'sound/misc/enter_blood.ogg', 50) + H.visible_message("[user] has drained some of [H]'s blood!", + "[user] has drained some of your blood!") + to_chat(user, "Your blood rite gains 50 charges from draining [H]'s blood.") + new /obj/effect/temp_visual/cult/sparks(get_turf(H)) + // This should really be split into multiple procs /obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity) if(user.holy_check()) return - if(proximity) - if(ishuman(target)) - var/mob/living/carbon/human/H = target + if(!proximity) + return ..() + if(ishuman(target)) + if(iscultist(target)) + heal_cultist(user, target) + target.clean_blood() + else + steal_blood(user, target) + return - //Healing a cultist - if(iscultist(H)) - var/charge_loss = uses // Before/after charge difference - if(H.stat == DEAD) - to_chat(user, "Only a revive rune can bring back the dead!") - return + if(isconstruct(target)) + heal_construct(user, target) + return - //Blood restoration - if(H.dna && !(NO_BLOOD in H.dna.species.species_traits) && H.dna.species.exotic_blood == null) - if(H.blood_volume < BLOOD_VOLUME_SAFE) - var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume - if(uses * 2 < restore_blood) - H.blood_volume += uses * 2 - to_chat(user, "You use the last of your charges to restore what blood you could, and the spell dissipates!") - uses = 0 - return ..() - else - H.blood_volume = BLOOD_VOLUME_SAFE - uses -= round(restore_blood / 2) - to_chat(user, "Your blood rites have restored [H == user ? "your" : "[H.p_their()]"] blood to safe levels!") - - //Damage healing - var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss() - if(overall_damage == 0) - to_chat(user, "That cultist doesn't require healing!") - return - else - var/ratio = uses / overall_damage - if(H == user) - to_chat(user, "Your blood healing is far less efficient when used on yourself!") - ratio *= 0.35 // Healing is half as effective if you can't perform a full heal - uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal - if(ratio > 1) - ratio = 1 - uses -= round(overall_damage) - H.visible_message("[H] is fully healed by [H == user ? "[H.p_their()]" : "[H]'s"] blood magic!", - "You are fully healed by [H == user ? "your" : "[user]'s"] blood magic!") - else - H.visible_message("[H] is partially healed by [H == user ? "[H.p_their()]" : "[H]'s"] blood magic.", - "You are partially healed by [H == user ? "your" : "[user]'s"] blood magic.") - uses = 0 - ratio *= -1 - H.adjustOxyLoss((overall_damage * ratio) * (H.getOxyLoss() / overall_damage), FALSE, null, TRUE) - H.adjustToxLoss((overall_damage * ratio) * (H.getToxLoss() / overall_damage), FALSE, null, TRUE) - H.adjustFireLoss((overall_damage * ratio) * (H.getFireLoss() / overall_damage), FALSE, null, TRUE) - H.adjustBruteLoss((overall_damage * ratio) * (H.getBruteLoss() / overall_damage), FALSE, null, TRUE) - H.updatehealth() - playsound(get_turf(H), 'sound/magic/staff_healing.ogg', 25) - new /obj/effect/temp_visual/cult/sparks(get_turf(H)) - user.Beam(H, icon_state="sendbeam", time = 15) - - charge_loss = charge_loss - uses - if(!uses) - to_chat(user, "You use the last of your charges to heal [H == user ? "yourself" : "[H]"], and the spell dissipates!") - else - to_chat(user, "You use [charge_loss] charge\s, and have [uses] remaining.") - - //Draining blood from non-cultists - else - if(H.stat == DEAD) - to_chat(user, "[H.p_their(TRUE)] blood has stopped flowing, you'll have to find another way to extract it.") - return - if(H.AmountCultSlurring()) - to_chat(user, "[H.p_their(TRUE)] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!") - return - if(H.dna && !(NO_BLOOD in H.dna.species.species_traits) && H.dna.species.exotic_blood == null) - if(H.blood_volume > BLOOD_VOLUME_SAFE) - H.blood_volume -= 100 - uses += 50 - user.Beam(H, icon_state = "drainbeam", time = 10) - playsound(get_turf(H), 'sound/misc/enter_blood.ogg', 50) - H.visible_message("[user] has drained some of [H]'s blood!", - "[user] has drained some of your blood!") - to_chat(user, "Your blood rite gains 50 charges from draining [H]'s blood.") - new /obj/effect/temp_visual/cult/sparks(get_turf(H)) - else - to_chat(user, "[H] is missing too much blood - you cannot drain [H.p_them()] further!") - return - else - to_chat(user, "[H] does not have any usable blood!") - return - - //Healing constructs - if(isconstruct(target)) - var/mob/living/simple_animal/M = target - var/missing = M.maxHealth - M.health - if(missing) - if(uses > missing) - M.adjustHealth(-missing) - M.visible_message("[M] is fully healed by [user]'s blood magic!", - "You are fully healed by [user]'s blood magic!") - uses -= missing - else - M.adjustHealth(-uses) - M.visible_message("[M] is partially healed by [user]'s blood magic!", - "You are partially healed by [user]'s blood magic.") - uses = 0 - playsound(get_turf(M), 'sound/magic/staff_healing.ogg', 25) - user.Beam(M, icon_state = "sendbeam", time = 10) - - //Draining blood on the floor - if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder)) - blood_draw(target, user) - if(istype(target, /obj/item/blood_orb)) - var/obj/item/blood_orb/candidate = target - if(candidate.blood) - uses += candidate.blood - to_chat(user, "You obtain [candidate.blood] blood from the orb of blood!") - playsound(user, 'sound/misc/enter_blood.ogg', 50) - qdel(candidate) - - ..() + if(istype(target, /obj/item/blood_orb)) + var/obj/item/blood_orb/candidate = target + if(candidate.blood) + uses += candidate.blood + to_chat(user, "You obtain [candidate.blood] blood from the orb of blood!") + playsound(user, 'sound/misc/enter_blood.ogg', 50) + qdel(candidate) + return + blood_draw(target, user) /obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) var/temp = 0 var/turf/T = get_turf(target) - if(T) - for(var/obj/effect/decal/cleanable/blood/B in view(T, 2)) - if(B.blood_state == BLOOD_STATE_HUMAN && (B.can_bloodcrawl_in() || istype(B, /obj/effect/decal/cleanable/blood/slime))) - if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam - temp += 30 - else - temp += max((B.bloodiness ** 2) / 800, 1) - new /obj/effect/temp_visual/cult/turf/open/floor(get_turf(B)) - qdel(B) - for(var/obj/effect/decal/cleanable/trail_holder/TH in view(T, 2)) - qdel(TH) - if(temp) - user.Beam(T, icon_state = "drainbeam", time = 15) - new /obj/effect/temp_visual/cult/sparks(get_turf(user)) - playsound(T, 'sound/misc/enter_blood.ogg', 50) - temp = round(temp) - to_chat(user, "Your blood rite has gained [temp] charge\s from blood sources around you!") - uses += max(1, temp) + if(!T) + return + for(var/obj/effect/decal/cleanable/blood/B in range(T, 2)) + if(B.blood_state == BLOOD_STATE_HUMAN && (B.can_bloodcrawl_in() || istype(B, /obj/effect/decal/cleanable/blood/slime))) + if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam + temp += 30 + else + temp += max((B.bloodiness ** 2) / 800, 1) + new /obj/effect/temp_visual/cult/turf/open/floor(get_turf(B)) + qdel(B) + for(var/obj/effect/decal/cleanable/trail_holder/TH in range(T, 2)) + new /obj/effect/temp_visual/cult/turf/open/floor(get_turf(TH)) + qdel(TH) + if(temp) + user.Beam(T, icon_state = "drainbeam", time = 15) + new /obj/effect/temp_visual/cult/sparks(get_turf(user)) + playsound(T, 'sound/misc/enter_blood.ogg', 50) + temp = round(temp) + to_chat(user, "Your blood rite has gained [temp] charge\s from blood sources around you!") + uses += max(1, temp) /obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user) if(user.holy_check())