From 02ea2b5f7527c08e0866de5b8599416d9724923b Mon Sep 17 00:00:00 2001 From: Marmio Date: Tue, 23 May 2023 17:51:40 -0500 Subject: [PATCH 01/38] hecata clan --- code/__DEFINES/bloodsuckers.dm | 5 +- .../bloodsuckers/bloodsucker_flaws.dm | 23 ++ .../bloodsuckers/bloodsucker_mobs.dm | 43 ++++ .../bloodsuckers/bloodsucker_objectives.dm | 21 ++ .../antagonists/bloodsuckers/powers/feed.dm | 6 + .../bloodsuckers/powers/targeted/hecata.dm | 202 ++++++++++++++++++ .../carbon/human/species_types/zombies.dm | 23 ++ .../actions/actions_hecata_bloodsucker.dmi | Bin 0 -> 4213 bytes icons/mob/bloodsucker_mobs.dmi | Bin 7441 -> 23118 bytes yogstation.dme | 1 + 10 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm create mode 100644 icons/mob/actions/actions_hecata_bloodsucker.dmi diff --git a/code/__DEFINES/bloodsuckers.dm b/code/__DEFINES/bloodsuckers.dm index d8be795f7d80..64e0bf842f59 100644 --- a/code/__DEFINES/bloodsuckers.dm +++ b/code/__DEFINES/bloodsuckers.dm @@ -37,6 +37,7 @@ #define CLAN_GANGREL "Gangrel Clan" #define CLAN_LASOMBRA "Lasombra Clan" #define CLAN_TZIMISCE "Tzimisce Clan" +#define CLAN_HECATA "Hecata Clan" #define TRIPLECHEST_MONSTER "Triple Chest (300 Blood)" #define ARMMY_MONSTER "Armmy (100 Blood)" @@ -70,6 +71,8 @@ #define HUNTER_CAN_BUY (1<<4) /// This Power can be purchased by Tzimisce Bloodsuckers #define TZIMISCE_CAN_BUY (1<<5) +/// This Power can be purchased by Hecata Bloodsuckers +#define HECATA_CAN_BUY (1<<6) /// This Power is a Toggled Power #define BP_AM_TOGGLE (1<<0) @@ -82,4 +85,4 @@ // Signals -#define COMSIG_BLOODSUCKER_RANKS_SPENT \ No newline at end of file +#define COMSIG_BLOODSUCKER_RANKS_SPENT diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm index f3f21fcc52e3..e5ca074ef01c 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm @@ -23,6 +23,7 @@ CLAN_GANGREL, CLAN_LASOMBRA, CLAN_TOREADOR, + CLAN_HECATA, ) var/list/options = list() options = clans @@ -96,5 +97,27 @@ continue masquarade_spell.bloodcost = 0 masquarade_spell.constant_bloodcost = 0 //Wow very cool code, good job + if(CLAN_HECATA) + my_clan = CLAN_HECATA + to_chat(owner, span_announce("You have Ranked up enough to learn: You are part of the Hecata Clan!\n\ + * As part of the Hecata clan, you are an avid practioner of necromancy.\n\ + * You are capable of raising the dead as zombies, making them into temporary vassals loyal to you. Dead vassals are instead permanently revived\n\ + * You can also call for help from the beyond by summong wraiths.\n\ + * You can also call for help from the beyond by summoning wraiths.\n\ + * In addition, you can send messages to all your vassals no matter their location via Deathly Communion.\n\ + * However, feeding on people causes them deep pain, making it impossible to feed silently.\n\ + * You also are unable to use the blood altar in order to gain tasks for ranks.\n\ + * Finally, your Favorite Vassal will transform into a zombie if they weren't one already, and gain the Spirit Call ability.")) + BuyPower(new /datum/action/bloodsucker/targeted/hecata/necromancy) + BuyPower(new /datum/action/bloodsucker/hecata/spiritcall) + BuyPower(new /datum/action/bloodsucker/hecata/communion) + bloodsucker.faction |= "bloodhungry" + var/datum/objective/bloodsucker/necromance/hecata_objective = new + hecata_objective.owner = owner + objectives += hecata_objective + for(var/datum/action/bloodsucker/feed/feed_spell in powers) + if(!istype(feed_spell)) + continue + feed_spell.suppressible = 0 owner.announce_objectives() diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm index 9bf707dac7e3..5498986ca9cf 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm @@ -262,3 +262,46 @@ else new /obj/structure/bloodsucker/possessedarmor(src.loc) qdel(src) + +//Wraith - Hecata mob + +/mob/living/simple_animal/hostile/bloodsucker/wraith + name = "wraith" + real_name = "Wraith" + desc = "An angry, tormented spirit, which looks to let out it's wrath on whoever is nearby." + gender = PLURAL + icon_state = "wraith" + icon_living = "wraith" + mob_biotypes = list(MOB_SPIRIT) + maxHealth = 30 + health = 30 + spacewalk = TRUE + healable = 0 + speak_emote = list("hisses") + emote_hear = list("wails.","screeches.") + response_help = "puts their hand through" + response_disarm = "flails at" + response_harm = "punches" + speak_chance = 1 + melee_damage_lower = 6 + melee_damage_upper = 6 + attacktext = "torments" + minbodytemp = 0 + maxbodytemp = INFINITY + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + status_flags = 0 + status_flags = CANPUSH + movement_type = FLYING + loot = list(/obj/item/ectoplasm) + +/mob/living/simple_animal/hostile/bloodsucker/wraith/Life() + . = ..() + if(!src) + return + if(src.stat != DEAD) //Wraith loses 1 health every 2 seconds, which means it will disperse after 60 seconds if not damaged. + adjustHealth(1) + +/mob/living/simple_animal/hostile/bloodsucker/wraith/death() + deathmessage = "withers away into nothing." + qdel(src) //Del on death for some reason doesn't work, might be due to previous code preventing it for /bloodsucker mobs. + ..() diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm index 646a07bd6097..ff600ca26ede 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm @@ -384,6 +384,27 @@ return TRUE return FALSE +/// Necromance X amount of people (Hecata) +/datum/objective/bloodsucker/necromance + name = "necromance" + +/datum/objective/bloodsucker/necromance/New() + target_amount = rand(6,8) + ..() + + +/datum/objective/bloodsucker/necromance/update_explanation_text() + . = ..() + explanation_text = "Using Necromancy, revive people [target_amount] times." + +/datum/objective/bloodsucker/necromance/check_completion() + var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.current.mind.has_antag_datum(/datum/antagonist/bloodsucker) + if(!bloodsuckerdatum) + return FALSE + if(bloodsuckerdatum.clanprogress >= target_amount) + return TRUE + return FALSE + ////////////////////////////////////////////////////////////////////////////////////// /// Mutilate a certain amount of Vassals diff --git a/code/modules/antagonists/bloodsuckers/powers/feed.dm b/code/modules/antagonists/bloodsuckers/powers/feed.dm index 123116cad0bc..6635582bd1e7 100644 --- a/code/modules/antagonists/bloodsuckers/powers/feed.dm +++ b/code/modules/antagonists/bloodsuckers/powers/feed.dm @@ -40,6 +40,8 @@ var/warning_full = FALSE var/warning_target_bloodvol = 99999 var/was_alive = FALSE + //can you silently feed? Hecata can't. + var/suppressible = 1 /datum/action/bloodsucker/feed/CheckCanUse(mob/living/carbon/user) . = ..() @@ -78,6 +80,10 @@ if(IS_BLOODSUCKER(target) && target == owner.pulling && owner.grab_state <= GRAB_PASSIVE) to_chat(owner, span_warning("Other Bloodsuckers will not fall for your subtle approach.")) return FALSE + // As Hecata, you can't feed off of anyone if they aren't grabbed more than Passively. + if(suppressible == 0 && owner.grab_state <= GRAB_PASSIVE) + to_chat(owner, span_warning("Feeding as a Hecata would cause enough pain to the victim to make silent feeding like this impossible.")) + return FALSE if(ishuman(target)) var/mob/living/carbon/human/target_user = target if(!target_user.can_inject(owner, BODY_ZONE_HEAD, 1) && target == owner.pulling && owner.grab_state < GRAB_AGGRESSIVE) diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm new file mode 100644 index 000000000000..2be6b1ad7b57 --- /dev/null +++ b/code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm @@ -0,0 +1,202 @@ +//Hecata, the unified clan of death. +//Focuses more on their vassals than other clans. +//Has to rely more on vassals for ranks and blood, as they cannot use the blood altar for leveling up and cannot silent feed. +//In exchange, they can raise the dead as temporary vassals to do their bidding, or permanently revive dead existing vassals. +//In addition, they can summon Wraiths (shades) around them for both offense and defense +//And can send messages to vassals anywhere globally via Dark Communion. +//In addition, raising the dead with Necromancy turns them into Sanguine Zombies +//They are pseudo zombies, which have high punch damage and special resistances, but aren't infectious nor can they use guns. +/datum/action/bloodsucker/targeted/hecata + purchase_flags = HECATA_CAN_BUY + button_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' + icon_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' + background_icon_state = "hecata_power_off" + background_icon_state_on = "hecata_power_on" + background_icon_state_off = "hecata_power_off" +/datum/action/bloodsucker/targeted/hecata/necromancy + name = "Necromancy" + level_current = 1 + button_icon_state = "power_necromancy" + desc = "Raise the dead as temporary vassals, or revive a dead vassal as a zombie permanently. Temporary vassals last longer as this ability ranks up." + power_explanation = "Necromancy:\n\ + Click on a corpse in order to attempt to resurrect them.\n\ + Non-vassals will become temporary zombies that will follow your orders. Dead vassals are also turned, but last permanently.\n\ + Temporary vassals tend to not last long, their form quickly falling apart, make sure you set them out to do what you want as soon as possible.\n\ + Vassaling people this way does not grant ranks. In addition, after their time is up they will die and no longer be your vassal." + check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_UNCONSCIOUS + power_flags = BP_AM_STATIC_COOLDOWN + bloodcost = 35 + cooldown = 45 SECONDS + target_range = 1 + prefire_message = "Select a target." + +/datum/action/bloodsucker/targeted/hecata/necromancy/CheckValidTarget(atom/target_atom) + . = ..() + if(!.) + return FALSE + return isliving(target_atom) +/datum/action/bloodsucker/targeted/hecata/necromancy/CheckCanTarget(atom/target_atom) + . = ..() + if(!.) + return FALSE + var/mob/living/current_target = target_atom // We already know it's carbon due to CheckValidTarget() + // No mind + if(!current_target.mind) + to_chat(owner, span_warning("[current_target] is mindless.")) + return FALSE + // Bloodsucker + if(IS_BLOODSUCKER(current_target)) + to_chat(owner, span_notice("Bloodsuckers are immune to [src].")) + return FALSE + // Alive + if(current_target.stat != DEAD) + to_chat(owner, "[current_target] is still alive.") + return FALSE + return TRUE +/datum/action/bloodsucker/targeted/hecata/necromancy/FireTargetedPower(atom/target_atom) + . = ..() + var/mob/living/target = target_atom + var/mob/living/user = owner + var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker) + if(target.stat == DEAD && user.Adjacent(target)) + owner.balloon_alert(owner, "attempting to revive...") + if(!do_mob(user, target, 6 SECONDS, NONE, TRUE)) + return FALSE + if(IS_VASSAL(target)) + PowerActivatedSuccessfully() + to_chat(user, span_warning("We revive [target]!")) + zombify(target) + bloodsuckerdatum.clanprogress++ //counts a succesful necromancy towards your objective progress + DeactivatePower() + return + if(IS_MONSTERHUNTER(target)) + to_chat(target, span_notice("Their body refuses to react...")) + DeactivatePower() + return + if(!bloodsuckerdatum_power.attempt_turn_vassal(target, TRUE)) + return FALSE + zombify(target) + PowerActivatedSuccessfully() + bloodsuckerdatum.clanprogress++ //counts a succesful necromancy towards your objective progress + to_chat(user, span_warning("We revive [target]!")) + var/living_time + if(level_current == 1) + living_time = 5 MINUTES + else if(level_current == 2) + living_time = 8 MINUTES + else if(level_current == 3) + living_time = 12 MINUTES + else if(level_current >= 4) + living_time = 15 MINUTES //in general, they don't last long, make the most of them. + addtimer(CALLBACK(src, PROC_REF(end_necromance), target), living_time) + else //extra check, but this shouldn't happen + owner.balloon_alert(owner, "Target is out of range or not dead yet.") + return FALSE + DeactivatePower() + +/datum/action/bloodsucker/targeted/hecata/necromancy/proc/end_necromance(mob/living/user) + user.mind.remove_antag_datum(/datum/antagonist/vassal) + to_chat(user, span_warning("You feel the shadows around you weaken, your form falling limp like a puppet cut from its strings!")) + user.set_species(/datum/species/krokodil_addict) //they will turn into a fake zombie on death, that still retains blood and isnt so powerful. + user.death() +/datum/action/bloodsucker/targeted/hecata/necromancy/proc/zombify(mob/living/user) + user.mind.grab_ghost() + user.revive(full_heal = TRUE, admin_revive = TRUE) + user.set_species(/datum/species/zombie/hecata) //imitation zombies that shamble around and beat people with their fists + user.visible_message(span_danger("[user] suddenly convulses, as [user.p_they()] stagger to their feet and gain a ravenous hunger in [user.p_their()] eyes!"), span_alien("You RISE!")) + playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) + to_chat(user, span_warning("Your broken form is picked up by strange shadows. If you were previously not a vassal, it is unlikely these shadows will be strong enough to keep you going for very long.")) + to_chat(user, span_notice("You are resilient to many things like the vacuum of space, can punch harder, and can take more damage before dropping. However, you are unable to use guns and are slower.")) +/datum/action/bloodsucker/hecata + purchase_flags = HECATA_CAN_BUY + button_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' + icon_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' + background_icon_state = "hecata_power_off" + background_icon_state_on = "hecata_power_on" + background_icon_state_off = "hecata_power_off" +//summon wraiths (weakened shades) to attack anyone who isn't a zombie. This includes non-zombified vassals. However, you can get around this by zombifying your vassals. +//to do this, you can make someone your favorite vassal, or you can kill them and then revive them with necromancy. +/datum/action/bloodsucker/hecata/spiritcall + name = "Spirit Call" + level_current = 1 + desc = "Summon two angry wraiths which will attack anyone whose flesh is still alive. Summon amount increases as this ability levels up." + button_icon_state = "power_spiritcall" + power_explanation = "Spirit Call:\n\ + Summon angry wraiths which enact vengeance from beyond the grave on those still connected to this world.\n\ + Note, that includes any of your vassals who are not undead, as wraiths will seek to kill them too!\n\ + Summons more wraiths as this ability ranks up.\n\ + These wraiths aren't very powerful, and best serve as a distraction, but in a pinch can help in a fight. \n\ + The spirits will eventually return back to their realm if not otherwise destroyed." + check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_UNCONSCIOUS + power_flags = BP_AM_STATIC_COOLDOWN + bloodcost = 15 + cooldown = 60 SECONDS + var/num_spirits = 2 +/datum/action/bloodsucker/hecata/spiritcall/vassal //this variant has to exist, as hecata favorite vassals are technically in 'torpor' + check_flags = BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS +/datum/action/bloodsucker/hecata/spiritcall/ActivatePower(mob/user = usr) + . = ..() + if(level_current == 2) + num_spirits = 3 + else if(level_current >= 3) + num_spirits = 4 + var/list/turf/locs = new + for(var/direction in GLOB.alldirs) //looking for spirit spawns + if(locs.len == num_spirits) //we found the number of spots needed and thats all we need + break + var/turf/T = get_step(usr, direction) //getting a loc in that direction + if(AStar(user, T, /turf/proc/Distance, 1, simulated_only = 0)) // if a path exists, so no dense objects in the way its valid salid + locs += T + // pad with player location + for(var/i = locs.len + 1 to num_spirits) + locs += user.loc + summonWraiths(locs, user = user) + cast_effect() // POOF + DeactivatePower() + +/datum/action/bloodsucker/hecata/spiritcall/proc/summonWraiths(list/targets, mob/user = usr) + for(var/T in targets) + new /mob/living/simple_animal/hostile/bloodsucker/wraith(T) +/datum/action/bloodsucker/hecata/spiritcall/proc/cast_effect() //same as veil of many faces, makes smoke and stuff when casted + // Effect + playsound(get_turf(owner), 'sound/magic/smoke.ogg', 20, 1) + var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread/() + puff.effect_type = /obj/effect/particle_effect/fluid/smoke/vampsmoke + puff.set_up(3, 0, get_turf(owner)) + puff.attach(owner) //OPTIONAL + puff.start() + owner.spin(8, 1) //Spin around like a loon. +/datum/action/bloodsucker/hecata/communion + name = "Deathly Communion" + level_current = 1 + desc = "Send a message to all your vassals." + button_icon_state = "power_communion" + power_explanation = "Deathly Communion:\n\ + Send a message directly to all vassals under your control, temporary or permanent.\n\ + They will not be able to respond to you through any supernatural means in the way you can.\n\ + Note, nearby humans can hear you talk when using this.\n\ + The cooldown of Communion will decrease as it levels up." + check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY + power_flags = NONE + bloodcost = 8 + cooldown = 30 SECONDS +/datum/action/bloodsucker/hecata/communion/ActivatePower() + . = ..() + var/input = stripped_input(usr, "Choose a message to tell your vassals.", "Voice of Blood", "") + if(!input || !IsAvailable()) + return FALSE + deathly_commune(usr, input) +/datum/action/bloodsucker/hecata/communion/proc/deathly_commune(mob/living/user, message) //code from Fulpstation + var/rendered = span_cultlarge("Master [user.real_name] announces: [message]") + user.log_talk(message, LOG_SAY, tag=ROLE_BLOODSUCKER) + var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker) + for(var/datum/antagonist/vassal/receiver as anything in bloodsuckerdatum.vassals) + if(!receiver.owner.current) + continue + var/mob/receiver_mob = receiver.owner.current + to_chat(receiver_mob, rendered) + to_chat(user, rendered) // tell yourself, too. + for(var/mob/dead_mob in GLOB.dead_mob_list) + var/link = FOLLOW_LINK(dead_mob, user) + to_chat(dead_mob, "[link] [rendered]") + DeactivatePower() diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 92841032dd5e..5e4bcf74c70a 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -121,6 +121,29 @@ mutanttongue = /obj/item/organ/tongue/zombie changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN +//Hecata necromancy bloodsucker zombie. Kind of like a weakened Szlachta that can also wear clothes still +/datum/species/zombie/hecata + name = "Sanguine Zombie" + id = "hecatazombie" + limbs_id = "zombie" + say_mod = "moans" + brutemod = 1.1 + burnmod = 1.25 //more fragile, though they also dont enter soft crit + brutemod = 1.1 //more fragile, though they also dont enter soft crit. No burn weakness since sanguine recuperation wont heal it. + speedmod = 0.33 //slightly slower + stunmod = 0.5 + staminamod = 0.5 //difficult to subdue via nonlethal means + punchdamagelow = 13 + punchdamagehigh = 16 + punchstunthreshold = 17 //pretty good punch damage but no knockdown + inherent_traits = list(TRAIT_STABLELIVER, TRAIT_STABLEHEART, TRAIT_RESISTCOLD ,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_EASILY_WOUNDED,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH, TRAIT_NOGUNS, TRAIT_NOSOFTCRIT) //no guns or soft crit + changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN +/datum/species/zombie/hecata/on_species_gain(mob/living/carbon/C, datum/species/old_species) + . = ..() + C.faction |= "bloodhungry" +/datum/species/zombie/hecata/on_species_loss(mob/living/carbon/C) + . = ..() + //The special zombie you get turned into in the zombie gamemode /datum/species/zombie/infectious/gamemode armor = 20 diff --git a/icons/mob/actions/actions_hecata_bloodsucker.dmi b/icons/mob/actions/actions_hecata_bloodsucker.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0c58b842c153fe21ca5d619dde3e336c7b9ccb69 GIT binary patch literal 4213 zcma)Ac{tSF+yBl?vSlm{W1FlcOpSe+FhiCh+4m=uJctJ)`!Z(iQL-e7vJ6ifg(QiX zNVYH<(#kNl$)0tX_)YJ1{oa4xf8IYn=RVgt_qp%0+~;$j>tx#5SP1Y*@&N!KV2Lwz z;7HOR@Eqopoko}XIpSrUlUs!8-{F_9UcpCP2@L^&n0skA-|(fV!P4fYl~2D;pR)ag zG*gD|@`+3}@)nuqznJ zx7wn&$3stqFPDa2ZM(I;cYnfgZt-`Bct$4(z!^(Ph_80U*UK7U_XRkTJ!Hq#Og|X<;~}n!&zB%%+H_Xk(*y=Ar-Fs z=c@m$GI&28&SF(3rwokm=g?7pbEhR~LWq9=y|^9yg!Qu8y5(WdfY1YQp5Df+F1jdZ z+vV0bR~Ind&)H^Q) z_x4n;ly>ENonJ>5ZUh$pS|^7k`vQ9Lvsw>q?(^lefJ$Y46nXDxUbvs%Fl$75qvhrhSN!-I9KU%2H~P^MI2(5Pqy&2as%-`ar~ zD3(PmyPMhD+k5iG7ubv;bCc}vdnoi}Qw{_E&87We67oWX0&?!FIz38WSzEwg(=X^{ ziCsR%y(mxf68Ixh%vl})q+3l{+6Y9?A$(<*#{Gud)CWs(WH+Q9xLR ztjNhEMt55$B079Qb&R#-7PqcRN_+e8lhZYC7b^y_E>IVsQi&A&(cijt+JF`I3%YDZuRgy+PcL`L|0OO+GR3^DBJ@fI|*J1)W!F| zW8L#v3^W+{t`8y>3PwZ#;!>iAVK>0Gi^nKBbN#^kV=9qexKUr>op;Ni&-aJ2CnpqA zFd?4+wmb6POg3BM7&fqcaI8b)u5kH8{q3+BBa@F(2k2QlCVg`K`Pb3wn0X+Phyi}f z12ckf(2gddyz=sgBXDz2BI39|rc22d)zOzHtc3`D$DZ!hTf%@SPxNxc*kMOOq&3yO z=pGpqi0q;HuU@m>}O`xdw7D;}`b5g?84oK;ExXa50trPmHc$s=0%YaYsruBR!z4=#sw$utPl8F|8yJiaxcUBq8^ zOG`tpI(wY(_>%puG1?Fi3f)I4#(vj}-I8~VnE_w@wP@D$x>|=w1-d?fBW9*pBlIBK!b#ZR<02b?P?`V`&^?_uS){`C2s zKkHEZ5`6SHt6QHk>Y|#?%WF<@{ShMJ$#tx+kI&2BwuqGS|Jn@9YF$-V2fcFp6MZNtsne=kwfR@-; z_n5FCOW74AZtC@k2!P~<)CI5?bK7{`!-n?0;eY!q+bixG>W$8T#2vQ?jNx1lLy~4z z?m64U&NBevWP#seEKv#w!4iy6H7-)l^k>2}e98LiU%-1Fy`*}18}v@xx|GBb0*1tU zS^jl*h_xcpnp;ipznJO+si?ecHzAtbPJ68*EJ2O}9qcno=}}8<{wqEK(@{@kr+qC23vKKS1!+UD;lch@}il)Jg&i-DdFX{@uR1 zRH&m*5PHM^%Et!XoVcc;cBGR@lZio8Lg1G$;W+-Vnq@Y{4FdGI$iuE1Q$7b@%@)Mr zfhV>P$M#WWrgM;5#^Oe=!=8{UoAmr}F4$`Wf7_a8ns}xXcEgVJKy+0xnj?e2_DCy-d(h zFlC28U6hu6Wb3b+-;u1V`>bR8Nt#cNy`LXIrQV}f<7E^T0=elMOdHM( zF-}u~BtN(;P*lIC{%TS4;w5p;lgddwxs+{YR#JS{6M~VDbwFsdx<+`@9yKLpKFNV! z-`zbGdpwzl;{rA%4Sk+z5l4bZ9Eb8F5B)ujaNj+Zt&LY=HRi(guJ<^zJJ(zi4&g^0&M0JtE23uWsincX9r@A{@#wN9|)HoW zmfON!)mY=ND1l+wdy=_^Hm)3d+IMW1cm2j@tvM6Ooj%8geU_cxeA_V?oUnxOY^gzw+W0m%G7f2Ko&P&1AtD6Va%!2?sd_h zKYxnuJ#iCA>}>*eaW6i7oEIWc53%j6xY=K8j<3dfzS0S@T-8h)EmmLNE|~S!egX2T z<*!cHIfS`Bb7vZeTVSvV)ciBLO%XTNYQqattwGBZ^qJ`zyKLep^{{o4p|481cRu7@ zmXX&v?waaq|9gX;bzc?%Qsr{(nrBFGPXW0xvdpImkUMBO+EgL+EcdZ^qPwu{s`|5u zTsbbS*3$V&t;~^mt<9J=zEAeIh}%`VfNVfSan>Y!35fg2;JQ$ZmL)p>`1)GVCCFS& zK>PF4r+c}#8cc?@Ns?@`G&UO!yOvf8osU>H@$@uwbafq~u72fcbJX4spgqJE*yNW< z3F^MDoCfgHvs?o7IcD>zQ>RbM>+7q+-fUM7ptfakjsye2tT%FJp(?7XnL~3aqk(3T zk=lQZofQ4mI0cX7w_|W|X;j>Ske@us`fw(aZ}5uEAK~omd;OzBPtUc?s(rb$XafQbJu(#N>!kk!%fh%^b%5h(5d;^rfS zto`PidB&q~lIfpJKyDMTHYK#i3c-$>FlnmkrO9IpCS6p=w?nWsa*i(A^c0x2yOCA# zFxULF;9c-qC8v!X1ymRjy5F_a>Ft90X!4{fac z|0I@g*eAB!dMP}kk2rxsU*81NOm8bvR3!Zxg z4^K^9*g9Qs`?m6H$*~fQ{iU64NRcolwc-+*^!C44Bg!q=$~eh!MREQS0829)(`P0Z Glm7!e@zUl1 literal 0 HcmV?d00001 diff --git a/icons/mob/bloodsucker_mobs.dmi b/icons/mob/bloodsucker_mobs.dmi index 20276e91d0cbe2873429ac39452bac3f46acc97e..041f03dd78ed6f59370274fbdb15251e68b09f63 100644 GIT binary patch literal 23118 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