This repository was archived by the owner on May 22, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 457
[BOUNTY] Hecata Bloodsucker Clan (retry) #18971
Merged
JohnFulpWillard
merged 41 commits into
yogstation13:master
from
Marmio64:retry-of-hecata
Aug 9, 2023
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
02ea2b5
hecata clan
Marmio64 5ee8f64
Merge remote-tracking branch 'upstream/master' into retry-of-hecata
Marmio64 f692d0e
Merge remote-tracking branch 'upstream/master' into retry-of-hecata
Marmio64 98db169
adapts the clan to the new changes
Marmio64 99fc3d5
vassal fix
Marmio64 0555cd7
first cleanup batch
Marmio64 6d1cbeb
Update code/modules/mob/living/carbon/human/species_types/zombies.dm
Marmio64 5e46d6c
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 2b8d3ec
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 f47b033
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 248b058
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 4e96bb9
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 5985a26
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 151d5d4
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 48150f5
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 f782be9
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 9e53fda
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 589e2ff
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 2a9751c
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 fae54d8
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 a228ab8
more stuff
Marmio64 77aedaf
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 fed7f1a
Update code/modules/antagonists/bloodsuckers/powers/feed.dm
Marmio64 bad7801
Update code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm
Marmio64 33c19f8
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 2d830ca
switches and multiline
Marmio64 3bfb697
autodoc
Marmio64 d118f50
fix
Marmio64 2f8f4c1
tgui input and sanitize, snake case, owner
Marmio64 05c89a0
Merge remote-tracking branch 'upstream/master' into retry-of-hecata
Marmio64 b0fed43
implements lifedrain element
Marmio64 ce93b45
Update code/modules/mob/living/carbon/human/species_types/zombies.dm
Marmio64 4032cc1
Update code/modules/mob/living/carbon/human/species_types/zombies.dm
Marmio64 431a4f1
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 8976f58
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 d6e7a8a
Update code/modules/mob/living/carbon/human/species_types/zombies.dm
Marmio64 9f9a8ba
Update code/datums/elements/life_drain.dm
JohnFulpWillard a33b05d
Update code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm
JohnFulpWillard 375472b
Update code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
Marmio64 3f666b9
Update code/modules/mob/living/carbon/human/species_types/zombies.dm
Marmio64 6ca8fe7
Update code/modules/mob/living/carbon/human/species_types/zombies.dm
Marmio64 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| ///Slowly drains HP from a living mob. | ||
| /datum/element/life_draining | ||
| element_flags = ELEMENT_BESPOKE | ||
| argument_hash_start_idx = 2 | ||
|
|
||
| ///How much damage to deal overtime. | ||
| var/damage_overtime | ||
| ///The callback we will use to cancel damage, if any | ||
| var/datum/callback/check_damage_callback | ||
|
|
||
| /datum/element/life_draining/Attach( | ||
| mob/living/target, | ||
| damage_overtime = 1, | ||
| datum/callback/check_damage_callback, | ||
| ) | ||
| . = ..() | ||
| if(!isliving(target)) | ||
| return ELEMENT_INCOMPATIBLE | ||
| src.damage_overtime = damage_overtime | ||
| src.check_damage_callback = check_damage_callback | ||
| RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_mob_life)) | ||
|
|
||
| /datum/element/life_draining/Detach(mob/living/source, ...) | ||
| UnregisterSignal(source, COMSIG_LIVING_LIFE) | ||
| return ..() | ||
|
|
||
| ///Handles removing HP from the mob, as long as they're not dead. | ||
| /datum/element/life_draining/proc/on_mob_life(mob/living/source, seconds_per_tick, times_fired) | ||
| SIGNAL_HANDLER | ||
| if(source.stat == DEAD) | ||
| return | ||
| if(check_damage_callback?.Invoke()) | ||
| return | ||
| source.adjustBruteLoss(damage_overtime) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
code/modules/antagonists/bloodsuckers/clans/clan_hecata.dm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| /datum/bloodsucker_clan/hecata | ||
| name = CLAN_HECATA | ||
| description = "This Clan is composed of curious practioners of dark magic who enjoy toying with the dead. \n\ | ||
| Often compared to the Lasombra, they sometimes act in similar ways and draw power from the void. \n\ | ||
| However, they are also very different, and place an emphasis on creating zombie like puppets from the dead. \n\ | ||
| They are able to raise the dead as temporary vassals, permanently revive dead vassals, communicate to their vassals from afar, and summon wraiths. \n\ | ||
| Their Favorite Vassal also has inherited a small fraction of their power, being able to call wraiths into the world as well." | ||
| clan_objective = /datum/objective/bloodsucker/necromance | ||
| join_icon_state = "hecata" | ||
| join_description = "Raise zombie hordes from the dead, and then coordinate them from anywhere anytime." | ||
| blood_drink_type = BLOODSUCKER_DRINK_PAINFUL | ||
|
|
||
| /datum/bloodsucker_clan/hecata/New(datum/antagonist/bloodsucker/owner_datum) | ||
| . = ..() | ||
| bloodsuckerdatum.BuyPower(new /datum/action/cooldown/bloodsucker/targeted/hecata/necromancy) | ||
| bloodsuckerdatum.BuyPower(new /datum/action/cooldown/bloodsucker/hecata/spiritcall) | ||
| bloodsuckerdatum.BuyPower(new /datum/action/cooldown/bloodsucker/hecata/communion) | ||
| bloodsuckerdatum.owner.current.faction |= "bloodhungry" | ||
| bloodsuckerdatum.owner.current.update_body() | ||
|
|
||
| /datum/bloodsucker_clan/hecata/on_favorite_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum) | ||
| vassaldatum.BuyPower(new /datum/action/cooldown/bloodsucker/hecata/spiritcall) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
220 changes: 220 additions & 0 deletions
220
code/modules/antagonists/bloodsuckers/powers/targeted/hecata.dm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,220 @@ | ||
| /** | ||
| * 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/cooldown/bloodsucker/targeted/hecata | ||
| purchase_flags = HECATA_CAN_BUY | ||
| background_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' | ||
| button_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' | ||
| active_background_icon_state = "hecata_power_on" | ||
| base_background_icon_state = "hecata_power_off" | ||
|
|
||
| /datum/action/cooldown/bloodsucker/targeted/hecata/necromancy | ||
| name = "Necromancy" | ||
| 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_time = 45 SECONDS | ||
| target_range = 1 | ||
| prefire_message = "Select a target." | ||
|
|
||
| /datum/action/cooldown/bloodsucker/targeted/hecata/necromancy/CheckValidTarget(atom/target_atom) | ||
| . = ..() | ||
| if(!.) | ||
| return FALSE | ||
| return isliving(target_atom) | ||
|
|
||
| /datum/action/cooldown/bloodsucker/targeted/hecata/necromancy/CheckCanTarget(mob/living/carbon/target_atom) | ||
| . = ..() | ||
| if(!.) | ||
| return FALSE | ||
| // No mind | ||
| if(!target_atom.mind) | ||
| to_chat(owner, span_warning("[target_atom] is mindless.")) | ||
| return FALSE | ||
| // Bloodsucker | ||
| if(IS_BLOODSUCKER(target_atom)) | ||
| to_chat(owner, span_notice("Bloodsuckers are immune to [src].")) | ||
| return FALSE | ||
| // Alive | ||
| if(target_atom.stat != DEAD) | ||
| to_chat(owner, span_notice("[target_atom] is still alive.")) | ||
| return FALSE | ||
| return TRUE | ||
|
|
||
| /datum/action/cooldown/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)) | ||
| power_activated_sucessfully() | ||
| owner.balloon_alert(owner, "we revive [target]!") | ||
| zombify(target) | ||
| bloodsuckerdatum.clanprogress++ //counts a succesful necromancy towards your objective progress | ||
| return | ||
| if(IS_MONSTERHUNTER(target)) | ||
| owner.balloon_alert(owner, "their body refuses to react...") | ||
| DeactivatePower() | ||
| return | ||
| zombify(target) | ||
| bloodsuckerdatum.make_vassal(target) | ||
| power_activated_sucessfully() | ||
| bloodsuckerdatum.clanprogress++ //counts a succesful necromancy towards your objective progress | ||
| to_chat(user, span_warning("We revive [target]!")) | ||
| var/living_time | ||
| switch(level_current) | ||
| if(0) | ||
| living_time = 2 MINUTES | ||
| if(1) | ||
| living_time = 5 MINUTES | ||
| if(2) | ||
| living_time = 8 MINUTES | ||
| if(3) | ||
| living_time = 11 MINUTES | ||
| if(4) | ||
| living_time = 14 MINUTES | ||
| if(5 to 99) | ||
| living_time = 17 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, "out of range/not dead.") | ||
| return FALSE | ||
| DeactivatePower() | ||
|
|
||
| /datum/action/cooldown/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/cooldown/bloodsucker/targeted/hecata/necromancy/proc/zombify(mob/living/user) | ||
| user.mind.grab_ghost() | ||
| user.set_species(/datum/species/zombie/hecata) //imitation zombies that shamble around and beat people with their fists | ||
| user.revive(full_heal = TRUE, admin_revive = TRUE) | ||
| 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/cooldown/bloodsucker/hecata | ||
| purchase_flags = HECATA_CAN_BUY | ||
| background_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' | ||
| button_icon = 'icons/mob/actions/actions_hecata_bloodsucker.dmi' | ||
| active_background_icon_state = "hecata_power_on" | ||
| base_background_icon_state = "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/cooldown/bloodsucker/hecata/spiritcall | ||
| name = "Spirit Call" | ||
| desc = "Summon 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_time = 60 SECONDS | ||
| ///How many spirits should be summoned when cast | ||
| var/num_spirits = 1 | ||
|
|
||
| /datum/action/cooldown/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/cooldown/bloodsucker/hecata/spiritcall/ActivatePower(mob/user = owner) | ||
| . = ..() | ||
| switch(level_current) | ||
| if(0) | ||
| num_spirits = 1 | ||
| if(1) | ||
| num_spirits = 2 | ||
| if(2) | ||
| num_spirits = 3 | ||
| if(3 to 99) | ||
| num_spirits = 4 | ||
| var/list/turf/locs = list() | ||
| 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(owner, 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 | ||
| summon_wraiths(locs, user = owner) | ||
| cast_effect() // POOF | ||
| DeactivatePower() | ||
|
|
||
| /datum/action/cooldown/bloodsucker/hecata/spiritcall/proc/summon_wraiths(list/targets, mob/living/user) | ||
| for(var/T in targets) | ||
| new /mob/living/simple_animal/hostile/bloodsucker/wraith(T) | ||
|
|
||
| /datum/action/cooldown/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, TRUE) | ||
| var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread/bloodsucker() | ||
| 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/cooldown/bloodsucker/hecata/communion | ||
| name = "Deathly Communion" | ||
| 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_time = 30 SECONDS | ||
|
|
||
| /datum/action/cooldown/bloodsucker/hecata/communion/ActivatePower() | ||
| . = ..() | ||
| var/input = sanitize(tgui_input_text(usr, "Enter a message to tell your vassals.", "Voice of Blood")) | ||
| if(!input || !IsAvailable()) | ||
| return FALSE | ||
| deathly_commune(usr, input) | ||
|
|
||
| /datum/action/cooldown/bloodsucker/hecata/communion/proc/deathly_commune(mob/living/user, message) //code from Fulpstation | ||
| var/rendered = span_cultlarge("<b>Master [user.real_name] announces:</b> [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() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hecata spells should follow what Tremere spells did and be in their own folder, but not in the same file