Merge remote-tracking branch 'upstream/master' into tackling_and_lunge

This commit is contained in:
Artur
2020-04-15 12:19:37 +03:00
499 changed files with 5377 additions and 3805 deletions
@@ -209,7 +209,6 @@
open_machine()
SendBack(H)
return "<span class='bad'>Specimen braindead - disposed.</span>"
return "<span class='bad'>ERROR</span>"
/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
@@ -1,12 +1,6 @@
// INTEGRATION: Adding Procs and Datums to existing "classes"
/mob/living/proc/AmBloodsucker(falseIfInDisguise=FALSE)
// No Datum
if(!mind || !mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
return FALSE
return TRUE
/mob/living/proc/HaveBloodsuckerBodyparts(var/displaymessage="") // displaymessage can be something such as "rising from death" for Torpid Sleep. givewarningto is the person receiving messages.
/mob/living/proc/HaveBloodsuckerBodyparts(displaymessage = "") // displaymessage can be something such as "rising from death" for Torpid Sleep. givewarningto is the person receiving messages.
if(!getorganslot(ORGAN_SLOT_HEART))
if(displaymessage != "")
to_chat(src, "<span class='warning'>Without a heart, you are incapable of [displaymessage].</span>")
@@ -21,33 +15,6 @@
return FALSE
return TRUE
// GET DAMAGE
// Do NOT count the damage on prosthetics for this.
/mob/living/proc/getBruteLoss_nonProsthetic()
return getBruteLoss()
/mob/living/proc/getFireLoss_nonProsthetic()
return getFireLoss()
/mob/living/carbon/getBruteLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if(BP.status < 2)
amount += BP.brute_dam
return amount
/mob/living/carbon/getFireLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if(BP.status < 2)
amount += BP.burn_dam
return amount
/mob/living/carbon
// EXAMINING
/mob/living/carbon/human/proc/ReturnVampExamine(var/mob/viewer)
if(!mind || !viewer.mind)
@@ -12,10 +12,10 @@
/datum/antagonist/bloodsucker/proc/LifeTick()// Should probably run from life.dm, same as handle_changeling, but will be an utter pain to move
set waitfor = FALSE // Don't make on_gain() wait for this function to finish. This lets this code run on the side.
var/notice_healing = FALSE
var/notice_healing
while(owner && !AmFinalDeath()) // owner.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) == src
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_DEATHCOMA)) // Deduct Blood
AddBloodVolume(-0.1) // -.15 (before tick went from 10 to 30, but we also charge more for faking life now)
AddBloodVolume(passive_blood_drain) // -.1 currently
if(HandleHealing(1)) // Heal
if(notice_healing == FALSE && owner.current.blood_volume > 0)
to_chat(owner, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
@@ -25,7 +25,7 @@
HandleStarving() // Death
HandleDeath() // Standard Update
update_hud()// Daytime Sleep in Coffin
if (SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
Torpor_Begin()
// Wait before next pass
@@ -39,12 +39,12 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/antagonist/bloodsucker/proc/AddBloodVolume(value)
owner.current.blood_volume = CLAMP(owner.current.blood_volume + value, 0, maxBloodVolume)
owner.current.blood_volume = CLAMP(owner.current.blood_volume + value, 0, max_blood_volume)
update_hud()
/datum/antagonist/bloodsucker/proc/HandleFeeding(mob/living/carbon/target, mult=1)
// mult: SILENT feed is 1/3 the amount
var/blood_taken = min(feedAmount, target.blood_volume) * mult // Starts at 15 (now 8 since we doubled the Feed time)
var/blood_taken = min(feed_amount, target.blood_volume) * mult // Starts at 15 (now 8 since we doubled the Feed time)
target.blood_volume -= blood_taken
// Simple Animals lose a LOT of blood, and take damage. This is to keep cats, cows, and so forth from giving you insane amounts of blood.
if(!ishuman(target))
@@ -82,38 +82,40 @@
/datum/antagonist/bloodsucker/proc/HandleHealing(mult = 1)
// NOTE: Mult of 0 is just a TEST to see if we are injured and need to go into Torpor!
//It is called from your coffin on close (by you only)
var/actual_regen = regen_rate + additional_regen
if(poweron_masquerade == TRUE || owner.current.AmStaked())
return FALSE
owner.current.adjustStaminaLoss(-1.5 + (regenRate * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
owner.current.adjustCloneLoss(-0.1 * (regenRate * 2) * mult, 0)
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (regenRate * 4) * mult) //adjustBrainLoss(-1 * (regenRate * 4) * mult, 0)
if(owner.current.reagents.has_reagent(/datum/reagent/consumable/garlic))
return FALSE
if(istype(owner.current.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
return FALSE
owner.current.adjustStaminaLoss(-1.5 + (actual_regen * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
owner.current.adjustCloneLoss(-0.1 * (actual_regen * 2) * mult, 0)
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (actual_regen * 4) * mult)
// No Bleeding
if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete.
/*if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete.
var/mob/living/carbon/human/H = owner.current
H.bleed_rate = 0
if(H.bleed_rate > 0) //Only heal bleeding if we are actually bleeding
H.bleed_rate =- 0.5 + actual_regen * 0.2 */
if(iscarbon(owner.current)) // Damage Heal: Do I have damage to ANY bodypart?
var/mob/living/carbon/C = owner.current
var/costMult = 1 // Coffin makes it cheaper
var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire)
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_DEATHCOMA)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
if(amInCoffinWhileTorpor)
mult *= 4 // Increase multiplier if we're sleeping in a coffin.
fireheal = min(C.getFireLoss_nonProsthetic(), regenRate) // NOTE: Burn damage ONLY heals in torpor.
costMult = 0.25
fireheal = min(C.getFireLoss(), regen_rate) // NOTE: Burn damage ONLY heals in torpor.
C.ExtinguishMob()
CureDisabilities() // Extinguish Fire
C.remove_all_embedded_objects() // Remove Embedded!
owner.current.regenerate_organs() // Heal Organs (will respawn original eyes etc. but we replace right away, next)
CheckVampOrgans() // Heart, Eyes
else
if(owner.current.blood_volume <= 0) // No Blood? Lower Mult
mult = 0.25
// Crit from burn? Lower damage to maximum allowed.
//if (C.getFireLoss() > owner.current.getMaxHealth())
// fireheal = regenRate / 2
if(check_limbs(costMult))
return TRUE
// BRUTE: Always Heal
var/bruteheal = min(C.getBruteLoss_nonProsthetic(), regenRate)
var/toxinheal = min(C.getToxLoss(), regenRate)
var/bruteheal = min(C.getBruteLoss(), actual_regen)
var/toxinheal = min(C.getToxLoss(), actual_regen)
// Heal if Damaged
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
if(mult == 0)
@@ -127,28 +129,29 @@
//C.heal_overall_damage(bruteheal * mult, fireheal * mult) // REMOVED: We need to FORCE this, because otherwise, vamps won't heal EVER. Swapped to above.
AddBloodVolume((bruteheal * -0.5 + fireheal * -1 + toxinheal * -0.2) / mult * costMult) // Costs blood to heal
return TRUE // Healed! Done for this tick.
if(amInCoffinWhileTorpor) // Limbs? (And I have no other healing)
var/list/missing = owner.current.get_missing_limbs() // Heal Missing
if (missing.len) // Cycle through ALL limbs and regen them!
for (var/targetLimbZone in missing) // 1) Find ONE Limb and regenerate it.
owner.current.regenerate_limb(targetLimbZone, 0) // regenerate_limbs() <--- If you want to EXCLUDE certain parts, do it like this ----> regenerate_limbs(0, list("head"))
var/obj/item/bodypart/L = owner.current.get_bodypart( targetLimbZone ) // 2) Limb returns Damaged
AddBloodVolume(50 * costMult) // Costs blood to heal
L.brute_dam = 60
to_chat(owner.current, "<span class='notice'>Your flesh knits as it regrows [L]!</span>")
playsound(owner.current, 'sound/magic/demon_consume.ogg', 50, 1)
// DONE! After regenerating ANY number of limbs, we stop here.
return TRUE
/*else // REMOVED: For now, let's just leave prosthetics on. Maybe you WANT to be a robovamp.
// Remove Prosthetic/False Limb
for(var/obj/item/bodypart/BP in C.bodyparts)
message_admins("T1: [BP] ")
if (istype(BP) && BP.status == 2)
message_admins("T2: [BP] ")
BP.drop_limb()
return TRUE */
// NOTE: Limbs have a "status", like their hosts "stat". 2 is dead (aka Prosthetic). 1 seems to be idle/alive.*/
return FALSE
/datum/antagonist/bloodsucker/proc/check_limbs(costMult)
var/limb_regen_cost = 50 * costMult
var/mob/living/carbon/C = owner.current
var/list/missing = C.get_missing_limbs()
if(missing.len && C.blood_volume < limb_regen_cost + 5)
return FALSE
for(var/targetLimbZone in missing) // 1) Find ONE Limb and regenerate it.
C.regenerate_limb(targetLimbZone, FALSE) // regenerate_limbs() <--- If you want to EXCLUDE certain parts, do it like this ----> regenerate_limbs(0, list("head"))
AddBloodVolume(50)
var/obj/item/bodypart/L = C.get_bodypart(targetLimbZone) // 2) Limb returns Damaged
L.brute_dam = 60
to_chat(C, "<span class='notice'>Your flesh knits as it regrows your [L]!</span>")
playsound(C, 'sound/magic/demon_consume.ogg', 50, TRUE)
return TRUE
/*for(var/obj/item/bodypart/BP in C.bodyparts)
if(!istype(BP) && !BP.status == 2)
return FALSE
to_chat(C, "<span class='notice'>Your body expels the [BP]!</span>")
BP.drop_limb()
return TRUE */
/datum/antagonist/bloodsucker/proc/CureDisabilities()
var/mob/living/carbon/C = owner.current
@@ -179,7 +182,16 @@
if(owner.current.blood_volume < BLOOD_VOLUME_BAD / 2)
owner.current.blur_eyes(8 - 8 * (owner.current.blood_volume / BLOOD_VOLUME_BAD))
// Nutrition
owner.current.nutrition = min(owner.current.blood_volume, NUTRITION_LEVEL_FED) // <-- 350 //NUTRITION_LEVEL_FULL
owner.current.nutrition = clamp(owner.current.blood_volume, 545, 0) //The amount of blood is how full we are.
//A bit higher regeneration based on blood volume
if(owner.current.blood_volume < 700)
additional_regen = 0.4
else if(owner.current.blood_volume < BLOOD_VOLUME_NORMAL)
additional_regen = 0.3
else if(owner.current.blood_volume < BLOOD_VOLUME_OKAY)
additional_regen = 0.2
else if(owner.current.blood_volume < BLOOD_VOLUME_BAD)
additional_regen = 0.1
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEATH
@@ -189,7 +201,7 @@
/datum/antagonist/bloodsucker/proc/HandleDeath()
// FINAL DEATH
// Fire Damage? (above double health)
if(owner.current.getFireLoss_nonProsthetic() >= owner.current.maxHealth * 2.5)
if(owner.current.getFireLoss() >= owner.current.maxHealth * 3)
FinalDeath()
return
// Staked while "Temp Death" or Asleep
@@ -209,8 +221,8 @@
// for (var/datum/action/bloodsucker/masquerade/P in powers)
// P.Deactivate()
// TEMP DEATH
var/total_brute = owner.current.getBruteLoss_nonProsthetic()
var/total_burn = owner.current.getFireLoss_nonProsthetic()
var/total_brute = owner.current.getBruteLoss()
var/total_burn = owner.current.getFireLoss()
var/total_toxloss = owner.current.getToxLoss() //This is neater than just putting it in total_damage
var/total_damage = total_brute + total_burn + total_toxloss
// Died? Convert to Torpor (fake death)
@@ -218,27 +230,25 @@
Torpor_Begin()
to_chat(owner, "<span class='danger'>Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.</span>")
sleep(30) //To avoid spam
if (poweron_masquerade == TRUE)
if(poweron_masquerade == TRUE)
to_chat(owner, "<span class='warning'>Your wounds will not heal until you disable the <span class='boldnotice'>Masquerade</span> power.</span>")
// End Torpor:
else // No damage, OR toxin healed AND brute healed and NOT in coffin (since you cannot heal burn)
if(total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin))
// Not Daytime, Not in Torpor
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
Torpor_End()
// Fake Unconscious
if(poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
owner.current.Unconscious(20,1)
//HEALTH_THRESHOLD_CRIT 0
//HEALTH_THRESHOLD_FULLCRIT -30
//HEALTH_THRESHOLD_DEAD -100
owner.current.Unconscious(20, 1)
/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin=FALSE)
/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin = FALSE)
owner.current.stat = UNCONSCIOUS
owner.current.fakedeath("bloodsucker") // Come after UNCONSCIOUS or else it fails
owner.current.apply_status_effect(STATUS_EFFECT_UNCONSCIOUS)
ADD_TRAIT(owner.current, TRAIT_FAKEDEATH, "bloodsucker") // Come after UNCONSCIOUS or else it fails
ADD_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker") // Without this, you'll just keep dying while you recover.
ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in 0 G. otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker") // So you can heal in 0 G. otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in space. Otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker")
// Visuals
owner.current.update_sight()
owner.current.reload_fullscreen()
@@ -247,10 +257,10 @@
if(power.active && !power.can_use_in_torpor)
power.DeactivatePower()
/datum/antagonist/bloodsucker/proc/Torpor_End()
owner.current.stat = SOFT_CRIT
owner.current.cure_fakedeath("bloodsucker") // Come after SOFT_CRIT or else it fails
owner.current.remove_status_effect(STATUS_EFFECT_UNCONSCIOUS)
REMOVE_TRAIT(owner.current, TRAIT_FAKEDEATH, "bloodsucker")
REMOVE_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker")
REMOVE_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker")
REMOVE_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker")
@@ -283,18 +293,19 @@
// Free my Vassals!
FreeAllVassals()
// Elders get Dusted
if(vamplevel >= 4) // (vamptitle)
if(bloodsucker_level >= 4) // (bloodsucker_title)
owner.current.visible_message("<span class='warning'>[owner.current]'s skin crackles and dries, their skin and bones withering to dust. A hollow cry whips from what is now a sandy pile of remains.</span>", \
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
"<span class='italics'>You hear a dry, crackling sound.</span>")
sleep(50)
owner.current.dust()
// Fledglings get Gibbed
else
owner.current.visible_message("<span class='warning'>[owner.current]'s skin bursts forth in a spray of gore and detritus. A horrible cry echoes from what is now a wet pile of decaying meat.</span>", \
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
"<span class='italics'>You hear a wet, bursting sound.</span>")
owner.current.gib(TRUE, FALSE, FALSE)//Brain cloning is wierd and allows hellbounds. Lets destroy the brain for safety.
playsound(owner.current.loc, 'sound/effects/tendril_destroyed.ogg', 40, 1)
owner.current.gib(TRUE, FALSE, FALSE) //Brain cloning is wierd and allows hellbounds. Lets destroy the brain for safety.
playsound(owner.current, 'sound/effects/tendril_destroyed.ogg', 40, TRUE)
@@ -304,15 +315,15 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/proc/CheckBloodsuckerEatFood(var/food_nutrition)
if (!isliving(src))
/mob/proc/CheckBloodsuckerEatFood(food_nutrition)
if(!isliving(src))
return
var/mob/living/L = src
if(!L.AmBloodsucker())
if(!AmBloodsucker(L))
return
// We're a vamp? Try to eat food...
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
bloodsuckerdatum.handle_eat_human_food(food_nutrition)
// We're a bloodsucker? Try to eat food...
var/datum/antagonist/bloodsucker/B = L.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
B.handle_eat_human_food(food_nutrition)
/datum/antagonist/bloodsucker/proc/handle_eat_human_food(food_nutrition, puke_blood = TRUE, masquerade_override) // Called from snacks.dm and drinks.dm
@@ -93,6 +93,14 @@
if(display_error)
to_chat(owner, "<span class='warning'>You have a stake in your chest! Your powers are useless.</span>")
return FALSE
if(istype(owner.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
if(display_error)
to_chat(owner, "<span class='warning'The necklace on your neck is interfering with your powers!</span>")
return FALSE
if(owner.reagents?.has_reagent(/datum/reagent/consumable/garlic))
if(display_error)
to_chat(owner, "<span class='warning'>Garlic in your blood is interfering with your powers!</span>")
return FALSE
// Incap?
if(must_be_capacitated)
var/mob/living/L = owner
@@ -141,23 +141,23 @@
if(!bloodsuckerdatum.warn_sun_locker)
to_chat(M, "<span class='warning'>Your skin sizzles. The [M.current.loc] doesn't protect well against UV bombardment.</span>")
bloodsuckerdatum.warn_sun_locker = TRUE
M.current.adjustFireLoss(0.5 + bloodsuckerdatum.vamplevel / 2) // M.current.fireloss += 0.5 + bloodsuckerdatum.vamplevel / 2 // Do DIRECT damage. Being spaced was causing this to not occur. setFireLoss(bloodsuckerdatum.vamplevel)
M.current.adjustFireLoss(0.5 + bloodsuckerdatum.bloodsucker_level / 2) // M.current.fireloss += 0.5 + bloodsuckerdatum.bloodsucker_level / 2 // Do DIRECT damage. Being spaced was causing this to not occur. setFireLoss(bloodsuckerdatum.bloodsucker_level)
M.current.updatehealth()
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_1)
// Out in the Open? Buh Bye
else
if(!bloodsuckerdatum.warn_sun_burn)
if(bloodsuckerdatum.vamplevel > 0)
if(bloodsuckerdatum.bloodsucker_level > 0)
to_chat(M, "<span class='userdanger'>The solar flare sets your skin ablaze!</span>")
else
to_chat(M, "<span class='userdanger'>The solar flare scalds your neophyte skin!</span>")
bloodsuckerdatum.warn_sun_burn = TRUE
if(M.current.fire_stacks <= 0)
M.current.fire_stacks = 0
if(bloodsuckerdatum.vamplevel > 0)
M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.vamplevel / 10)
if(bloodsuckerdatum.bloodsucker_level > 0)
M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.bloodsucker_level / 10)
M.current.IgniteMob()
M.current.adjustFireLoss(2 + bloodsuckerdatum.vamplevel) // M.current.fireloss += 2 + bloodsuckerdatum.vamplevel // Do DIRECT damage. Being spaced was causing this to not occur. //setFireLoss(2 + bloodsuckerdatum.vamplevel)
M.current.adjustFireLoss(2 + bloodsuckerdatum.bloodsucker_level) // M.current.fireloss += 2 + bloodsuckerdatum.bloodsucker_level // Do DIRECT damage. Being spaced was causing this to not occur. //setFireLoss(2 + bloodsuckerdatum.bloodsucker_level)
M.current.updatehealth()
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_2)
@@ -8,9 +8,9 @@
job_rank = ROLE_BLOODSUCKER
threat = 5
// NAME
var/vampname // My Dracula name
var/vamptitle // My Dracula title
var/vampreputation // My "Surname" or description of my deeds
var/bloodsucker_name // My Dracula style name
var/bloodsucker_title // My Dracula style title
var/bloodsucker_reputation // My "Surname" or description of my deeds
// CLAN
var/datum/team/vampireclan/clan
var/list/datum/antagonist/vassal/vassals = list()// Vassals under my control. Periodically remove the dead ones.
@@ -20,35 +20,33 @@
var/poweron_feed = FALSE // Am I feeding?
var/poweron_masquerade = FALSE
// STATS
var/vamplevel = 0
var/vamplevel_unspent = 1
var/regenRate = 0.4 // How many points of Brute do I heal per tick?
var/feedAmount = 15 // Amount of blood drawn from a target per tick.
var/maxBloodVolume = 600 // Maximum blood a Vamp can hold via feeding. // BLOOD_VOLUME_NORMAL 550 // BLOOD_VOLUME_SAFE 475 //BLOOD_VOLUME_OKAY 336 //BLOOD_VOLUME_BAD 224 // BLOOD_VOLUME_SURVIVE 122
var/bloodsucker_level
var/bloodsucker_level_unspent = 1
var/regen_rate = 0.3 // How fast do I regenerate?
var/additional_regen // How much additional blood regen we gain from bonuses such as high blood.
var/feed_amount = 15 // Amount of blood drawn from a target per tick.
var/max_blood_volume = 600 // Maximum blood a Vamp can hold via feeding.
// OBJECTIVES
var/list/datum/objective/objectives_given = list() // For removal if needed.
var/area/lair
var/obj/structure/closet/crate/coffin
// TRACKING
var/foodInGut = 0 // How much food to throw up later. You shouldn't have eaten that.
var/warn_sun_locker = FALSE // So we only get the locker burn message once per day.
var/warn_sun_burn = FALSE // So we only get the sun burn message once per day.
var/had_toxlover = FALSE
var/foodInGut // How much food to throw up later. You shouldn't have eaten that.
var/warn_sun_locker // So we only get the locker burn message once per day.
var/warn_sun_burn // So we only get the sun burn message once per day.
var/had_toxlover
var/level_bloodcost
var/passive_blood_drain = -0.1 //The amount of blood we loose each bloodsucker life() tick
// LISTS
var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_NIGHT_VISION, \
TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_VIRUSIMMUNE)
// NOTES: TRAIT_AGEUSIA <-- Doesn't like flavors.
// REMOVED: TRAIT_NODEATH
// TO ADD:
//var/static/list/defaultOrgans = list (/obj/item/organ/heart/vampheart,/obj/item/organ/heart/vampeyes)
/datum/antagonist/bloodsucker/on_gain()
SSticker.mode.bloodsuckers |= owner // Add if not already in here (and you might be, if you were picked at round start)
SSticker.mode.check_start_sunlight()// Start Sunlight? (if first Vamp)
SelectFirstName()// Name & Title
SelectTitle(am_fledgling=TRUE) // If I have a creator, then set as Fledgling.
SelectReputation(am_fledgling=TRUE)
SelectTitle(am_fledgling = TRUE) // If I have a creator, then set as Fledgling.
SelectReputation(am_fledgling = TRUE)
AssignStarterPowersAndStats()// Give Powers & Stats
forge_bloodsucker_objectives()// Objectives & Team
update_bloodsucker_icons_added(owner.current, "bloodsucker") // Add Antag HUD
@@ -68,18 +66,18 @@
/datum/antagonist/bloodsucker/greet()
var/fullname = ReturnFullName(TRUE)
to_chat(owner, "<span class='userdanger'>You are [fullname], a bloodsucking vampire!</span><br>")
to_chat(owner, "<span class='userdanger'>You are [fullname], a strain of vampire dubbed bloodsucker!</span><br>")
owner.announce_objectives()
to_chat(owner, "<span class='boldannounce'>* You regenerate your health slowly, you're weak to fire, and you depend on blood to survive. Allow your stolen blood to run too low, and you will find yourself at \
risk of being discovered!</span><br>")
//to_chat(owner, "<span class='boldannounce'>As an immortal, your power is linked to your age. The older you grow, the more abilities you will have access to.<span>")
var/vamp_greet
vamp_greet += "<span class='boldannounce'>* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.</span><br>"
vamp_greet += "<span class='boldannounce'><i>* Use \",b\" to speak your ancient Bloodsucker language.</span><br>"
vamp_greet += "<span class='announce'>Bloodsucker Tip: Rest in a <i>Coffin</i> to claim it, and that area, as your lair.</span><br>"
vamp_greet += "<span class='announce'>Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.</span><br>"
vamp_greet += "<span class='announce'>Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.</span><br>"
to_chat(owner, vamp_greet)
var/bloodsucker_greet
bloodsucker_greet += "<span class='boldannounce'>* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.</span><br>"
bloodsucker_greet += "<span class='boldannounce'><i>* Use \",b\" to speak your ancient Bloodsucker language.</span><br>"
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: Rest in a <i>Coffin</i> to claim it, and that area, as your lair.</span><br>"
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.</span><br>"
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.</span><br>"
to_chat(owner, bloodsucker_greet)
owner.current.playsound_local(null, 'sound/bloodsucker/BloodsuckerAlert.ogg', 100, FALSE, pressure_affected = FALSE)
antag_memory += "Although you were born a mortal, in un-death you earned the name <b>[fullname]</b>.<br>"
@@ -92,13 +90,13 @@
owner.current.blood_volume = max(owner.current.blood_volume,BLOOD_VOLUME_SAFE)
/datum/antagonist/bloodsucker/threat()
return ..()+3*vamplevel
return ..() + 3 * bloodsucker_level
/datum/antagonist/bloodsucker/proc/SelectFirstName()
// Names (EVERYONE gets one))
if(owner.current.gender == MALE)
vampname = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \
bloodsucker_name = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \
"Sveyn","Aurel","Alexe","Iustin","Theodor","Dimitrie","Octav","Damien","Magnus","Caine","Abel", // Romanian/Ancient
"Lucius","Gaius","Otho","Balbinus","Arcadius","Romanos","Alexios","Vitellius", // Latin
"Melanthus","Teuthras","Orchamus","Amyntor","Axion", // Greek
@@ -106,7 +104,7 @@
"Dio")
else
vampname = pick("Islana","Tyrra","Greganna","Pytra","Hilda","Andra","Crina","Viorela","Viorica","Anemona","Camelia","Narcisa","Sorina","Alessia","Sophia","Gladda","Arcana","Morgan","Lasarra","Ioana","Elena", \
bloodsucker_name = pick("Islana","Tyrra","Greganna","Pytra","Hilda","Andra","Crina","Viorela","Viorica","Anemona","Camelia","Narcisa","Sorina","Alessia","Sophia","Gladda","Arcana","Morgan","Lasarra","Ioana","Elena", \
"Alina","Rodica","Teodora","Denisa","Mihaela","Svetla","Stefania","Diyana","Kelssa","Lilith", // Romanian/Ancient
"Alexia","Athanasia","Callista","Karena","Nephele","Scylla","Ursa", // Latin
"Alcestis","Damaris","Elisavet","Khthonia","Teodora", // Greek
@@ -114,57 +112,57 @@
/datum/antagonist/bloodsucker/proc/SelectTitle(am_fledgling = 0, forced = FALSE)
// Already have Title
if (!forced && vamptitle != null)
if(!forced && bloodsucker_title != null)
return
// Titles [Master]
if (!am_fledgling)
if(!am_fledgling)
if(owner.current.gender == MALE)
vamptitle = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master")
bloodsucker_title = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master")
else
vamptitle = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress")
bloodsucker_title = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress")
to_chat(owner, "<span class='announce'>You have earned a title! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
// Titles [Fledgling]
else
vamptitle = null
bloodsucker_title = null
/datum/antagonist/bloodsucker/proc/SelectReputation(am_fledgling = 0, forced=FALSE)
// Already have Reputation
if(!forced && vampreputation != null)
if(!forced && bloodsucker_reputation != null)
return
// Reputations [Master]
if(!am_fledgling)
vampreputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \
bloodsucker_reputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \
"Inqisitor","Harvester","Reviled","Robust","Betrayer","Destructor","Damned","Accursed","Terrible","Vicious","Profane","Vile","Depraved","Foul","Slayer","Manslayer","Sovereign","Slaughterer", \
"Forsaken","Mad","Dragon","Savage","Villainous","Nefarious","Inquisitor","Marauder","Horrible","Immortal","Undying","Overlord","Corrupt","Hellspawn","Tyrant","Sanguineous")
if(owner.current.gender == MALE)
if(prob(10)) // Gender override
vampreputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King")
bloodsucker_reputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King")
else
if(prob(10)) // Gender override
vampreputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen")
bloodsucker_reputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen")
to_chat(owner, "<span class='announce'>You have earned a reputation! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
// Reputations [Fledgling]
else
vampreputation = pick ("Crude","Callow","Unlearned","Neophyte","Novice","Unseasoned","Fledgling","Young","Neonate","Scrapling","Untested","Unproven","Unknown","Newly Risen","Born","Scavenger","Unknowing",\
bloodsucker_reputation = pick ("Crude","Callow","Unlearned","Neophyte","Novice","Unseasoned","Fledgling","Young","Neonate","Scrapling","Untested","Unproven","Unknown","Newly Risen","Born","Scavenger","Unknowing",\
"Unspoiled","Disgraced","Defrocked","Shamed","Meek","Timid","Broken")//,"Fresh")
/datum/antagonist/bloodsucker/proc/AmFledgling()
return !vamptitle
return !bloodsucker_title
/datum/antagonist/bloodsucker/proc/ReturnFullName(var/include_rep=0)
var/fullname
// Name First
fullname = (vampname ? vampname : owner.current.name)
fullname = (bloodsucker_name ? bloodsucker_name : owner.current.name)
// Title
if(vamptitle)
fullname = vamptitle + " " + fullname
if(bloodsucker_title)
fullname = bloodsucker_title + " " + fullname
// Rep
if(include_rep && vampreputation)
fullname = fullname + " the " + vampreputation
if(include_rep && bloodsucker_reputation)
fullname = fullname + " the " + bloodsucker_reputation
return fullname
@@ -199,15 +197,12 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
// Make Changes
H.physiology.brute_mod *= 0.8 // <-------------------- Start small, but burn mod increases based on rank!
H.physiology.brute_mod *= 0.8
H.physiology.cold_mod = 0
H.physiology.stun_mod *= 0.5
H.physiology.siemens_coeff *= 0.75 //base electrocution coefficient 1
//S.heatmod += 0.5 // Heat shouldn't affect. Only Fire.
//S.punchstunthreshold = 8 //damage at which punches from this race will stun 9
S.punchdamagelow += 1 //lowest possible punch damage 0
S.punchdamagehigh += 1 //highest possible punch damage 9
// Clown
if(istype(H) && owner.assigned_role == "Clown")
H.dna.remove_mutation(CLOWNMUT)
to_chat(H, "As a vampiric clown, you are no longer a danger to yourself. Your nature is subdued.")
@@ -215,8 +210,6 @@
CheckVampOrgans() // Heart, Eyes
// Language
owner.current.grant_language(/datum/language/vampiric)
// Soul
//owner.current.hellbound = TRUE Causes wierd stuff
owner.hasSoul = FALSE // If false, renders the character unable to sell their soul.
owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles
// Disabilities
@@ -248,7 +241,6 @@
// Clown
if(istype(H) && owner.assigned_role == "Clown")
H.dna.add_mutation(CLOWNMUT)
// NOTE: Use initial() to return things to default!
// Physiology
owner.current.regenerate_organs()
// Update Health
@@ -264,13 +256,13 @@
set waitfor = FALSE
if(!owner || !owner.current)
return
vamplevel_unspent ++
bloodsucker_level_unspent ++
// Spend Rank Immediately?
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
SpendRank()
else
to_chat(owner, "<EM><span class='notice'>You have grown more ancient! Sleep in a coffin that you have claimed to thicken your blood and become more powerful.</span></EM>")
if(vamplevel_unspent >= 2)
if(bloodsucker_level_unspent >= 2)
to_chat(owner, "<span class='announce'>Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wooden planks.</span><br>")
/datum/antagonist/bloodsucker/proc/LevelUpPowers()
@@ -279,10 +271,10 @@
/datum/antagonist/bloodsucker/proc/SpendRank()
set waitfor = FALSE
if(vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current))
if(bloodsucker_level_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current))
return
var/mob/living/L = owner.current
level_bloodcost = maxBloodVolume * 0.2
level_bloodcost = max_blood_volume * 0.2
//If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker
//TODO: Make this into a radial, or perhaps a tgui next UI
@@ -298,7 +290,7 @@
if(options.len > 1)
var/choice = input(owner.current, "You have the opportunity to grow more ancient at the cost of [level_bloodcost] units of blood. Select a power to advance your Rank.", "Your Blood Thickens...") in options
// Cheat-Safety: Can't keep opening/closing coffin to spam levels
if(vamplevel_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal.
if(bloodsucker_level_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal.
return
if(!istype(owner.current.loc, /obj/structure/closet/crate/coffin))
to_chat(owner.current, "<span class='warning'>Return to your coffin to advance your Rank.</span>")
@@ -329,20 +321,20 @@
// More Health
owner.current.setMaxHealth(owner.current.maxHealth + 10)
// Vamp Stats
regenRate += 0.05 // Points of brute healed (starts at 0.3)
feedAmount += 2 // Increase how quickly I munch down vics (15)
maxBloodVolume += 100 // Increase my max blood (600)
regen_rate += 0.05 // Points of brute healed (starts at 0.3)
feed_amount += 2 // Increase how quickly I munch down vics (15)
max_blood_volume += 100 // Increase my max blood (600)
/////////
vamplevel ++
vamplevel_unspent --
bloodsucker_level ++
bloodsucker_level_unspent --
// Assign True Reputation
if(vamplevel == 4)
if(bloodsucker_level == 4)
SelectReputation(am_fledgling = FALSE, forced = TRUE)
to_chat(owner.current, "<span class='notice'>You are now a rank [vamplevel] Bloodsucker. Your strength, health, feed rate, regen rate, and maximum blood have all increased!</span>")
to_chat(owner.current, "<span class='notice'>You are now a rank [bloodsucker_level] Bloodsucker. Your strength, health, feed rate, regen rate, can have up to [bloodsucker_level - count_vassals(owner.current.mind)] vassals, and maximum blood have all increased!</span>")
to_chat(owner.current, "<span class='notice'>Your existing powers have all ranked up as well!</span>")
update_hud(TRUE)
owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, TRUE, pressure_affected = FALSE)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -654,13 +646,13 @@
var/datum/antagonist/vassal/mob_V = M.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
// Check 2) If they are a BLOODSUCKER, then are they my Master?
if (mob_V && atom_B == mob_V.master)
return TRUE // SUCCESS!
return TRUE
// Check 3) If I am a BLOODSUCKER, then are they my Vassal?
if (mob_B && atom_V && (atom_V in mob_B.vassals))
return TRUE // SUCCESS!
return TRUE
// Check 4) If we are both VASSAL, then do we have the same master?
if (atom_V && mob_V && atom_V.master == mob_V.master)
return TRUE // SUCCESS!
return TRUE
return FALSE
@@ -705,10 +697,10 @@
// Update Rank Counter
if(owner.current.hud_used.vamprank_display)
var/valuecolor = vamplevel_unspent ? "#FFFF00" : "#FF0000"
owner.current.hud_used.vamprank_display.update_counter(vamplevel, valuecolor)
var/valuecolor = bloodsucker_level_unspent ? "#FFFF00" : "#FF0000"
owner.current.hud_used.vamprank_display.update_counter(bloodsucker_level, valuecolor)
if(updateRank) // Only change icon on special request.
owner.current.hud_used.vamprank_display.icon_state = (vamplevel_unspent > 0) ? "rank_up" : "rank"
owner.current.hud_used.vamprank_display.icon_state = (bloodsucker_level_unspent > 0) ? "rank_up" : "rank"
/obj/screen/bloodsucker
@@ -718,12 +710,12 @@
invisibility = INVISIBILITY_ABSTRACT
/obj/screen/bloodsucker/proc/update_counter(value, valuecolor)
invisibility = 0 // Make Visible
invisibility = 0
/obj/screen/bloodsucker/blood_counter // NOTE: Look up /obj/screen/devil/soul_counter in _onclick / hud / human.dm
icon = 'icons/mob/actions/bloodsucker.dmi'//'icons/mob/screen_gen.dmi'
/obj/screen/bloodsucker/blood_counter
icon = 'icons/mob/actions/bloodsucker.dmi'
name = "Blood Consumed"
icon_state = "blood_display"//"power_display"
icon_state = "blood_display"
screen_loc = ui_blood_display
/obj/screen/bloodsucker/blood_counter/update_counter(value, valuecolor)
@@ -748,22 +740,27 @@
/datum/antagonist/bloodsucker/proc/update_sunlight(value, amDay = FALSE)
// No Hud? Get out.
if (!owner.current.hud_used)
if(!owner.current.hud_used)
return
// Update Sun Time
if (owner.current.hud_used.sunlight_display)
if(owner.current.hud_used.sunlight_display)
var/valuecolor = "#BBBBFF"
if (amDay)
if(amDay)
valuecolor = "#FF5555"
else if(value <= 25)
valuecolor = "#FFCCCC"
else if(value < 10)
valuecolor = "#FF5555"
var/value_string = (value >= 60) ? "[round(value / 60, 1)] m" : "[round(value,1)] s"
var/value_string = (value >= 60) ? "[round(value / 60, 1)] m" : "[round(value, 1)] s"
owner.current.hud_used.sunlight_display.update_counter( value_string, valuecolor )
owner.current.hud_used.sunlight_display.icon_state = "sunlight_" + (amDay ? "day":"night")
/obj/screen/bloodsucker/sunlight_counter/update_counter(value, valuecolor)
..()
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
/datum/antagonist/bloodsucker/proc/count_vassals(datum/mind/master)
var/datum/antagonist/bloodsucker/B = master.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/vassal_amount = B.vassals.len
return vassal_amount
@@ -5,7 +5,8 @@
var/obj/item/organ/O
// Heart
O = owner.current.getorganslot(ORGAN_SLOT_HEART)
if(!istype(O, /obj/item/organ/heart/vampheart))
if(!istype(O, /obj/item/organ/heart/vampheart) && !istype(O, /obj/item/organ/heart/demon))
qdel(O)
var/obj/item/organ/heart/vampheart/H = new
H.Insert(owner.current)
@@ -115,13 +115,15 @@
qdel(src)
/obj/structure/bloodsucker/vassalrack/examine(mob/user)
var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
. = ..()
if(isvamp(user) || isobserver(user))
if(B || isobserver(user))
. += {"<span class='cult'>This is the vassal rack, which allows you to thrall crewmembers into loyal minions in your service.</span>"}
. += {"<span class='cult'>You need to first secure the vassal rack by clicking on it while it is in your lair.</span>"}
. += {"<span class='cult'>Simply click and hold on a victim, and then drag their sprite on the vassal rack. Alt click on the vassal rack to unbuckle them.</span>"}
. += {"<span class='cult'>Make sure that the victim is handcuffed, or else they can simply run away or resist, as the process is not instant.</span>"}
. += {"<span class='cult'>To convert the victim, simply click on the vassal rack itself. Sharp weapons work faster than other tools.</span>"}
. += {"<span class='cult'> You have only the power for [B.bloodsucker_level - B.count_vassals(user.mind)] vassals</span>"}
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
. += {"<span class='cult'>This is the vassal rack, which allows your master to thrall crewmembers into his minions.\n
Aid your master in bringing their victims here and keeping them secure.\n
@@ -130,7 +132,7 @@
/obj/structure/bloodsucker/vassalrack/MouseDrop_T(atom/movable/O, mob/user)
if(!O.Adjacent(src) || O == user || !isliving(O) || !isliving(user) || useLock || has_buckled_mobs() || user.incapacitated())
return
if(!anchored && isvamp(user))
if(!anchored && AmBloodsucker(user))
to_chat(user, "<span class='danger'>Until this rack is secured in place, it cannot serve its purpose.</span>")
return
// PULL TARGET: Remember if I was pullin this guy, so we can restore this
@@ -183,7 +185,7 @@
/obj/structure/bloodsucker/vassalrack/user_unbuckle_mob(mob/living/M, mob/user)
// Attempt Unbuckle
if(!isvamp(user))
if(!AmBloodsucker(user))
if(M == user)
M.visible_message("<span class='danger'>[user] tries to release themself from the rack!</span>",\
"<span class='danger'>You attempt to release yourself from the rack!</span>") // For sound if not seen --> "<span class='italics'>You hear a squishy wet noise.</span>")
@@ -222,15 +224,15 @@
// Go away. Torturing.
if(useLock)
return
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
// CHECK ONE: Am I claiming this? Is it in the right place?
if(istype(bloodsuckerdatum) && !owner)
if(!bloodsuckerdatum.lair)
if(istype(B) && !owner)
if(!B.lair)
to_chat(user, "<span class='danger'>You don't have a lair. Claim a coffin to make that location your lair.</span>")
if(bloodsuckerdatum.lair != get_area(src))
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [bloodsuckerdatum.lair].</span>")
if(B.lair != get_area(src))
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [B.lair].</span>")
return
switch(alert(user,"Do you wish to afix this structure here? Be aware you wont be able to unsecure it anymore","Secure [src]","Yes", "No"))
switch(alert(user,"Do you wish to afix this structure here? Be aware you wont be able to unsecure it anymore", "Secure [src]", "Yes", "No"))
if("Yes")
owner = user
density = FALSE
@@ -241,27 +243,31 @@
return
// CHECK TWO: Am I a non-bloodsucker?
var/mob/living/carbon/C = pick(buckled_mobs)
if(!istype(bloodsuckerdatum))
if(!istype(B))
// Try to release this guy
user_unbuckle_mob(C, user)
return
// Bloodsucker Owner! Let the boy go.
if(C.mind)
var/datum/antagonist/vassal/vassaldatum = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD)
var/datum/antagonist/vassal/V = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(istype(V) && V.master == B || C.stat >= DEAD)
unbuckle_mob(C)
useLock = FALSE // Failsafe
return
// Just torture the boy
torture_victim(user, C)
#define CONVERT_COST 150
/obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
// Check Bloodmob/living/M, force = FALSE, check_loc = TRUE
var/convert_cost = 200 + 200 * bloodsuckerdatum.vassals
if(user.blood_volume < convert_cost + 5)
if(user.blood_volume < CONVERT_COST + 5)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target].</span>")
return
if(B.count_vassals(user.mind) > B.bloodsucker_level)
to_chat(user, "<span class='notice'>Your power is yet too weak to bring more vassals under your control....</span>")
return
// Prep...
useLock = TRUE
// Step One: Tick Down Conversion from 3 to 0
@@ -302,12 +308,13 @@
useLock = FALSE
return
// Check: Blood
if(user.blood_volume < convert_cost)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [convert_cost - user.blood_volume] units more!</span>")
if(user.blood_volume < CONVERT_COST)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [CONVERT_COST - user.blood_volume] units more!</span>")
useLock = FALSE
return
bloodsuckerdatum.AddBloodVolume(-convert_cost)
target.add_mob_blood(user)
B.AddBloodVolume(-CONVERT_COST)
target.add_mob_blood(user, "<span class='danger'>Youve used [CONVERT_COST] amount of blood to gain a new vassal!</span>")
to_chat(user, )
user.visible_message("<span class='notice'>[user] marks a bloody smear on [target]'s forehead and puts a wrist up to [target.p_their()] mouth!</span>", \
"<span class='notice'>You paint a bloody marking across [target]'s forehead, place your wrist to [target.p_their()] mouth, and subject [target.p_them()] to the Dark Communion.</span>")
if(!do_mob(user, src, 50))
@@ -315,21 +322,22 @@
useLock = FALSE
return
// Convert to Vassal!
if(bloodsuckerdatum && bloodsuckerdatum.attempt_turn_vassal(target))
if(B && B.attempt_turn_vassal(target))
//remove_loyalties(target) // In case of Mindshield, or appropriate Antag (Traitor, Internal, etc)
//if (!target.buckled)
// to_chat(user, "<span class='danger'><i>The ritual has been interrupted!</i></span>")
// useLock = FALSE
// return
user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
target.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE)
target.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE)
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
target.Jitter(25)
target.emote("laugh")
//remove_victim(target) // Remove on CLICK ONLY!
useLock = FALSE
/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/target, mult=1)
#undef CONVERT_COST
/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/target, mult = 1)
var/torture_time = 15 // Fifteen seconds if you aren't using anything. Shorter with weapons and such.
var/torture_dmg_brute = 2
var/torture_dmg_burn = 0
@@ -454,7 +462,7 @@
/obj/structure/bloodsucker/candelabrum/examine(mob/user)
. = ..()
if((isvamp()) || isobserver(user))
if((AmBloodsucker(user)) || isobserver(user))
. += {"<span class='cult'>This is a magical candle which drains at the sanity of mortals who are not under your command while it is active.</span>"}
. += {"<span class='cult'>You can alt click on it from any range to turn it on remotely, or simply be next to it and click on it to turn it on and off normally.</span>"}
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
@@ -463,12 +471,12 @@
/obj/structure/bloodsucker/candelabrum/attack_hand(mob/user)
var/datum/antagonist/vassal/T = user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(isvamp(user) || istype(T))
if(AmBloodsucker(user) || istype(T))
toggle()
/obj/structure/bloodsucker/candelabrum/AltClick(mob/user)
// Bloodsuckers can turn their candles on from a distance. SPOOOOKY.
if(isvamp(user))
if(AmBloodsucker(user))
toggle()
/obj/structure/bloodsucker/candelabrum/proc/toggle(mob/user)
@@ -485,7 +493,7 @@
if(lit)
for(var/mob/living/carbon/human/H in viewers(7, src))
var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(isvamp(H) || T) //We dont want vassals or vampires affected by this
if(AmBloodsucker(H) || T) //We dont want vassals or vampires affected by this
return
H.hallucination = 20
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "vampcandle", /datum/mood_event/vampcandle)
@@ -2,7 +2,7 @@
/datum/action/bloodsucker/cloak
name = "Cloak of Darkness"
desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas."
desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas, and you cannot dissapear while mortals watch you."
button_icon_state = "power_cloak"
bloodcost = 5
cooldown = 50
@@ -140,7 +140,7 @@
to_chat(user, "<span class='notice'>You lean quietly toward [target] and secretly draw out your fangs...</span>")
else
to_chat(user, "<span class='warning'>You pull [target] close to you and draw out your fangs...</span>")
if(!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10)
if(!do_mob(user, target, feed_time, 0, 1, extra_checks = CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10)
to_chat(user, "<span class='warning'>Your feeding was interrupted.</span>")
//DeactivatePower(user,target)
return
@@ -166,7 +166,7 @@
var/deadmessage = target.stat == DEAD ? "" : " <i>[target.p_they(TRUE)] looks dazed, and will not remember this.</i>"
user.visible_message("<span class='notice'>[user] puts [target]'s wrist up to [user.p_their()] mouth.</span>", \
"<span class='notice'>You secretly slip your fangs into [target]'s wrist.[deadmessage]</span>", \
vision_distance = notice_range, ignored_mobs=target) // Only people who AREN'T the target will notice this action.
vision_distance = notice_range, ignored_mobs = target) // Only people who AREN'T the target will notice this action.
// Warn Feeder about Witnesses...
var/was_unnoticed = TRUE
for(var/mob/living/M in viewers(notice_range, owner))
@@ -257,11 +257,11 @@
to_chat(user, "<span class='notice'>Your victim is dead. [target.p_their(TRUE)] blood barely nourishes you.</span>")
warning_target_dead = TRUE
// Full?
if(!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume)
if(!warning_full && user.blood_volume >= bloodsuckerdatum.max_blood_volume)
to_chat(user, "<span class='notice'>You are full. Further blood will be wasted.</span>")
warning_full = TRUE
// Blood Remaining? (Carbons/Humans only)
if(iscarbon(target) && !target.AmBloodsucker(1))
if(iscarbon(target) && !AmBloodsucker(target, TRUE))
if(target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD)
to_chat(user, "<span class='warning'>Your victim's blood volume is fatally low!</span>")
else if(target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY)
@@ -275,8 +275,9 @@
break
// Blood Gulp Sound
owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
if(!amSilent)
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
// DONE!
//DeactivatePower(user,target)
if(amSilent)
@@ -294,12 +295,12 @@
/datum/action/bloodsucker/feed/proc/CheckKilledTarget(mob/living/user, mob/living/target)
// Bad Vampire. You shouldn't do that.
// Bad Bloodsucker. You shouldn't do that.
if(target && target.stat >= DEAD && ishuman(target))
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankkilled", /datum/mood_event/drankkilled) // BAD // in bloodsucker_life.dm
/datum/action/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target)
return ..() && target && (!target_grappled || user.pulling == target)// Active, and still Antag,
return ..() && target && (!target_grappled || user.pulling == target) && blood_sucking_checks(target, TRUE, TRUE) // Active, and still antag,
// NOTE: We only care about pulling if target started off that way. Mostly only important for Aggressive feed.
/datum/action/bloodsucker/feed/proc/ApplyVictimEffects(mob/living/target)
@@ -30,7 +30,16 @@
var/was_running = (user.m_intent == MOVE_INTENT_RUN)
if(was_running)
user.toggle_move_intent()
while(B && ContinueActive(user) && !(user.m_intent == MOVE_INTENT_RUN))
while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN)
if(istype(user.buckled, /obj/vehicle)) //We dont want people using fortitude being able to use vehicles
var/obj/vehicle/V = user.buckled
var/datum/component/riding/VRD = V.GetComponent(/datum/component/riding)
if(VRD)
VRD.force_dismount(user)
to_chat(user, "<span class='notice'>You trip off the [V], your muscles too heavy for it to support you.</span>")
else
V.unbuckle_mob(user, force = TRUE)
to_chat(user, "<span class='notice'>You fall off the [V], your weight making you too heavy to be supported by it.</span>")
// Pay Blood Toll (if awake)
if(user.stat == CONSCIOUS)
B.AddBloodVolume(-0.5)
@@ -8,7 +8,7 @@
desc = "Dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed."
button_icon_state = "power_speed"
bloodcost = 6
cooldown = 50
cooldown = 120
target_range = 15
power_activates_immediately = TRUE
message_Trigger = ""//"Whom will you subvert to your will?"
@@ -64,7 +64,7 @@
to_chat(owner, "<span class='warning'>Your victim's eyes are glazed over. They cannot perceive you.</span>")
return FALSE
// Check: Target See Me? (behind wall)
if(!(target in view(target_range, get_turf(owner))))
if(!(target in viewers(target_range, get_turf(owner))))
// Sub-Check: GET CLOSER
//if (!(owner in range(target_range, get_turf(target)))
// if (display_error)
@@ -90,48 +90,56 @@
/datum/action/bloodsucker/targeted/mesmerize/proc/ContinueTarget(atom/A)
var/mob/living/carbon/target = A
var/mob/living/user = owner
var/mob/living/L = owner
var/cancontinue=CheckCanTarget(target)
var/cancontinue = CheckCanTarget(target)
if(!cancontinue)
success = FALSE
target.remove_status_effect(STATUS_EFFECT_MESMERIZE)
user.remove_status_effect(STATUS_EFFECT_MESMERIZE)
L.remove_status_effect(STATUS_EFFECT_MESMERIZE)
DeactivatePower()
DeactivateRangedAbility()
StartCooldown()
to_chat(user, "<span class='warning'>[target] has escaped your gaze!</span>")
to_chat(L, "<span class='warning'>[target] has escaped your gaze!</span>")
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
/datum/action/bloodsucker/targeted/mesmerize/FireTargetedPower(atom/A)
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
var/mob/living/carbon/target = A
var/mob/living/user = owner
var/mob/living/L = owner
L.face_atom(A)
if(!istype(target))
return
success = TRUE
var/power_time = 138 + level_current * 12
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
L.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
// 5 second windup
addtimer(CALLBACK(src, .proc/apply_effects, L, target, power_time), 6 SECONDS)
ADD_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
ADD_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(target))
success = TRUE
var/power_time = 138 + level_current * 12
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
user.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
/datum/action/bloodsucker/targeted/mesmerize/proc/apply_effects(aggressor, victim, power_time)
var/mob/living/carbon/target = victim
var/mob/living/L = aggressor
if(!success)
return
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time)
REMOVE_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
target.face_atom(L)
target.Stun(power_time)
to_chat(L, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
REMOVE_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(L) && target.stat == CONSCIOUS && (target in view(10, get_turf(L)))) // They Woke Up! (Notice if within view)
to_chat(L, "<span class='warning'>[target] has snapped out of their trance.</span>")
// 3 second windup
sleep(30)
if(success)
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.face_atom(user)
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) // pretty much purely cosmetic
target.Stun(power_time)
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
// They Woke Up! (Notice if within view)
if(istype(user) && target.stat == CONSCIOUS && (target in view(10, get_turf(user))) )
to_chat(user, "<span class='warning'>[target] has snapped out of their trance.</span>")
/datum/action/bloodsucker/targeted/mesmerize/ContinueActive(mob/living/user, mob/living/target)
return ..() && CheckCanUse() && CheckCanTarget(target)
@@ -31,6 +31,7 @@
var/isabsorbing = 0
var/islinking = 0
var/geneticpoints = 10
var/maxgeneticpoints = 10
var/purchasedpowers = list()
var/mimicing = ""
var/canrespec = 0
@@ -98,17 +99,24 @@
to_chat(H, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
/datum/antagonist/changeling/proc/reset_properties()
/datum/antagonist/changeling/proc/reset_properties(hardReset = FALSE)
changeling_speak = 0
chosen_sting = null
geneticpoints = initial(geneticpoints)
geneticpoints = maxgeneticpoints
sting_range = initial(sting_range)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
chem_charges = min(chem_charges, chem_storage)
chem_recharge_slowdown = initial(chem_recharge_slowdown)
mimicing = ""
if (hardReset)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
geneticpoints = initial(geneticpoints)
maxgeneticpoints = initial(maxgeneticpoints)
chem_charges = min(chem_charges, chem_storage)
/datum/antagonist/changeling/proc/remove_changeling_powers()
if(ishuman(owner.current) || ismonkey(owner.current))
reset_properties()
@@ -287,7 +295,6 @@
prof.name_list[slot] = I.name
prof.appearance_list[slot] = I.appearance
prof.flags_cover_list[slot] = I.flags_cover
prof.item_color_list[slot] = I.item_color
prof.item_state_list[slot] = I.item_state
prof.exists_list[slot] = 1
else
@@ -503,7 +510,6 @@
var/list/appearance_list = list()
var/list/flags_cover_list = list()
var/list/exists_list = list()
var/list/item_color_list = list()
var/list/item_state_list = list()
var/underwear
@@ -526,7 +532,6 @@
newprofile.appearance_list = appearance_list.Copy()
newprofile.flags_cover_list = flags_cover_list.Copy()
newprofile.exists_list = exists_list.Copy()
newprofile.item_color_list = item_color_list.Copy()
newprofile.item_state_list = item_state_list.Copy()
newprofile.underwear = underwear
newprofile.undershirt = undershirt
@@ -28,8 +28,7 @@
action.Remove(user)
return
/obj/effect/proc_holder/changeling/Click()
var/mob/user = usr
/obj/effect/proc_holder/changeling/Trigger(mob/user)
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
return
try_to_sting(user)
@@ -96,6 +96,7 @@
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
target_ling.remove_changeling_powers()
changeling.geneticpoints += round(target_ling.geneticpoints/2)
changeling.maxgeneticpoints += round(target_ling.geneticpoints/2)
target_ling.geneticpoints = 0
target_ling.canrespec = 0
changeling.chem_storage += round(target_ling.chem_storage/2)
@@ -3,8 +3,7 @@
desc = "Stabby stabby."
var/sting_icon = null
/obj/effect/proc_holder/changeling/sting/Click()
var/mob/user = usr
/obj/effect/proc_holder/changeling/sting/Trigger(mob/user)
if(!user || !user.mind)
return
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
@@ -74,8 +73,7 @@
action_icon_state = "ling_sting_transform"
action_background_icon_state = "bg_ling"
/obj/effect/proc_holder/changeling/sting/transformation/Click()
var/mob/user = usr
/obj/effect/proc_holder/changeling/sting/transformation/Trigger(mob/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.chosen_sting)
unset_sting(user)
@@ -279,9 +279,15 @@
sigil_name = "Vitality Matrix"
var/revive_cost = 150
var/sigil_active = FALSE
var/min_drain_health = -INFINITY
var/can_dust = TRUE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
/obj/effect/clockwork/sigil/vitality/neutered
min_drain_health = 20
can_dust = FALSE
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
. = ..()
if(is_servant_of_ratvar(user) || isobserver(user))
@@ -306,7 +312,7 @@
animation_number++
if(!is_servant_of_ratvar(L))
var/vitality_drained = 0
if(L.stat == DEAD && !consumed_vitality)
if(L.stat == DEAD && !consumed_vitality && can_dust)
consumed_vitality = TRUE //Prevent the target from being consumed multiple times
vitality_drained = L.maxHealth
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
@@ -318,7 +324,7 @@
if(!L.dropItemToGround(W))
qdel(W)
L.dust()
else
else if(L.health > min_drain_health)
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
vitality_drained = L.adjustToxLoss(1, forced = TRUE)
else
@@ -35,7 +35,7 @@
var/span_for_name = "heavy_brass"
var/span_for_message = "brass"
/datum/action/innate/hierophant/IsAvailable()
/datum/action/innate/hierophant/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
return FALSE
return ..()
@@ -12,7 +12,7 @@
var/obj/item/clockwork/weapon/weapon_type //The type of weapon to create
var/obj/item/clockwork/weapon/weapon
/datum/action/innate/call_weapon/IsAvailable()
/datum/action/innate/call_weapon/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
qdel(src)
return
@@ -127,7 +127,6 @@
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_gauntlets"
item_state = "clockwork_gauntlets"
item_color = null //So they don't wash.
strip_delay = 50
equip_delay_other = 30
body_parts_covered = ARMS
@@ -36,6 +36,24 @@
speed_multiplier = 0
no_cost = TRUE
/obj/item/clockwork/slab/traitor
var/spent = FALSE
/obj/item/clockwork/slab/traitor/check_uplink_validity()
return !spent
/obj/item/clockwork/slab/traitor/attack_self(mob/living/user)
if(!is_servant_of_ratvar(user) && !spent)
to_chat(user, "<span class='userdanger'>You press your hand onto [src], golden tendrils of light latching onto you. Was this the best of ideas?</span>")
if(add_servant_of_ratvar(user, FALSE, FALSE, /datum/antagonist/clockcult/neutered/traitor))
spent = TRUE
// Add some (5 KW) power so they don't suffer for 100 ticks
GLOB.clockwork_power += 5000
// This intentionally does not use adjust_clockwork_power.
else
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
return ..()
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
@@ -103,8 +121,8 @@
. = ..()
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
if(isinhands && item_state && inhand_overlay)
var/mutable_appearance/M = mutable_appearance(icon_file, "slab_[inhand_overlay]")
. += M
@@ -232,7 +232,7 @@
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
/datum/action/innate/eminence/IsAvailable()
/datum/action/innate/eminence/IsAvailable(silent = FALSE)
if(!iseminence(owner))
qdel(src)
return
@@ -283,7 +283,7 @@
desc = "Initiates a mass recall, warping all servants to the Ark after a short delay. This can only be used once."
button_icon_state = "Spatial Gateway"
/datum/action/innate/eminence/mass_recall/IsAvailable()
/datum/action/innate/eminence/mass_recall/IsAvailable(silent = FALSE)
. = ..()
if(.)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
@@ -30,6 +30,7 @@ Applications: 8 servants, 3 caches, and 100 CV
var/primary_component
var/important = FALSE //important scripture will be italicized in the slab's interface
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
var/requires_full_power = FALSE //requires the user to be a full, non neutered servant of ratvar
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
var/static/list/neovgre_penalty = list("Go to the station.", "Useless.", "Don't waste time.", "Pathetic.", "Wasteful.")
@@ -77,6 +78,9 @@ Applications: 8 servants, 3 caches, and 100 CV
/datum/clockwork_scripture/proc/can_recite() //If the words can be spoken
if(!invoker || !slab || invoker.get_active_held_item() != slab)
return FALSE
if(!is_servant_of_ratvar(invoker, requires_full_power))
to_chat(invoker, "<span class='warning'>You aren't strongly connected enough to Ratvar to invoke this!</span>")
return FALSE
if(!invoker.can_speak_vocal())
to_chat(invoker, "<span class='warning'>You are unable to speak the words of the scripture!</span>")
return FALSE
@@ -236,18 +240,21 @@ Applications: 8 servants, 3 caches, and 100 CV
return FALSE
return TRUE
/datum/clockwork_scripture/create_object/proc/get_spawn_path(mob/user)
return object_path
/datum/clockwork_scripture/create_object/scripture_effects()
if(creator_message && observer_message)
invoker.visible_message(observer_message, creator_message)
else if(creator_message)
to_chat(invoker, creator_message)
var/obj/O = new object_path (get_turf(invoker))
var/to_spawn = get_spawn_path(invoker)
var/obj/O = new to_spawn(get_turf(invoker))
O.ratvar_act() //update the new object so it gets buffed if ratvar is alive
if(isitem(O) && put_object_in_hands)
invoker.put_in_hands(O)
return TRUE
//Used specifically to create construct shells.
/datum/clockwork_scripture/create_object/construct
put_object_in_hands = FALSE
@@ -88,7 +88,7 @@
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
requires_full_power = TRUE
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
/datum/clockwork_scripture/ranged_ability/kindle
@@ -211,6 +211,7 @@
quickbind = TRUE
quickbind_desc = "Returns you to Reebe."
var/client_color
requires_full_power = TRUE
/datum/clockwork_scripture/abscond/check_special_requirements()
if(is_reebe(invoker.z))
@@ -50,7 +50,6 @@
return FALSE
return ..()
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
/datum/clockwork_scripture/create_object/vitality_matrix
descname = "Trap, Damage to Healing"
@@ -77,6 +76,10 @@
return FALSE
return ..()
/datum/clockwork_scripture/create_object/vitality_matrix/get_spawn_path(mob/user)
if(!is_servant_of_ratvar(user, TRUE))
return /obj/effect/clockwork/sigil/vitality/neutered
return ..()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
@@ -150,7 +153,7 @@
/obj/item/clothing/head/helmet/space,
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
/datum/action/innate/clockwork_armaments/IsAvailable()
/datum/action/innate/clockwork_armaments/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
qdel(src)
return
@@ -5,15 +5,27 @@
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
antag_moodlet = /datum/mood_event/cult
var/datum/action/innate/hierophant/hierophant_network = new
threat = 3
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
var/ignore_eligibility_check = FALSE
var/ignore_holy_water = FALSE
/datum/antagonist/clockcult/silent
silent = TRUE
show_in_antagpanel = FALSE //internal
/datum/antagonist/clockcult/neutered
neutered = TRUE
/datum/antagonist/clockcult/neutered/traitor
ignore_eligibility_check = TRUE
ignore_holy_water = TRUE
show_in_roundend = FALSE
make_team = FALSE
/datum/antagonist/clockcult/Destroy()
qdel(hierophant_network)
return ..()
@@ -38,7 +50,7 @@
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
if(. && !ignore_eligibility_check)
. = is_eligible_servant(new_owner.current)
/datum/antagonist/clockcult/greet()
+12 -5
View File
@@ -17,7 +17,7 @@
qdel(X)
..()
/datum/action/innate/cult/blood_magic/IsAvailable()
/datum/action/innate/cult/blood_magic/IsAvailable(silent = FALSE)
if(!iscultist(owner))
return FALSE
return ..()
@@ -118,7 +118,7 @@
hand_magic = null
..()
/datum/action/innate/cult/blood_spell/IsAvailable()
/datum/action/innate/cult/blood_spell/IsAvailable(silent = FALSE)
if(!iscultist(owner) || owner.incapacitated() || !charges)
return FALSE
return ..()
@@ -439,7 +439,7 @@
"<span class='userdanger'>A feeling of warmth washes over you, rays of holy light surround your body and protect you from the flash of light!</span>")
else // cult doesn't stun any longer when halos are out, instead it does burn damage + knockback!
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(user_antag.cult_team.cult_ascendent)
if(user_antag.cult_team?.cult_ascendent)
if(!iscultist(L))
L.adjustFireLoss(20)
if(L.move_resist < MOVE_FORCE_STRONG)
@@ -577,7 +577,9 @@
var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/candidate = target
if(candidate.use(50))
if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
else if(candidate.use(50))
uses--
to_chat(user, "<span class='warning'>A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
@@ -600,7 +602,9 @@
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi)
if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
else if(candidate.mmi)
user.visible_message("<span class='danger'>A dark cloud emanates from [user]'s hand and swirls around [candidate]!</span>")
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
var/prev_color = candidate.color
@@ -656,6 +660,7 @@
C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), SLOT_WEAR_SUIT)
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), SLOT_SHOES)
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), SLOT_BACK)
C.equip_to_slot_or_del(new /obj/item/clothing/gloves/fingerless/pugilist/hungryghost(user), SLOT_GLOVES)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade(user))
@@ -819,6 +824,8 @@
if("Blood Beam (500)")
if(uses < 500)
to_chat(user, "<span class='cultitalic'>You need 500 charges to perform this rite.</span>")
else if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected to Nar'sie enough to use something of this power.</span>")
else
var/obj/rite = new /obj/item/blood_beam()
uses -= 500
+21 -9
View File
@@ -11,15 +11,27 @@
var/datum/action/innate/cult/blood_magic/magic = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
var/make_team = TRUE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
var/ignore_eligibility_checks = FALSE
var/ignore_holy_water = FALSE
/datum/antagonist/cult/neutered
neutered = TRUE
/datum/antagonist/cult/neutered/traitor
ignore_eligibility_checks = TRUE
ignore_holy_water = TRUE
show_in_roundend = FALSE
make_team = FALSE
/datum/antagonist/cult/get_team()
return cult_team
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
if(!new_team)
if(!new_team && make_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
if(!H.owner)
@@ -30,12 +42,12 @@
cult_team = new /datum/team/cult
cult_team.setup_objectives()
return
if(!istype(new_team))
if(make_team && !istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
cult_team = new_team
/datum/antagonist/cult/proc/add_objectives()
objectives |= cult_team.objectives
objectives |= cult_team?.objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
@@ -44,7 +56,7 @@
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
if(. && !ignore_implant && !ignore_eligibility_checks)
. = is_convertable_to_cult(new_owner.current,cult_team)
/datum/antagonist/cult/greet()
@@ -62,7 +74,7 @@
SSticker.mode.update_cult_icons_added(owner)
current.log_message("has been converted to the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
if(cult_team?.blood_target && cult_team.blood_target_image && current.client)
current.client.images += cult_team.blood_target_image
@@ -105,13 +117,13 @@
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
if(!cult_team.cult_master)
if(!cult_team?.cult_master)
vote.Grant(current)
communion.Grant(current)
if(ishuman(current))
magic.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
if(cult_team.cult_risen)
if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
@@ -144,7 +156,7 @@
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!</span>", null, null, null, owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("has renounced the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
if(cult_team?.blood_target && cult_team.blood_target_image && owner.current.client)
owner.current.client.images -= cult_team.blood_target_image
. = ..()
@@ -206,7 +218,7 @@
throwing.Grant(current)
current.update_action_buttons_icon()
current.apply_status_effect(/datum/status_effect/cult_master)
if(cult_team.cult_risen)
if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
+26 -14
View File
@@ -6,7 +6,7 @@
buttontooltipstyle = "cult"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
/datum/action/innate/cult/IsAvailable()
/datum/action/innate/cult/IsAvailable(silent = FALSE)
if(!iscultist(owner))
return FALSE
return ..()
@@ -51,7 +51,7 @@
name = "Spiritual Communion"
desc = "Conveys a message from the spirit realm that all cultists can hear."
/datum/action/innate/cult/comm/spirit/IsAvailable()
/datum/action/innate/cult/comm/spirit/IsAvailable(silent = FALSE)
if(iscultist(owner.mind.current))
return TRUE
@@ -72,9 +72,9 @@
name = "Assert Leadership"
button_icon_state = "cultvote"
/datum/action/innate/cult/mastervote/IsAvailable()
/datum/action/innate/cult/mastervote/IsAvailable(silent = FALSE)
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
if(!C?.cult_team || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
@@ -82,6 +82,9 @@
var/choice = alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
if(choice == "Yes" && IsAvailable())
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(owner, "<span class='cult bold'>Do you not alreaady lead yourself?</span>")
return
pollCultists(owner,C.cult_team)
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
@@ -137,7 +140,7 @@
to_chat(B.current,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!</span>")
return TRUE
/datum/action/innate/cult/master/IsAvailable()
/datum/action/innate/cult/master/IsAvailable(silent = FALSE)
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master) || GLOB.cult_narsie)
return 0
return ..()
@@ -151,6 +154,9 @@
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
if(!antag.cult_team)
to_chat(owner, "<span class='cult bold'>You have no team. You are alone.</span>")
return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -220,9 +226,9 @@
CM.attached_action = src
..()
/datum/action/innate/cult/master/cultmark/IsAvailable()
/datum/action/innate/cult/master/cultmark/IsAvailable(silent = FALSE)
if(cooldown > world.time)
if(!CM.active)
if(!CM.active && !silent)
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!</b></span>")
return FALSE
return ..()
@@ -261,7 +267,10 @@
return FALSE
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(ranged_ability_user, "<span class='cultlarge'>What is the point of marking a target for yourself?</span>")
remove_ranged_ability()
return
if(target in view(7, get_turf(ranged_ability_user)))
if(C.cult_team.blood_target)
to_chat(ranged_ability_user, "<span class='cult'>The cult has already designated a target!</span>")
@@ -299,7 +308,7 @@
name = "Mark a Blood Target for the Cult"
desc = "Marks a target for the entire cult to track."
/datum/action/innate/cult/master/cultmark/ghost/IsAvailable()
/datum/action/innate/cult/master/cultmark/ghost/IsAvailable(silent = FALSE)
if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current))
return TRUE
else
@@ -313,7 +322,7 @@
var/cooldown = 0
var/base_cooldown = 600
/datum/action/innate/cult/ghostmark/IsAvailable()
/datum/action/innate/cult/ghostmark/IsAvailable(silent = FALSE)
if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current))
return TRUE
else
@@ -330,8 +339,11 @@
/datum/action/innate/cult/ghostmark/Activate()
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(owner, "<span class='cultbold'>You are alone. You do not have a team.</span>")
return
if(C.cult_team.blood_target)
if(cooldown>world.time)
if(cooldown > world.time)
reset_blood_target(C.cult_team)
to_chat(owner, "<span class='cultbold'>You have cleared the cult's blood target!</span>")
deltimer(C.cult_team.blood_target_reset_timer)
@@ -339,7 +351,7 @@
else
to_chat(owner, "<span class='cultbold'>The cult has already designated a target!</span>")
return
if(cooldown>world.time)
if(cooldown > world.time)
to_chat(owner, "<span class='cultbold'>You aren't ready to place another blood mark yet!</span>")
return
target = owner.orbiting?.parent || get_turf(owner)
@@ -389,11 +401,11 @@
PM.attached_action = src
..()
/datum/action/innate/cult/master/pulse/IsAvailable()
/datum/action/innate/cult/master/pulse/IsAvailable(silent = FALSE)
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master))
return FALSE
if(cooldown > world.time)
if(!PM.active)
if(!PM.active && !silent)
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!</b></span>")
return FALSE
return ..()
+20 -5
View File
@@ -6,6 +6,21 @@
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
/obj/item/tome/traitor
var/spent = FALSE
/obj/item/tome/traitor/check_uplink_validity()
return !spent
/obj/item/tome/traitor/attack_self(mob/living/user)
if(!iscultist(user) && !spent)
to_chat(user, "<span class='userdanger'>You press your hand onto [src], sinister tendrils of corrupted magic swirling around you. Was this the best of ideas?</span>")
if(user.mind.add_antag_datum(/datum/antagonist/cult/neutered/traitor))
spent = TRUE
else
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
return ..()
/obj/item/melee/cultblade/dagger
name = "ritual dagger"
desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods."
@@ -207,7 +222,7 @@
phasein = /obj/effect/temp_visual/dir_setting/cult/phase
phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
/datum/action/innate/dash/cult/IsAvailable()
/datum/action/innate/dash/cult/IsAvailable(silent = FALSE)
if(iscultist(holder) && current_charges)
return TRUE
else
@@ -227,7 +242,7 @@
sword = bastard
holder = user
/datum/action/innate/cult/spin2win/IsAvailable()
/datum/action/innate/cult/spin2win/IsAvailable(silent = FALSE)
if(iscultist(holder) && cooldown <= world.time)
return TRUE
else
@@ -436,8 +451,8 @@
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, style_flags = NONE)
. = list()
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands && current_charges)
. += mutable_appearance('icons/effects/cult_effects.dmi', "shield-cult", MOB_LAYER + 0.01)
@@ -509,7 +524,7 @@
var/static/curselimit = 0
/obj/item/shuttle_curse/attack_self(mob/living/user)
if(!iscultist(user))
if(!iscultist(user, TRUE))
user.dropItemToGround(src, TRUE)
user.DefaultCombatKnockdown(100)
to_chat(user, "<span class='warning'>A powerful force shoves you away from [src]!</span>")
+5 -2
View File
@@ -59,6 +59,9 @@ This file contains the cult dagger and rune list code
rune_to_scribe = GLOB.rune_types[entered_rune_name]
if(!rune_to_scribe)
return
if(!iscultist(user, initial(rune_to_scribe.requires_full_power)))
to_chat(user, "<span class='warning'>You aren't strongly connected enough to Nar'sie to do draw this.</span>")
return
if(initial(rune_to_scribe.req_keyword))
chosen_keyword = stripped_input(user, "Enter a keyword for the new rune.", "Words of Power")
if(!chosen_keyword)
@@ -84,8 +87,8 @@ This file contains the cult dagger and rune list code
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
return
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team?.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team?.objectives
if(!summon_objective)
to_chat(user, "<span class='warning'>Nar'Sie does not wish to be summoned!</span>")
return
@@ -14,7 +14,7 @@
var/obj/effect/temp_visual/cult/rune_spawn/rune_center_type
var/rune_color
/datum/action/innate/cult/create_rune/IsAvailable()
/datum/action/innate/cult/create_rune/IsAvailable(silent = FALSE)
if(!rune_type || cooldown > world.time)
return FALSE
return ..()
+11
View File
@@ -32,6 +32,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
var/scribe_delay = 40 //how long the rune takes to create
var/scribe_damage = 0.1 //how much damage you take doing it
var/requires_full_power = FALSE //requires full power to draw or invoke
var/invoke_damage = 0 //how much damage invokers take when invoking it
var/construct_invoke = TRUE //if constructs can invoke it
@@ -185,6 +186,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_OFFER
req_cultists = 1
rune_in_use = FALSE
requires_full_power = TRUE
/obj/effect/rune/convert/do_invoke_glow()
return
@@ -458,6 +460,7 @@ structure_check() searches for nearby cultist structures required for the invoca
pixel_y = -32
scribe_delay = 500 //how long the rune takes to create
scribe_damage = 40.1 //how much damage you take doing it
requires_full_power = TRUE
var/used = FALSE
/obj/effect/rune/narsie/Initialize(mapload, set_keyword)
@@ -482,6 +485,9 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
return
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag.cult_team)
to_chat(user, "<span class='cultlarge'>You can't seem to make the arcane links to your fellows that you'd need to use this.</span>")
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/area/place = get_area(src)
if(!(place in summon_objective.summon_spots))
@@ -812,6 +818,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invoke_damage = 10
construct_invoke = FALSE
color = RUNE_COLOR_DARKRED
requires_full_power = TRUE
var/mob/living/affecting = null
var/ghost_limit = 3
var/ghosts = 0
@@ -942,6 +949,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
req_cultists = 3
scribe_delay = 100
requires_full_power = TRUE
/obj/effect/rune/apocalypse/invoke(var/list/invokers)
if(rune_in_use)
@@ -950,6 +958,9 @@ structure_check() searches for nearby cultist structures required for the invoca
var/area/place = get_area(src)
var/mob/living/user = invokers[1]
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag.cult_team)
to_chat(user, "<span class='cultlarge'>You can't seem to make the arcane links to your fellows that you'd need to use this.</span>")
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
if(summon_objective.summon_spots.len <= 1)
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
@@ -12,12 +12,7 @@
var/obj/item/r_hand = get_item_for_held_index(2)
if(r_hand)
var/r_state = r_hand.item_state
if(!r_state)
r_state = r_hand.icon_state
var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(state = r_state, default_layer = DEVIL_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE)
var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(default_layer = DEVIL_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE)
hands_overlays += r_hand_overlay
@@ -28,12 +23,7 @@
client.screen |= r_hand
if(l_hand)
var/l_state = l_hand.item_state
if(!l_state)
l_state = l_hand.icon_state
var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(state = l_state, default_layer = DEVIL_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE)
var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(default_layer = DEVIL_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE)
hands_overlays += l_hand_overlay
+61 -2
View File
@@ -179,8 +179,8 @@
/obj/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
if(resistance_flags & INDESTRUCTIBLE)
return FALSE
for(var/mob/living/L in contents)
if(!issilicon(L) && !isbrain(L))
for(var/mob/living/L in GetAllContents())
if(!ispAI(L) && !isbrain(L))
to_chat(S, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
return FALSE
return ..()
@@ -416,6 +416,57 @@
to_chat(S, "<span class='warning'>Destroying this object would cause a catastrophic chain reaction. Aborting.</span>")
return FALSE
/obj/machinery/ore_silo/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object, however tempting it's, will disrupt the research development that may serve for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/rnd/server/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object, will disrupt the research development that may serve for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) //pool's closed, but not.
to_chat(S, "<span class='warning'>The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.</span>")
return FALSE
/obj/structure/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.</span>")
return FALSE
/obj/structure/holosign/barrier/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
var/static/list/lazy_typecache = typecacheof(list(/obj/structure/holosign/barrier/engineering, /obj/structure/holosign/barrier/firelock, /obj/structure/holosign/barrier/atmos, /obj/structure/holosign/barrier/combifan))
if(lazy_typecache[type])
to_chat(S, "<span class='warning'>Destroying this holographic barrier may not benefit us. Aborting.</span>")
return FALSE
return ..()
/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/computer/bsa_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/bsa/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/dna_vault/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/structure/filler/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/computer/sat_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object will lower the station shielding against space debris. Aborting.</span>")
return FALSE
/obj/machinery/satellite/meteor_shield/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object will lower the station shielding against space debris. Aborting.</span>")
return FALSE
////END CTRL CLICK FOR SWARMERS////
/mob/living/simple_animal/hostile/swarmer/proc/Fabricate(atom/fabrication_object,fabrication_cost = 0)
@@ -429,6 +480,14 @@
return new fabrication_object(loc)
/mob/living/simple_animal/hostile/swarmer/proc/Integrate(atom/movable/target)
if(isobj(target))
var/obj/O = target
if(O.resistance_flags & INDESTRUCTIBLE)
return FALSE
for(var/mob/living/L in GetAllContents())
if(!ispAI(L) && !isbrain(L))
to_chat(src, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
return FALSE
var/resource_gain = target.IntegrateAmount()
if(resources + resource_gain > max_resources)
to_chat(src, "<span class='warning'>We cannot hold more materials!</span>")
@@ -1,10 +1,10 @@
/datum/round_event_control/spawn_swarmer
name = "Spawn Swarmer Shell"
typepath = /datum/round_event/spawn_swarmer
weight = 0
max_occurrences = 0
weight = 7
max_occurrences = 1 //Only once okay fam
earliest_start = 30 MINUTES
min_players = 15
min_players = 35
gamemode_blacklist = list("dynamic")
@@ -38,8 +38,8 @@
weights[C] = weight
var/choice = pickweightAllowZero(weights)
if(!choice)
choice = GLOB.traitor_classes[TRAITOR_HUMAN]
set_traitor_kind(pickweightAllowZero(weights))
choice = GLOB.traitor_classes[TRAITOR_HUMAN] // it's an "easter egg"
set_traitor_kind(choice)
traitor_kind.weight *= 0.8 // less likely this round
SSticker.mode.traitors += owner
owner.special_role = special_role
@@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
else
owner_AI = owner
/datum/action/innate/ai/IsAvailable()
/datum/action/innate/ai/IsAvailable(silent = FALSE)
. = ..()
if(owner_AI && owner_AI.malf_cooldown > world.time)
return FALSE
@@ -31,12 +31,12 @@
/obj/item/soulstone/pickup(mob/living/user)
..()
if(!iscultist(user) && !iswizard(user) && !usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.</span>")
/obj/item/soulstone/examine(mob/user)
. = ..()
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
if(usability || iscultist(user, TRUE) || iswizard(user) || isobserver(user))
if (old_shard)
. += "<span class='cult'>A soulstone, used to capture a soul, either from dead humans or from freed shades.</span>"
else
@@ -53,7 +53,7 @@
//////////////////////////////Capturing////////////////////////////////////////////////////////
/obj/item/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
if(!iscultist(user) && !iswizard(user) && !usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(100)
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
return
@@ -74,7 +74,7 @@
/obj/item/soulstone/attack_self(mob/living/user)
if(!in_range(src, user))
return
if(!iscultist(user) && !iswizard(user) && !usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(100)
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
return
@@ -103,7 +103,7 @@
/obj/structure/constructshell/examine(mob/user)
. = ..()
if(iscultist(user) || iswizard(user) || user.stat == DEAD)
if(iscultist(user, TRUE) || iswizard(user) || user.stat == DEAD)
. += "<span class='cult'>A construct shell, used to house bound souls from a soulstone.</span>"
. += "<span class='cult'>Placing a soulstone with a soul into this shell allows you to produce your choice of the following:</span>"
. += "<span class='cult'>An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.</span>"
@@ -113,7 +113,7 @@
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/soulstone))
var/obj/item/soulstone/SS = O
if(!iscultist(user) && !iswizard(user) && !SS.usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !SS.usability)
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.</span>")
user.Dizzy(30)
return
@@ -145,7 +145,7 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(C && C.cult_team.is_sacrifice_target(T.mind))
if(C && C.cult_team?.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
else