Yogstation Bloodsucker Clan Ports Part I of IV: Hecata (#1391)

* Ports Hecata bloodsuckers (by Marmio64) from Yogstation.

* Almost forgot the base bloodsucker mob type.

* Update fulp_modules/features/antagonists/bloodsuckers/code/powers/hecata/spirit_call.dm

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>

* Update fulp_modules/features/antagonists/bloodsuckers/code/powers/hecata/necromancy.dm

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>

* Replaces the 'clan_progress' var with 'revive_count' on '/datum/action/cooldown/bloodsucker/targeted/hecata/necromancy'.

* Converts bloodsucker simplemobs and wraiths into basic mobs; adds the 'DEL_ON_DEATH' flag to wraiths.

* Define-ifies the bloodhungry faction.

* Sets sanguine zombie arm damage to initial on species loss.

* Renames a couple of parameters for code clarity.

* Update fulp_modules/features/antagonists/bloodsuckers/code/powers/hecata/spirit_call.dm

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>

* Sets user to equal owner in an action's proc.

* Makes a single item (ectoplasm) remains drop list static.

* Maybe this will work...

* Attempts to fix a unit test error by simplifying something.

* Corrects a typo.

* Adds hecata zombie screenshot; updates tg_edits.md.

---------

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
This commit is contained in:
QuiteLiterallyAnything
2025-10-30 08:58:37 -05:00
committed by GitHub
parent 1dc4f8a4ad
commit 672183ae53
20 changed files with 511 additions and 3 deletions

View File

@@ -52,6 +52,7 @@
#define CLAN_VENTRUE "Ventrue Clan"
#define CLAN_MALKAVIAN "Malkavian Clan"
#define CLAN_TZIMISCE "Tzimisce Clan"
#define CLAN_HECATA "Hecata Clan"
#define CLAN_VASSAL "your Master"
#define TREMERE_VASSAL "tremere_vassal"
@@ -83,6 +84,8 @@
#define VASSAL_CAN_BUY (1<<3)
/// This Power is exclusive to Brujah Bloodsuckers, who will gain them upon joining Brujah.
#define BRUJAH_DEFAULT_POWER (1<<4)
/// This Power can be purchased by Hecata Bloodsuckers
#define HECATA_CAN_BUY (1<<5)
/// This Power is a Toggled Power
#define BP_AM_TOGGLE (1<<0)
@@ -124,6 +127,8 @@
#define BLOODSUCKER_DRINK_SNOBBY "bloodsucker_drink_snobby"
///Drinks blood from disgusting creatures without Humanity consequences.
#define BLOODSUCKER_DRINK_INHUMANELY "bloodsucker_drink_imhumanely"
///Drinks blood only from aggressive or higher grabs, no silent feeding.
#define BLOODSUCKER_DRINK_PAINFUL "bloodsucker_drink_painful"
/**
* Role defines
@@ -141,3 +146,5 @@
*/
/// The attack bonus added to the punch damage of the Brujah clan's favorite vassals.
#define BRUJAH_FAVORITE_VASSAL_ATTACK_BONUS 4
/// The attack bonus added to the punch damage of Hecata zombies.
#define HECATA_ZOMBIE_ATTACK_BONUS 10

View File

@@ -39,8 +39,10 @@
#define COMSIG_GAIN_INSIGHT "gain_insight"
#define COMSIG_BEASTIFY "beastify"
///Define for the 'Rabbits' Faction.
///Define for the "Rabbits" faction.
#define FACTION_RABBITS "rabbits"
///Define for the "Bloodhungry"/bloodsucker monster faction.
#define FACTION_BLOODHUNGRY "bloodhungry"
///Define for the Syndicate Engineer Ruin, used in 'syndicate_engineer.dm"
#define ROLE_SYNDICATE_ENGINEER "Syndicate Engineer"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,20 @@
# Notice:
Some content featured as part of the bloodsucker antagonist has been ported
from codebases external to Fulpstation. While the antagonist was originally
developed for Fulpstation, it has been ported and further developed by other
servers at various points in time. Permission has been acquired by assorted
parties to then port these new features back to Fulpstation. Attribution
for each feature ported can be found below, including links to the GitHub pull
request which originally introduced the feature, the GitHub pull request which
ported the feature to Fulpstation, and the GitHub user page of the feature's
original developer.
# Attribution Listing for Ported Features
## Hecata Bloodsucker Clan
Original PR: https://github.com/yogstation13/Yogstation/pull/18971
Porting PR: https://github.com/fulpstation/fulpstation/pull/1391
Original Developer's GitHub Profile: https://github.com/Marmio64

View File

@@ -0,0 +1,50 @@
/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 |= 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)
/**
* Clan objective
* Hecata's objective is to raise a certain number of people from the dead.
*/
/datum/objective/bloodsucker/necromance
name = "necromance"
/datum/objective/bloodsucker/necromance/New()
var/crew_count = length(get_crewmember_minds())
target_amount = rand(1, ceil(crew_count/5))
update_explanation_text()
..()
/datum/objective/bloodsucker/necromance/update_explanation_text()
. = ..()
explanation_text = "Using Necromancy, revive [target_amount] [target_amount > 1 ? "people" : "person"]."
/datum/objective/bloodsucker/necromance/check_completion()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.current.mind.has_antag_datum(/datum/antagonist/bloodsucker)
if(!bloodsuckerdatum)
return FALSE
var/datum/action/cooldown/bloodsucker/targeted/hecata/necromancy/power_with_revive_count
for(var/datum/action/cooldown/bloodsucker/targeted/hecata/necromancy/necromancy_power in bloodsuckerdatum.powers)
power_with_revive_count = necromancy_power
if(power_with_revive_count.revive_count >= target_amount)
return TRUE
return FALSE

View File

@@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////////////////////
// By Marmio64 as part of the Hecata bloodsucker clan //
// (see 'fulp_modules\features\antagonists\bloodsuckers\_attribution.md') //
////////////////////////////////////////////////////////////////////////////
///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)

View File

@@ -0,0 +1,21 @@
/mob/living/basic/bloodsucker
icon = 'fulp_modules/icons/antagonists/bloodsuckers/bloodsucker_mobs.dmi'
melee_damage_lower = 20
melee_damage_upper = 20
attack_sound = 'sound/items/weapons/slash.ogg'
see_in_dark = 10
mob_size = MOB_SIZE_LARGE
gold_core_spawnable = FALSE
movement_type = GROUND
faction = list(FACTION_HOSTILE, FACTION_BLOODHUNGRY)
response_help_continuous = "touches"
response_help_simple = "touch"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "punches"
response_harm_simple = "punch"
var/mob/living/bloodsucker

View File

@@ -0,0 +1,64 @@
//Wraith - Hecata mob
/mob/living/basic/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)
status_flags = 0
status_flags = CANPUSH
movement_type = FLYING
basic_mob_flags = DEL_ON_DEATH
maxHealth = 30
health = 30
melee_damage_lower = 6
melee_damage_upper = 6
speak_emote = list("hisses")
response_help_continuous = "puts their hand through"
response_help_simple = "put your hand through"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "punches"
response_harm_simple = "punch"
attack_verb_continuous = "metaphysically strikes"
attack_verb_simple = "metaphysically strike"
death_message = "withers away into nothing."
ai_controller = /datum/ai_controller/basic_controller/wraith
minimum_survivable_temperature = 0
maximum_survivable_temperature = INFINITY
unsuitable_atmos_damage = 0
/mob/living/basic/bloodsucker/wraith/Initialize(mapload)
ADD_TRAIT(src, TRAIT_FREE_HYPERSPACE_MOVEMENT, INNATE_TRAIT)
. = ..()
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
AddElement(/datum/element/life_draining)
AddElement(/datum/element/simple_flying)
/mob/living/basic/bloodsucker/wraith/death(gibbed)
. = ..()
new /obj/item/ectoplasm(src.loc)
/// Copied from '/datum/ai_controller/basic_controller/ghost' with minor alteration.
/datum/ai_controller/basic_controller/wraith
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
)
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
/datum/ai_planning_subtree/random_speech/faithless,
)

View File

@@ -28,7 +28,7 @@
/// Requirement flags for checks
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_STAKED|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
/// Who can purchase the Power
var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER|TREMERE_CAN_BUY|VASSAL_CAN_BUY
var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER|TREMERE_CAN_BUY|BRUJAH_CAN_BUY|HECATA_CAN_BUY|VASSAL_CAN_BUY
// VARS //
/// If the Power is currently active, differs from action cooldown because of how powers are handled.

View File

@@ -36,6 +36,9 @@
if(user.is_mouth_covered() && !isplasmaman(user))
owner.balloon_alert(owner, "mouth covered!")
return FALSE
if(bloodsuckerdatum_power.my_clan.blood_drink_type == BLOODSUCKER_DRINK_PAINFUL && owner.grab_state <= GRAB_PASSIVE)
owner.balloon_alert(owner, "can't silent feed!")
return FALSE
//Find target, it will alert what the problem is, if any.
if(!find_target())
return FALSE

View File

@@ -0,0 +1,26 @@
/**
* 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.
*
* ⸸ Blood altars are not implemented on Fulpstation, but this comment has been kept regardless.
*/
/datum/action/cooldown/bloodsucker/targeted/hecata
purchase_flags = HECATA_CAN_BUY
background_icon = 'fulp_modules/icons/antagonists/bloodsuckers/actions_hecata_bloodsucker.dmi'
button_icon = 'fulp_modules/icons/antagonists/bloodsuckers/actions_hecata_bloodsucker.dmi'
active_background_icon_state = "hecata_power_on"
base_background_icon_state = "hecata_power_off"
/datum/action/cooldown/bloodsucker/hecata
purchase_flags = HECATA_CAN_BUY
background_icon = 'fulp_modules/icons/antagonists/bloodsuckers/actions_hecata_bloodsucker.dmi'
button_icon = 'fulp_modules/icons/antagonists/bloodsuckers/actions_hecata_bloodsucker.dmi'
active_background_icon_state = "hecata_power_on"
base_background_icon_state = "hecata_power_off"

View File

@@ -0,0 +1,35 @@
/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_cult_large("<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()

View File

@@ -0,0 +1,102 @@
/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."
/// The number of people "revived" with this power.
/// Used to determine Hecata clan objective completion status.
var/revive_count = 0
/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_after(user, 6 SECONDS, target, NONE, TRUE))
return FALSE
if(IS_VASSAL(target))
power_activated_sucessfully()
owner.balloon_alert(owner, "we revive [target]!")
zombify(target)
revive_count++ //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()
revive_count++ //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
else
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/victim)
victim.mind.remove_antag_datum(/datum/antagonist/vassal)
to_chat(victim, span_warning("You feel the shadows around you weaken, your form falling limp like a puppet cut from its strings!"))
victim.set_species(/datum/species/human/krokodil_addict) //they will turn into a fake zombie on death, that still retains blood and isnt so powerful.
victim.death()
/datum/action/cooldown/bloodsucker/targeted/hecata/necromancy/proc/zombify(mob/living/victim)
victim.mind.grab_ghost()
victim.set_species(/datum/species/zombie/hecata) //imitation zombies that shamble around and beat people with their fists
victim.revive(HEAL_ALL)
victim.visible_message(span_danger("[victim.name] suddenly convulses, as [victim.p_they()] stagger to [victim.p_their()] feet and gain a ravenous hunger in [victim.p_their()] eyes!"), span_alien("You RISE!"))
playsound(get_turf(victim), 'sound/effects/hallucinations/far_noise.ogg', 50, 1)
to_chat(victim, 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(victim, 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."))

View File

@@ -0,0 +1,61 @@
///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()
. = ..()
var/mob/user = owner
switch(level_current)
if(0)
num_spirits = 1
if(1)
num_spirits = 2
if(2)
num_spirits = 3
else
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(get_path_to(user, T, 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/basic/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/effects/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.

View File

@@ -0,0 +1,59 @@
//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"
examine_limb_id = SPECIES_ZOMBIE
damage_modifier = -10
stunmod = 0.5
///no guns or soft crit
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,
)
changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN
// Same as infectious zombies for the slow legs.
bodypart_overrides = list(
BODY_ZONE_HEAD = /obj/item/bodypart/head/zombie,
BODY_ZONE_CHEST = /obj/item/bodypart/chest/zombie,
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/zombie,
BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/zombie,
BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/zombie/infectious,
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie/infectious,
)
/datum/species/zombie/hecata/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load, regenerate_icons)
. = ..()
human_who_gained_species.faction |= FACTION_BLOODHUNGRY
var/mob/living/carbon/our_zombie = human_who_gained_species
var/obj/item/bodypart/zombie_left_hand = our_zombie.get_bodypart(BODY_ZONE_L_ARM)
var/obj/item/bodypart/zombie_right_hand = our_zombie.get_bodypart(BODY_ZONE_R_ARM)
zombie_left_hand.unarmed_damage_low += HECATA_ZOMBIE_ATTACK_BONUS
zombie_right_hand.unarmed_damage_low += HECATA_ZOMBIE_ATTACK_BONUS
zombie_left_hand.unarmed_damage_high += HECATA_ZOMBIE_ATTACK_BONUS
zombie_right_hand.unarmed_damage_high += HECATA_ZOMBIE_ATTACK_BONUS
/datum/species/zombie/hecata/on_species_loss(mob/living/carbon/human/human, datum/species/new_species, pref_load)
. = ..()
human.faction -= FACTION_BLOODHUNGRY
var/mob/living/carbon/our_zombie = human
var/obj/item/bodypart/zombie_left_hand = our_zombie.get_bodypart(BODY_ZONE_L_ARM)
var/obj/item/bodypart/zombie_right_hand = our_zombie.get_bodypart(BODY_ZONE_R_ARM)
zombie_left_hand.unarmed_damage_low = initial(zombie_left_hand.unarmed_damage_low)
zombie_right_hand.unarmed_damage_low = initial(zombie_right_hand.unarmed_damage_low)
zombie_left_hand.unarmed_damage_high = initial(zombie_left_hand.unarmed_damage_high)
zombie_right_hand.unarmed_damage_high = initial(zombie_right_hand.unarmed_damage_high)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -29,7 +29,17 @@
- code/__DEFINES/fulp_defines > Contains all of our defines
- _maps/fulp_maps > Contains all of our non-station maps (Ruins, Deathmatch maps, etc.)
- tgui/packages/fulpui-patches > Adds all Fulp TGUI files
- code/modules/unit_tests/screenshots > Contains Fulp antag & species screenshots for unit tests.
- code/modules/unit_tests/screenshots > Contains Fulp antag & species screenshots for unit tests. This includes **BUT IS NOT LIMITED TO** the following:
1. screenshot_antag_icons_bloodsucker.png
2. screenshot_antag_icons_bloodsuckerbreakout.png
3. screenshot_antag_icons_infiltrator.png
4. screenshot_antag_icons_monsterhunter.png
5. screenshot_antag_icons_vampiricaccident.png
6. screenshot_humanoids__datum_species_beefman.png
7. screenshot_humanoids__datum_species_protogen.png
8. screenshot_humanoids__datum_species_zombie_hecata.png
#### Maps & Shuttles
- _maps/map_files/Heliostation/Heliostation.dmm

View File

@@ -6595,11 +6595,15 @@
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\_clan.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_brujah.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_flavortext.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_hecata.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_malkavian.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_nosferatu.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_tremere.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_vassal.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\clans\clan_ventrue.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\elements\lifedrain.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\mobs\_bloodsucker_mob.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\mobs\wraith.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\objects\bloodsucker_blood_containers.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\objects\bloodsucker_book.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\objects\bloodsucker_stakes.dm"
@@ -6612,6 +6616,10 @@
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\masquerade.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\veil.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\brujah\brash.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\hecata\_powers_hecata.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\hecata\communion.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\hecata\necromancy.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\hecata\spirit_call.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\targeted\_powers_targeted.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\targeted\brawn.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\targeted\haste.dm"
@@ -6625,6 +6633,7 @@
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\vassal\distress.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\vassal\recuperate.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\powers\vassal\vassal_fold.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\species\bloodsucker_zombies.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\structures\_bloodsucker_structure.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\structures\bloodsucker_coffin.dm"
#include "fulp_modules\features\antagonists\bloodsuckers\code\structures\bloodsucker_lighting.dm"