More fixes. Urgh

This commit is contained in:
Artur
2019-12-08 21:47:25 +02:00
parent 4711eb0987
commit 9773b530f8
21 changed files with 201 additions and 238 deletions

View File

@@ -73,56 +73,6 @@
// Blood Gulp Sound
owner.current.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.
/datum/mood_event/drankblood
description = "<span class='nicegreen'>I have fed greedly from that which nourishes me.</span>\n"
mood_change = 10
timeout = 900
/datum/mood_event/drankblood_bad
description = "<span class='boldwarning'>I drank the blood of a lesser creature. Disgusting.</span>\n"
mood_change = -4
timeout = 900
/datum/mood_event/drankblood_dead
description = "<span class='boldwarning'>I drank dead blood. I am better than this.</span>\n"
mood_change = -7
timeout = 900
/datum/mood_event/drankblood_synth
description = "<span class='boldwarning'>I drank synthetic blood. What is wrong with me?</span>\n"
mood_change = -7
timeout = 900
/datum/mood_event/drankkilled
description = "<span class='boldwarning'>I drank from my victim until they died. I feel...less human.</span>\n"
mood_change = -12
timeout = 6000
/datum/mood_event/madevamp
description = "<span class='boldwarning'>A soul has been cursed to undeath by my own hand.</span>\n"
mood_change = -10
timeout = 10000
/datum/mood_event/vampatefood
description = "<span class='boldwarning'>Mortal nourishment no longer sustains me. I feel unwell.</span>\n"
mood_change = -6
timeout = 1000
/datum/mood_event/coffinsleep
description = "<span class='nicegreen'>I slept in a coffin during the day. I feel whole again.</span>\n"
mood_change = 8
timeout = 1200
/datum/mood_event/daylight_1
description = "<span class='boldwarning'>I slept poorly in a makeshift coffin during the day.</span>\n"
mood_change = -3
timeout = 1000
/datum/mood_event/daylight_2
description = "<span class='boldwarning'>I have been scorched by the unforgiving rays of the sun.</span>\n"
mood_change = -6
timeout = 1200
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HEALING
@@ -138,10 +88,10 @@
owner.current.adjustCloneLoss(-1 * (regenRate * 4) * mult, 0)
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (regenRate * 4) * mult) //adjustBrainLoss(-1 * (regenRate * 4) * mult, 0)
// 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 (iscarbon(owner.current)) // Damage Heal: Do I have damage to ANY bodypart?
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)
@@ -150,9 +100,10 @@
mult *= 5 // 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
C.ExtinguishMob() // Extinguish Fire
C.ExtinguishMob()
CureDisabilities() // Extinguish Fire
else
if (owner.current.blood_volume <= 0) // No Blood? Lower Mult
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())
@@ -161,8 +112,8 @@
var/bruteheal = min(C.getBruteLoss_nonProsthetic(), regenRate)
var/toxinheal = min(C.getToxLoss(), regenRate)
// Heal if Damaged
if (bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
if (mult == 0)
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
if(mult == 0)
return TRUE
// We have damage. Let's heal (one time)
C.adjustBruteLoss(-bruteheal * mult, forced=TRUE)// Heal BRUTE / BURN in random portions throughout the body.
@@ -171,7 +122,7 @@
//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) / mult * costMult) // Costs blood to heal
return TRUE // Healed! Done for this tick.
if (amInCoffinWhileTorpor) // Limbs? (And I have no other healing)
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.
@@ -193,7 +144,6 @@
return TRUE
// NOTE: Limbs have a "status", like their hosts "stat". 2 is dead (aka Prosthetic). 1 seems to be idle/alive.
*/
CureDisabilities() // Cure Final Disabilities
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
@@ -328,7 +278,7 @@
var/mob/living/carbon/C = owner.current
C.remove_all_embedded_objects()
// Make me UN-CLONEABLE
owner.current.hellbound = TRUE // This was done during creation, but let's do it again one more time...to make SURE this guy stays dead.
owner.current.hellbound = TRUE // This was done during creation, but let's do it again one more time...to make SURE this guy stays dead, but they dont stay dead because brains can be cloned!
// Free my Vassals!
FreeAllVassals()
// Elders get Dusted
@@ -342,7 +292,7 @@
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()
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)

View File

@@ -24,18 +24,18 @@
time_til_cycle = TIME_BLOODSUCKER_NIGHT
// Part 1: Night (all is well)
while (time_til_cycle > TIME_BLOODSUCKER_DAY_WARN)
while(time_til_cycle > TIME_BLOODSUCKER_DAY_WARN)
sleep(10)
if (cancel_me)
if(cancel_me)
return
//sleep(TIME_BLOODSUCKER_NIGHT - TIME_BLOODSUCKER_DAY_WARN)
warn_daylight(1,"<span class = 'danger'>Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>") // time2text <-- use Help On
give_home_power() // Give VANISHING ACT power to all vamps with a lair!
// Part 2: Night Ending
while (time_til_cycle > TIME_BLOODSUCKER_DAY_FINAL_WARN)
while(time_til_cycle > TIME_BLOODSUCKER_DAY_FINAL_WARN)
sleep(10)
if (cancel_me)
if(cancel_me)
return
//sleep(TIME_BLOODSUCKER_DAY_WARN - TIME_BLOODSUCKER_DAY_FINAL_WARN)
message_admins("BLOODSUCKER NOTICE: Daylight beginning in [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds.)")
@@ -43,7 +43,7 @@
"<span class = 'danger'>In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!</span>")
// (FINAL LIL WARNING)
while (time_til_cycle > 5)
while(time_til_cycle > 5)
sleep(10)
if (cancel_me)
return
@@ -90,56 +90,56 @@
while(!cancel_me)
// Update all Bloodsucker sunlight huds
for (var/datum/mind/M in SSticker.mode.bloodsuckers)
if (!istype(M) || !istype(M.current))
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
if(!istype(M) || !istype(M.current))
continue
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (istype(bloodsuckerdatum))
if(istype(bloodsuckerdatum))
bloodsuckerdatum.update_sunlight(max(0, time_til_cycle), amDay) // This pings all HUDs
sleep(10)
time_til_cycle --
/obj/effect/sunlight/proc/warn_daylight(danger_level=0, vampwarn = "", vassalwarn = "")
for (var/datum/mind/M in SSticker.mode.bloodsuckers)
if (!istype(M))
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
if(!istype(M))
continue
to_chat(M,vampwarn)
if (M.current)
if (danger_level == 1)
if(M.current)
if(danger_level == 1)
M.current.playsound_local(null, 'sound/chatter/griffin_3.ogg', 50 + danger_level, 1)
else if (danger_level == 2)
else if(danger_level == 2)
M.current.playsound_local(null, 'sound/chatter/griffin_5.ogg', 50 + danger_level, 1)
else if (danger_level == 3)
else if(danger_level == 3)
M.current.playsound_local(null, 'sound/effects/alert.ogg', 75, 1)
else if (danger_level == 4)
else if(danger_level == 4)
M.current.playsound_local(null, 'sound/ambience/ambimystery.ogg', 100, 1)
else if (danger_level == 5)
else if(danger_level == 5)
M.current.playsound_local(null, 'sound/spookoween/ghosty_wind.ogg', 90, 1)
if (vassalwarn != "")
for (var/datum/mind/M in SSticker.mode.vassals)
if (!istype(M))
if(vassalwarn != "")
for(var/datum/mind/M in SSticker.mode.vassals)
if(!istype(M))
continue
to_chat(M,vassalwarn)
/obj/effect/sunlight/proc/punish_vamps()
// Cycle through all vamp antags and check if they're inside a closet.
for (var/datum/mind/M in SSticker.mode.bloodsuckers)
if (!istype(M) || !istype(M.current))
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
if(!istype(M) || !istype(M.current))
continue
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (!istype(bloodsuckerdatum))
if(!istype(bloodsuckerdatum))
continue
// Closets offer SOME protection
if (istype(M.current.loc, /obj/structure))
if(istype(M.current.loc, /obj/structure))
// Coffins offer the BEST protection
if (istype(M.current.loc, /obj/structure/closet/crate/coffin))
if(istype(M.current.loc, /obj/structure/closet/crate/coffin))
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/coffinsleep)
continue
else
if (!bloodsuckerdatum.warn_sun_locker)
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)
@@ -147,15 +147,15 @@
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.warn_sun_burn)
if(bloodsuckerdatum.vamplevel > 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)
if(M.current.fire_stacks <= 0)
M.current.fire_stacks = 0
if (bloodsuckerdatum.vamplevel > 0)
if(bloodsuckerdatum.vamplevel > 0)
M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.vamplevel / 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)
@@ -163,36 +163,36 @@
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_2)
/obj/effect/sunlight/proc/day_end()
for (var/datum/mind/M in SSticker.mode.bloodsuckers)
if (!istype(M) || !istype(M.current))
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
if(!istype(M) || !istype(M.current))
continue
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (!istype(bloodsuckerdatum))
if(!istype(bloodsuckerdatum))
continue
// Reset Warnings
bloodsuckerdatum.warn_sun_locker = FALSE
bloodsuckerdatum.warn_sun_burn = FALSE
// Remove Dawn Powers
for(var/datum/action/bloodsucker/P in bloodsuckerdatum.powers)
if (istype(P, /datum/action/bloodsucker/gohome))
if(istype(P, /datum/action/bloodsucker/gohome))
bloodsuckerdatum.powers -= P
P.Remove(M.current)
/obj/effect/sunlight/proc/vamps_rank_up()
set waitfor = FALSE
// Cycle through all vamp antags and check if they're inside a closet.
for (var/datum/mind/M in SSticker.mode.bloodsuckers)
if (!istype(M) || !istype(M.current))
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
if(!istype(M) || !istype(M.current))
continue
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (istype(bloodsuckerdatum))
if(istype(bloodsuckerdatum))
bloodsuckerdatum.RankUp() // Rank up! Must still be in a coffin to level!
/obj/effect/sunlight/proc/give_home_power()
// It's late...! Give the "Vanishing Act" gohome power to bloodsuckers.
for (var/datum/mind/M in SSticker.mode.bloodsuckers)
if (!istype(M) || !istype(M.current))
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
if(!istype(M) || !istype(M.current))
continue
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (istype(bloodsuckerdatum) && bloodsuckerdatum.lair && !(locate(/datum/action/bloodsucker/gohome) in bloodsuckerdatum.powers))
if(istype(bloodsuckerdatum) && bloodsuckerdatum.lair && !(locate(/datum/action/bloodsucker/gohome) in bloodsuckerdatum.powers))
bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/gohome)

View File

@@ -36,7 +36,7 @@
// LISTS
var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_VIRUSIMMUNE, TRAIT_NIGHT_VISION, \
TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE)
TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_NOCLONE)
// NOTES: TRAIT_AGEUSIA <-- Doesn't like flavors.
// REMOVED: TRAIT_NODEATH
// TO ADD:
@@ -187,6 +187,8 @@
// Traits
for (var/T in defaultTraits)
ADD_TRAIT(owner.current, T, "bloodsucker")
if(HAS_TRAIT(owner.current, TRAIT_TOXINLOVER)) //No slime bonuses here, no thank you
REMOVE_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
// Traits: Species
if (ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
@@ -233,14 +235,14 @@
power.Remove(owner.current)
// owner.RemoveSpell(power)
// Traits
for (var/T in defaultTraits)
for(var/T in defaultTraits)
REMOVE_TRAIT(owner.current, T, "bloodsucker")
// Traits: Species
if (ishuman(owner.current))
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(H.dna.species.type)
// Stats
if (ishuman(owner.current))
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(H.dna.species.type)
// Clown
@@ -260,15 +262,15 @@
datum/antagonist/bloodsucker/proc/RankUp()
set waitfor = FALSE
if (!owner || !owner.current)
if(!owner || !owner.current)
return
vamplevel_unspent ++
// Spend Rank Immediately?
if (istype(owner.current.loc, /obj/structure/closet/crate/coffin))
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(vamplevel_unspent >= 2)
to_chat(owner, "<span class='announce'>Bloodsucker Tip: If you cannot find or steal a coffin to use, they can be built from wooden planks.</span><br>")
datum/antagonist/bloodsucker/proc/LevelUpPowers()
@@ -287,19 +289,19 @@ datum/antagonist/bloodsucker/proc/SpendRank()
for(var/pickedpower in typesof(/datum/action/bloodsucker))
var/datum/action/bloodsucker/power = pickedpower
// If I don't own it, and I'm allowed to buy it.
if (!(locate(power) in powers) && initial(power.bloodsucker_can_buy))
if(!(locate(power) in powers) && initial(power.bloodsucker_can_buy))
options[initial(power.name)] = power // TESTING: After working with TGUI, it seems you can use initial() to view the variables inside a path?
options["\[ Not Now \]"] = null
// Abort?
if (options.len > 1)
if(options.len > 1)
var/choice = input(owner.current, "You have the opportunity to grow more ancient. 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(vamplevel_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))
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>")
return
if (!choice || !options[choice] || (locate(options[choice]) in powers)) // ADDED: Check to see if you already have this power, due to window stacking.
if(!choice || !options[choice] || (locate(options[choice]) in powers)) // ADDED: Check to see if you already have this power, due to window stacking.
to_chat(owner.current, "<span class='notice'>You prevent your blood from thickening just yet, but you may try again later.</span>")
return
// Buy New Powers
@@ -313,7 +315,7 @@ datum/antagonist/bloodsucker/proc/SpendRank()
LevelUpPowers()
////////
// Advance Stats
if (ishuman(owner.current))
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
S.burnmod += 0.025 // Slightly more burn damage
@@ -331,7 +333,7 @@ datum/antagonist/bloodsucker/proc/SpendRank()
vamplevel_unspent --
// Assign True Reputation
if (vamplevel == 4)
if(vamplevel == 4)
SelectReputation(am_fledgling=FALSE, forced=TRUE)
to_chat(owner.current, "<span class='notice'>You are now a rank [vamplevel] Bloodsucker. Your strength, resistence, health, feed rate, regen rate, and maximum blood have all increased!</span>")
to_chat(owner.current, "<span class='notice'>Your existing powers have all ranked up as well!</span>")
@@ -485,7 +487,7 @@ datum/antagonist/bloodsucker/proc/SpendRank()
// - Warms up the body
// - Creates a heartbeat
// - Fake blood amount (550)
// Feign DEATH:
// Feign DEATH: Not yet done
// - When lying down or sitting, you appear "dead and lifeless"
// * Bloodsuckers REGENERATE

View File

@@ -109,38 +109,17 @@
var/disloyalty_offered = FALSE // Has the popup been issued? Don't spam them.
var/convert_cost = 10
//obj/structure/kitchenspike/vassalrack/crowbar_act()
// // Do Nothing (Cancel crowbar deconstruct)
// return FALSE
/obj/structure/bloodsucker/vassalrack/deconstruct(disassembled = TRUE)
new /obj/item/stack/sheet/metal(src.loc, 4)
new /obj/item/stack/rods(loc, 4)
qdel(src)
/*
/obj/structure/closet/CtrlShiftClick(mob/living/user)
if(!user.has_trait(TRAIT_SKITTISH))
return ..()
if(!user.canUseTopic(src) || !isturf(user.loc))
return
dive_into(user)
*/
// adding a STRAP on top of an icon: look at update_icon in closets.dm, and the use of overlays.dm cut_overlay() and add_overlay()
/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 && user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
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
var/waspulling = (O == owner.pulling)
var/wasgrabstate = owner.grab_state
@@ -463,7 +442,7 @@
///obj/structure/bloodsucker/candelabrum/is_hot() // candle.dm
//return FALSE
/datum/component/nanites/Destroy()
/obj/structure/bloodsucker/candelabrum/Destroy()
STOP_PROCESSING(SSobj, src)
/obj/structure/bloodsucker/candelabrum/update_icon()

View File

@@ -33,73 +33,60 @@
/datum/antagonist/bloodsucker/proc/RunLair()
set waitfor = FALSE // Don't make on_gain() wait for this function to finish. This lets this code run on the side.
while (!AmFinalDeath() && coffin && lair)
// WAit 1 min and Repeat
sleep(60)
while(!AmFinalDeath() && coffin && lair)
// WAit 2 min and Repeat
sleep(120)
// Coffin Moved SOMEHOW?
if (lair != get_area(coffin))
if (coffin)
if(lair != get_area(coffin))
if(coffin)
coffin.UnclaimCoffin()
//lair = get_area(coffin)
break // DONE
var/list/turf/area_turfs = get_area_turfs(lair)
// Create Dirt etc.
var/turf/T_Dirty = pick(area_turfs)
if (T_Dirty && !T_Dirty.density)
if(T_Dirty && !T_Dirty.density)
// Default: Dirt
// CHECK: Cobweb already there?
//if (!locate(var/obj/effect/decal/cleanable/cobweb) in T_Dirty) // REMOVED! Cleanables don't stack.
// STEP ONE: COBWEBS
// CHECK: Wall to North?
var/turf/check_N = get_step(T_Dirty, NORTH)
if (istype(check_N, /turf/closed/wall))
if(istype(check_N, /turf/closed/wall))
// CHECK: Wall to West?
var/turf/check_W = get_step(T_Dirty, WEST)
if (istype(check_W, /turf/closed/wall))
if(istype(check_W, /turf/closed/wall))
new /obj/effect/decal/cleanable/cobweb (T_Dirty)
// CHECK: Wall to East?
var/turf/check_E = get_step(T_Dirty, EAST)
if (istype(check_E, /turf/closed/wall))
if(istype(check_E, /turf/closed/wall))
new /obj/effect/decal/cleanable/cobweb/cobweb2 (T_Dirty)
// STEP TWO: DIRT
new /obj/effect/decal/cleanable/dirt (T_Dirty)
// Find Animals in Area
if (rand(0,2) == 0)
if(rand(0,2) == 0)
var/mobCount = 0
var/mobMax = CLAMP(area_turfs.len / 25, 1, 4)
for (var/turf/T in area_turfs)
if (!T) continue
if(!T) continue
var/mob/living/simple_animal/SA = locate() in T
if (SA)
if(SA)
mobCount ++
if (mobCount >= mobMax) // Already at max
break
// Spawn One
if (mobCount < mobMax)
if(mobCount < mobMax)
// Seek Out Location
while (area_turfs.len > 0)
while(area_turfs.len > 0)
sleep(240) //We dont want this to happen often
var/turf/T = pick(area_turfs) // We use while&pick instead of a for/loop so it's random, rather than from the top of the list.
if (T && !T.density)
if(T && !T.density)
var/mob/living/simple_animal/SA = /mob/living/simple_animal/mouse // pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse,
new SA (T)
break
area_turfs -= T
// NOTE: area_turfs is now cleared out!
if (coffin)
if(coffin)
coffin.UnclaimCoffin()
// Done (somehow)
lair = null

View File

@@ -22,22 +22,24 @@
return
. = TRUE
// Break Out of Restraints! (And then cancel)
if (CheckBreakRestraints())
if(CheckBreakRestraints())
//PowerActivatedSuccessfully() // PAY COST! BEGIN COOLDOWN!DEACTIVATE!
. = FALSE //return FALSE
// Throw Off Attacker! (And then cancel)
if (CheckEscapePuller())
if(CheckEscapePuller())
//PowerActivatedSuccessfully() // PAY COST! BEGIN COOLDOWN!DEACTIVATE!
. = FALSE //return FALSE
// Did we successfuly use power to BREAK CUFFS and/or ESCAPE PULLER?
/*if(CheckBreakLocker())
.= FALSE */
// Did we successfuly use power to BREAK CUFFS and/or ESCAPE PULLER and/or escape from a locker?
// Then PAY COST!
if (. == FALSE)
if(. == FALSE)
PowerActivatedSuccessfully() // PAY COST! BEGIN COOLDOWN!DEACTIVATE!
// NOTE: We use . = FALSE so that we can break cuffs AND throw off our attacker in one use!
//return TRUE
/datum/action/bloodsucker/targeted/brawn/CheckValidTarget(atom/A)
return isliving(A) || istype(A, /obj/machinery/door) || istype(A, /obj/structure/closet)
return isliving(A) || istype(A, /obj/machinery/door))
/datum/action/bloodsucker/targeted/brawn/CheckCanTarget(atom/A, display_error)
// DEFAULT CHECKS (Distance)
@@ -53,10 +55,7 @@
if(isliving(A))
return TRUE
// Target Type: Door
else if(upgrade_canDoor && istype(A, /obj/machinery/door))
return TRUE
// Target Type: Closet
else if(upgrade_canLocker && istype(A, /obj/structure/closet))
else if(istype(A, /obj/machinery/door))
return TRUE
return ..() // yes, FALSE! You failed if you got here! BAD TARGET
@@ -88,30 +87,21 @@
owner.newtonian_move(send_dir) // Bounce back in 0 G
target.throw_at(T, powerlevel, TRUE, owner) //new /datum/forced_movement(target, get_ranged_target_turf(target, send_dir, (hitStrength / 4)), 1, FALSE)
// Target Type: Door
else if (upgrade_canDoor && istype(target, /obj/machinery/door))
else if(istype(target, /obj/machinery/door))
var/obj/machinery/door/D = target
playsound(get_turf(usr), 'sound/machines/airlock_alien_prying.ogg', 40, 1, -1)
if (do_mob(usr,target,25))
var/obj/machinery/door/D = target
to_chat(user, "<span class='notice'>You prepare to tear open [D].</span>")
if(do_mob(usr,target,25))
if (D.Adjacent(user))
to_chat(user, "<span class='notice'>You prepare to tear open [D].</span>")
to_chat(user, "<span class='notice'>You tear open the [D].</span>")
user.Stun(10)
user.do_attack_animation(D, ATTACK_EFFECT_SMASH)
playsound(get_turf(D), 'sound/effects/bang.ogg', 30, 1, -1)
D.open(2) // open(2) is like a crowbar or jaws of life.
// Target Type: Closet
else if (upgrade_canLocker && istype(target, /obj/structure/closet))
playsound(get_turf(usr), 'sound/machines/airlock_alien_prying.ogg', 40, 1, -1)
if (do_mob(usr,target,25))
var/obj/structure/closet/C = target
to_chat(user, "<span class='notice'>You prepare to tear open the [C].</span>")
user.Stun(10)
user.do_attack_animation(C, ATTACK_EFFECT_SMASH)
playsound(get_turf(C), 'sound/effects/bang.ogg', 30, 1, -1)
C.bust_open()
/datum/action/bloodsucker/targeted/brawn/proc/CheckBreakRestraints()
if (!iscarbon(owner)) // || !owner.restrained()
if(!iscarbon(owner)) // || !owner.restrained()
return FALSE
// (NOTE: Just like biodegrade.dm, we only remove one thing per use //
// Destroy Cuffs
@@ -125,18 +115,18 @@
user_C.clear_cuffs(O,TRUE)
playsound(get_turf(usr), 'sound/effects/grillehit.ogg', 80, 1, -1)
return TRUE
/* Doesnt work
// Destroy Straightjacket
if (ishuman(owner))
if(ishuman(owner))
var/mob/living/carbon/human/user_H = owner
if(user_H.wear_suit && user_H.wear_suit.breakouttime)
var/obj/item/clothing/suit/S = user_H.get_item_by_slot(ITEM_SLOT_ICLOTHING)
var/obj/item/clothing/suit/straight_jacket/S = user_H.get_item_by_slot(ITEM_SLOT_ICLOTHING)
if(istype(S))
user_C.visible_message("<span class='warning'>[user_C] attempts to remove [S]!</span>", \
"<span class='warning'>You rip through [S] like it's nothing!</span>")
user_C.clear_cuffs(S,TRUE)
playsound(get_turf(usr), 'sound/effects/grillehit.ogg', 80, 1, -1)
return TRUE
return TRUE */
// Destroy Leg Cuffs
if(user_C.legcuffed)
var/obj/O = user_C.get_item_by_slot(SLOT_LEGCUFFED)
@@ -149,7 +139,7 @@
return FALSE
/datum/action/bloodsucker/targeted/brawn/proc/CheckEscapePuller()
if (!owner.pulledby)// || owner.pulledby.grab_state <= GRAB_PASSIVE)
if(!owner.pulledby)// || owner.pulledby.grab_state <= GRAB_PASSIVE)
return FALSE
var/mob/M = owner.pulledby
var/pull_power = M.grab_state
@@ -169,3 +159,16 @@
"<span class='warning'>You shrug off [M]'s grasp!</span>")
owner.pulledby = null // It's already done, but JUST IN CASE.
return TRUE
/* Doesnt work
/datum/action/bloodsucker/targeted/brawn/proc/CheckBreakLocker()
if(!istype(owner.loc, /obj/structure/closet))
return FALSE
playsound(get_turf(owner), 'sound/machines/airlock_alien_prying.ogg', 40, 1, -1)
if(do_mob(owner ,target, 25))
var/obj/structure/closet/C = owner.loc
to_chat(owner, "<span class='notice'>You prepare to tear open the [C].</span>")
owner.do_attack_animation(C, ATTACK_EFFECT_SMASH)
playsound(get_turf(C), 'sound/effects/bang.ogg', 30, 1, -1)
C.bust_open()
return TRUE
*/

View File

@@ -11,9 +11,6 @@
warn_constant_cost = TRUE
var/light_min = 0.5 // If lum is above this, no good.
var/remember_start_loc // Where this power was activated, so it can be checked from ContinueActive
// Level Up
var/upgrade_canMove = FALSE // Can I move around with this power?
/datum/action/bloodsucker/cloak/CheckCanUse(display_error)
. = ..()
@@ -30,19 +27,11 @@
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/mob/living/user = owner
remember_start_loc = user.loc
// Freeze in Place (so you don't auto-cancel)
//user.mobility_flags &= ~MOBILITY_MOVE
while (bloodsuckerdatum && ContinueActive(user))
//if (!do_mob(user, user, 10, 0, 0, extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))
// return
// Fade from sight
owner.alpha = max(0, owner.alpha - min(75, 20 + 15 * level_current))
bloodsuckerdatum.AddBloodVolume(-0.2)
ADD_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
sleep(5)
/datum/action/bloodsucker/cloak/ContinueActive(mob/living/user, mob/living/target)
@@ -52,12 +41,8 @@
if(user.stat == !CONSCIOUS)
to_chat(owner, "<span class='warning'>Your cloak failed due to you falling unconcious! </span>")
return FALSE
// Must be SAME LOCATION
var/turf/T = owner.loc
if (!upgrade_canMove && T != remember_start_loc)
to_chat(owner, "<span class='warning'>Your cloak is not yet powerfull enough to allow you to move!</span>")
return FALSE
// Must be DARK
var/turf/T = owner.loc
if(istype(T) && T.get_lumcount() > light_min)
to_chat(owner, "<span class='warning'>Your cloak failed due to there being too much light!</span>")
return FALSE
@@ -66,4 +51,5 @@
/datum/action/bloodsucker/cloak/DeactivatePower(mob/living/user = owner, mob/living/target)
..()
REMOVE_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
user.alpha = 255

View File

@@ -94,7 +94,7 @@
puff.set_up(3, 0, get_turf(owner))
puff.start()
// TELEPORT: Move to Coffin & Close it!
do_teleport(owner, bloodsuckerdatum.coffin, no_effects=TRUE) // in teleport.dm?
do_teleport(owner, bloodsuckerdatum.coffin, no_effects = TRUE, forced = TRUE) // in teleport.dm?
// SLEEP
user.resting = TRUE
//user.Unconscious(30,0)

View File

@@ -20,10 +20,14 @@
if(!.)
return
// Being Grabbed
if (owner.pulledby && owner.pulledby.grab_state >= GRAB_AGGRESSIVE)
if (display_error)
if(owner.pulledby && owner.pulledby.grab_state >= GRAB_AGGRESSIVE)
if(display_error)
to_chat(owner, "<span class='warning'>You're being grabbed!</span>")
return FALSE
if(!owner.has_gravity(owner.loc)) //We dont want people to be able to use this to fly around in space
if(display_error)
to_chat(owner, "<span class='warning'>You cant dash while floating!</span>")
return FALSE
return TRUE
/datum/action/bloodsucker/targeted/haste/CheckValidTarget(atom/A)
@@ -67,9 +71,6 @@
if (rand(0, 5) < level_current)
playsound(get_turf(newtarget), "sound/weapons/punch[rand(1,4)].ogg", 15, 1, -1)
newtarget.Knockdown(10 + level_current * 5)
newtarget.adjustStaminaLoss(10 + 5 * level_current)
newtarget.Stun(5 + level_current * 2)
newtarget.adjustStaminaLoss(5 + 3 * level_current)
if(newtarget.IsStun())
newtarget.spin(10,1)
if (rand(0,4))

View File

@@ -17,10 +17,14 @@
if(!..(display_error))// DEFAULT CHECKS
return FALSE
// Being Grabbed
if (owner.pulledby && owner.pulledby.grab_state >= GRAB_AGGRESSIVE)
if (display_error)
if(owner.pulledby && owner.pulledby.grab_state >= GRAB_AGGRESSIVE)
if(display_error)
to_chat(owner, "<span class='warning'>You're being grabbed!</span>")
return FALSE
if(!owner.has_gravity(owner.loc))//TODO figure out how to check if theyre able to move while in nograv
if(display_error)
to_chat(owner, "<span class='warning'>You cant lunge while floating!</span>")
return FALSE
return TRUE
/datum/action/bloodsucker/targeted/lunge/CheckValidTarget(atom/A)
@@ -28,7 +32,7 @@
/datum/action/bloodsucker/targeted/lunge/CheckCanTarget(atom/A, display_error)
// Check: Self
if (target == owner)
if(target == owner)
return FALSE
// Check: Range
//if (!(target in view(target_range, get_turf(owner))))
@@ -36,11 +40,11 @@
// to_chat(owner, "<span class='warning'>Your victim is too far away.</span>")
// return FALSE
// DEFAULT CHECKS (Distance)
if (!..())
if(!..())
return FALSE
// Check: Turf
var/mob/living/L = A
if (!isturf(L.loc))
if(!isturf(L.loc))
return FALSE
return TRUE
@@ -56,6 +60,7 @@
// Step One: Heatseek toward Target's Turf
walk_towards(owner, T, 0.1, 10) // NOTE: this runs in the background! to cancel it, you need to use walk(owner.current,0), or give them a new path.
addtimer(CALLBACK(owner, .proc/_walk, 0), 2 SECONDS)
if(get_turf(owner) != T && !(isliving(target) && target.Adjacent(owner)) && owner.incapacitated() && owner.resting)
var/send_dir = get_dir(owner, T)
new /datum/forced_movement(owner, get_ranged_target_turf(owner, send_dir, 1), 1, FALSE)
@@ -64,7 +69,7 @@
sleep(1)
if(target.Adjacent(owner))
// LEVEL 2: If behind target, mute or unconscious!
if (do_knockdown) // && level_current >= 1)
if(do_knockdown) // && level_current >= 1)
target.Knockdown(15 + 10 * level_current,1)
target.adjustStaminaLoss(40 + 10 * level_current)
// Cancel Walk (we were close enough to contact them)

View File

@@ -94,8 +94,8 @@
if(do_mob(user, target, 40, 0, TRUE, extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))
PowerActivatedSuccessfully() // PAY COST! BEGIN COOLDOWN!
target.silent += 100 + level_current * 15
var/power_time = 90 + level_current * 15
target.silent += power_time + 50
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 100 + level_current * 15)
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
target.Stun(power_time)

View File

@@ -101,7 +101,7 @@
// Move & Freeze
if (isturf(target_turf))
do_teleport(owner, target_turf, no_effects=TRUE) // in teleport.dm?
do_teleport(owner, target_turf, no_effects=TRUE, forced = TRUE) // in teleport.dm?
user.next_move = world.time + mist_delay / 2
user.Stun(mist_delay / 2, ignore_canstun = TRUE)

View File

@@ -33,7 +33,7 @@
C.heal_overall_damage(bruteheal)
C.blood_volume -= 0.6
if (C.getStaminaLoss() < 60)
C.adjustStaminaLoss(25, forced = TRUE)
C.adjustStaminaLoss(10, forced = TRUE)
// Stop Bleeding
if (istype(H) && H.bleed_rate > 0 && rand(20) == 0)
H.bleed_rate --
@@ -41,7 +41,7 @@
C.Jitter(5)
sleep(20)
sleep(10)
// DONE!
//DeactivatePower(owner)

View File

@@ -177,6 +177,8 @@
bodies = old_species.bodies
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
if((HAS_TRAIT(H, TRAIT_NOMARROW)))
return
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
if(prob(5))
to_chat(H, "<span class='notice'>You feel very bloated!</span>")

View File

@@ -180,7 +180,7 @@
else
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color())
if(iscarbon(L))
if(iscarbon(L) && !HAS_TRAIT(L, TRAIT_NOMARROW))
var/mob/living/carbon/C = L
C.bleed(damage)
else