Mooaar fixeees

This commit is contained in:
Artur
2019-12-14 01:01:38 +02:00
parent 488c0f1833
commit 9faf3d1dac
32 changed files with 171 additions and 137 deletions
@@ -1,23 +1,22 @@
// 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))
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.
if (!getorganslot(ORGAN_SLOT_HEART))
if (displaymessage != "")
if(!getorganslot(ORGAN_SLOT_HEART))
if(displaymessage != "")
to_chat(src, "<span class='warning'>Without a heart, you are incapable of [displaymessage].</span>")
return FALSE
if (!get_bodypart(BODY_ZONE_HEAD))
if (displaymessage != "")
if(!get_bodypart(BODY_ZONE_HEAD))
if(displaymessage != "")
to_chat(src, "<span class='warning'>Without a head, you are incapable of [displaymessage].</span>")
return FALSE
if (!getorgan(/obj/item/organ/brain)) // NOTE: This is mostly just here so we can do one scan for all needed parts when creating a vamp. You probably won't be trying to use powers w/out a brain.
if (displaymessage != "")
if(!getorgan(/obj/item/organ/brain)) // NOTE: This is mostly just here so we can do one scan for all needed parts when creating a vamp. You probably won't be trying to use powers w/out a brain.
if(displaymessage != "")
to_chat(src, "<span class='warning'>Without a brain, you are incapable of [displaymessage].</span>")
return FALSE
return TRUE
@@ -37,41 +36,38 @@
/mob/living/carbon/getBruteLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if (BP.status < 2)
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)
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)
if(!mind || !viewer.mind)
return ""
// Target must be a Vamp
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (!bloodsuckerdatum)
if(!bloodsuckerdatum)
return ""
// Viewer is Target's Vassal?
if (viewer.mind.has_antag_datum(ANTAG_DATUM_VASSAL) in bloodsuckerdatum.vassals)
if(viewer.mind.has_antag_datum(ANTAG_DATUM_VASSAL) in bloodsuckerdatum.vassals)
var/returnString = "\[<span class='warning'><EM>This is your Master!</EM></span>\]"
var/returnIcon = "[icon2html('icons/mob/hud.dmi', world, "bloodsucker_big")]"
var/returnIcon = "[icon2html('icons/misc/language.dmi', world, "bloodsucker")]"
returnString += "\n"
return returnIcon + returnString
// Viewer not a Vamp AND not the target's vassal?
if (!viewer.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) && !(viewer in bloodsuckerdatum.vassals))
if(!viewer.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) && !(viewer in bloodsuckerdatum.vassals))
return ""
// Default String
var/returnString = "\[<span class='warning'><EM>[bloodsuckerdatum.ReturnFullName(1)]</EM></span>\]"
var/returnIcon = "[icon2html('icons/mob/hud.dmi', world, "bloodsucker_big")]"
var/returnIcon = "[icon2html('icons/misc/language.dmi', world, "bloodsucker")]"
// In Disguise (Veil)?
//if (name_override != null)
@@ -82,35 +78,35 @@
/mob/living/carbon/human/proc/ReturnVassalExamine(var/mob/viewer)
if (!mind || !viewer.mind)
if(!mind || !viewer.mind)
return ""
// Am I not even a Vassal? Then I am not marked.
var/datum/antagonist/vassal/vassaldatum = mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if (!vassaldatum)
if(!vassaldatum)
return ""
// Only Vassals and Bloodsuckers can recognize marks.
if (!viewer.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) && !viewer.mind.has_antag_datum(ANTAG_DATUM_VASSAL))
if(!viewer.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) && !viewer.mind.has_antag_datum(ANTAG_DATUM_VASSAL))
return ""
// Default String
var/returnString = "\[<span class='warning'>"
var/returnIcon = ""
// Am I Viewer's Vassal?
if (vassaldatum.master.owner == viewer.mind)
if(vassaldatum.master.owner == viewer.mind)
returnString += "This [dna.species.name] bears YOUR mark!"
returnIcon = "[icon2html('icons/mob/hud.dmi', world, "vassal_big")]"
returnIcon = "[icon2html('icons/misc/mark_icons.dmi', world, "vassal")]"
// Am I someone ELSE'S Vassal?
else if (viewer.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
else if(viewer.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
returnString += "This [dna.species.name] bears the mark of <span class='boldwarning'>[vassaldatum.master.ReturnFullName(vassaldatum.master.owner.current,1)]</span>"
returnIcon = "[icon2html('icons/mob/hud.dmi', world, "vassal_grey_big")]"
returnIcon = "[icon2html('icons/misc/mark_icons.dmi', world, "vassal_grey")]"
// Are you serving the same master as I am?
else if (viewer.mind.has_antag_datum(ANTAG_DATUM_VASSAL) in vassaldatum.master.vassals)
else if(viewer.mind.has_antag_datum(ANTAG_DATUM_VASSAL) in vassaldatum.master.vassals)
returnString += "[p_they(TRUE)] bears the mark of your Master"
returnIcon = "[icon2html('icons/mob/hud.dmi', world, "bloodsucker_big")]"
returnIcon = "[icon2html('icons/misc/mark_icons.dmi', world, "vassal")]"
// You serve a different Master than I do.
else
returnString += "[p_they(TRUE)] bears the mark of another Bloodsucker"
returnIcon = "[icon2html('icons/mob/hud.dmi', world, "vassal_grey_big")]"
returnIcon = "[icon2html('icons/misc/mark_icons.dmi', world, "vassal_grey")]"
returnString += "</span>\]" // \n" Don't need spacers. Using . += "" in examine.dm does this on its own.
return returnIcon + returnString
@@ -124,7 +120,7 @@
return blood_volume < BLOOD_VOLUME_SAFE
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (bloodsuckerdatum.poweron_masquerade)
if(bloodsuckerdatum.poweron_masquerade)
return FALSE
// If a Bloodsucker is malnourished, AND if his temperature matches his surroundings (aka he hasn't fed recently and looks COLD)...
@@ -132,14 +128,14 @@
/mob/living/carbon/human/ShowAsPaleExamine()
// Check for albino, as per human/examine.dm's check.
if (skin_tone == "albino")
if(skin_tone == "albino")
return TRUE
return ..() // Return vamp check
/mob/living/carbon/proc/scan_blood_volume()
// Vamps don't show up normally to scanners unless Masquerade power is on ----> scanner.dm
if (mind)
if(mind)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if (istype(bloodsuckerdatum) && bloodsuckerdatum.poweron_masquerade)
return BLOOD_VOLUME_NORMAL
@@ -47,10 +47,10 @@
var/blood_taken = min(feedAmount, 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))
if(!ishuman(target))
target.blood_volume -= (blood_taken / max(target.mob_size, 0.1)) * 3.5 // max() to prevent divide-by-zero
target.apply_damage_type(blood_taken / 3.5) // Don't do too much damage, or else they die and provide no blood nourishment.
if (target.blood_volume <= 0)
if(target.blood_volume <= 0)
target.blood_volume = 0
target.death(0)
///////////
@@ -59,9 +59,9 @@
// our volume * temp, + their volume * temp, / total volume
///////////
// Reduce Value Quantity
if (target.stat == DEAD) // Penalty for Dead Blood
if(target.stat == DEAD) // Penalty for Dead Blood
blood_taken /= 3
if (!ishuman(target)) // Penalty for Non-Human Blood
if(!ishuman(target)) // Penalty for Non-Human Blood
blood_taken /= 2
//if (!iscarbon(target)) // Penalty for Animals (they're junk food)
// Apply to Volume
@@ -84,7 +84,7 @@
//It is called from your coffin on close (by you only)
if(poweron_masquerade == TRUE || owner.current.AmStaked())
return FALSE
owner.current.adjustStaminaLoss(-3 * (regenRate * 2) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
owner.current.adjustStaminaLoss(-2 + (regenRate * -10) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
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
@@ -102,6 +102,9 @@
costMult = 0.25
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
@@ -128,7 +131,7 @@
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(20 * costMult) // Costs blood to heal
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)
@@ -141,12 +144,8 @@
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.
*/
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
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/CureDisabilities()
@@ -43,7 +43,7 @@
// EXPLANATION
/datum/objective/bloodsucker/lair/update_explanation_text()
explanation_text = "Create a lair by claiming a coffin."// Make sure to keep it safe!"
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift"// Make sure to keep it safe!"
// WIN CONDITIONS?
/datum/objective/bloodsucker/lair/check_completion()
@@ -63,7 +63,6 @@
// LOOKUP: /datum/crewmonitor/proc/update_data(z) for .assignment to see how to get a person's PDA.
var/list/roles = list(
"Captain",
"Head of Security",
"Head of Personnel",
"Research Director",
"Chief Engineer",
@@ -71,7 +70,6 @@
"Quartermaster"
)
var/list/departs = list(
"Head of Security",
"Research Director",
"Chief Engineer",
"Chief Medical Officer",
@@ -93,8 +91,6 @@
// Department?
else
switch(target_role)
if("Head of Security")
department_string = "Security"
if("Research Director")
department_string = "Science"
if("Chief Engineer")
@@ -260,7 +256,7 @@
var/list/all_items = owner.current.GetAllContents() // Includes items inside other items.
var/itemcount = FALSE
for(var/obj/I in all_items) //Check for items
if(istype(I, /obj/item/organ/heart))
if(I == /obj/item/organ/heart)
itemcount ++
if (itemcount >= target_amount) // Got the right amount?
return TRUE
@@ -33,7 +33,7 @@
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
// 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_NOCLONE)
@@ -185,16 +185,17 @@
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
had_toxlover = TRUE
REMOVE_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
// Traits: Species
if (ishuman(owner.current))
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
S.species_traits |= DRINKSBLOOD
// Clear Addictions
owner.current.reagents.addiction_list = list() // Start over from scratch. Lucky you! At least you're not addicted to blood anymore (if you were)
// Stats
if (ishuman(owner.current))
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
// Make Changes
@@ -233,6 +234,9 @@
// Traits
for(var/T in defaultTraits)
REMOVE_TRAIT(owner.current, T, "bloodsucker")
if(had_toxlover == TRUE)
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
// Traits: Species
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
@@ -47,6 +47,7 @@
objectives += vassal_objective
objectives_given += vassal_objective
give_thrall_eyes()
owner.current.grant_language(/datum/language/vampiric)
// Add Antag HUD
update_vassal_icons_added(owner.current, "vassal")
. = ..()
@@ -85,6 +86,7 @@
qdel(O)
objectives_given = list()
remove_thrall_eyes()
owner.current.remove_language(/datum/language/vampiric)
// Clear Antag HUD
update_vassal_icons_removed(owner.current)
@@ -146,5 +148,5 @@
set_antag_hud(vassal, null)
//Displayed at the start of roundend_category section, default to roundend_category header
/datum/antagonist/vassal/roundend_report_header()
return "<span class='header'>Loyal to their bloodsucking masters, the Vassals were:</span><br><br>"
/*/datum/antagonist/vassal/roundend_report_header()
return "<span class='header'>Loyal to their bloodsucking masters, the Vassals were:</span><br><br>"*/
@@ -104,20 +104,33 @@
can_buckle = TRUE
var/useLock = FALSE // So we can't just keep dragging ppl on here.
var/mob/buckled
var/convert_progress = 2 // Resets on each new character to be added to the chair. Some effects should lower it...
var/convert_progress = 3 // Resets on each new character to be added to the chair. Some effects should lower it...
var/disloyalty_confirm = FALSE // Command & Antags need to CONFIRM they are willing to lose their role (and will only do it if the Vassal'ing succeeds)
var/disloyalty_offered = FALSE // Has the popup been issued? Don't spam them.
var/convert_cost = 10
var/convert_cost = 100
/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/bloodsucker/vassalrack/examine(mob/user)
. = ..()
if((user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) || 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.</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>"}
/* 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
You can secure victims to the vassal rack by click dragging the victim onto the rack while it is secured</span>"} */
/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())
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))
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
@@ -126,11 +139,9 @@
// * MOVE! *
O.forceMove(drop_location())
// PULL TARGET: Restore?
if (waspulling)
if(waspulling)
owner.start_pulling(O, wasgrabstate, TRUE)
// NOTE: in bs_lunge.dm, we use [target.grabbedby(owner)], which simulates doing a grab action. We don't want that though...we're cutting directly back to where we were in a grab.
// Do Action!
useLock = TRUE
if(do_mob(user, O, 50))
@@ -138,19 +149,19 @@
useLock = FALSE
/obj/structure/bloodsucker/vassalrack/AltClick(mob/user)
if (!has_buckled_mobs() || !isliving(user) || useLock)
if(!has_buckled_mobs() || !isliving(user) || useLock)
return
// Attempt Release (Owner vs Non Owner)
var/mob/living/carbon/C = pick(buckled_mobs)
if (C)
if (user == owner)
if(C)
if(user == owner)
unbuckle_mob(C)
else
user_unbuckle_mob(C,user)
/obj/structure/bloodsucker/vassalrack/proc/attach_victim(mob/living/M, mob/living/user)
// Standard Buckle Check
if (!buckle_mob(M)) // force=TRUE))
if(!buckle_mob(M)) // force=TRUE))
return
// Attempt Buckle
user.visible_message("<span class='notice'>[user] straps [M] into the rack, immobilizing them.</span>", \
@@ -164,9 +175,7 @@
m180.Turn(180)//90)//180
animate(M, transform = m180, time = 2)
M.pixel_y = -2 //M.get_standard_pixel_y_offset(120)//180)
update_icon()
// Torture Stuff
convert_progress = 2 // Goes down unless you start over.
disloyalty_confirm = FALSE // New guy gets the chance to say NO if he's special.
@@ -174,8 +183,8 @@
/obj/structure/bloodsucker/vassalrack/user_unbuckle_mob(mob/living/M, mob/user)
// Attempt Unbuckle
if (!user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
if (M == user)
if(!user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
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>")
else
@@ -188,7 +197,7 @@
unbuckle_mob(M)
/obj/structure/bloodsucker/vassalrack/unbuckle_mob(mob/living/buckled_mob)//, force=FALSE)
if (!..())
if(!..())
return
var/matrix/m180 = matrix(buckled_mob.transform)
m180.Turn(180)//-90)//180
@@ -197,13 +206,11 @@
src.visible_message(text("<span class='danger'>[buckled_mob][buckled_mob.stat==DEAD?"'s corpse":""] slides off of the rack.</span>"))
density = FALSE
buckled_mob.AdjustKnockdown(30)
update_icon()
useLock = FALSE // Failsafe
/obj/structure/bloodsucker/vassalrack/attackby(obj/item/W, mob/user, params)
if (has_buckled_mobs()) // Attack w/weapon vs guy standing there? Don't do an attack.
if(has_buckled_mobs()) // Attack w/weapon vs guy standing there? Don't do an attack.
attack_hand(user)
return FALSE
return ..()
@@ -213,14 +220,14 @@
//if(.)
// return
// Go away. Torturing.
if (useLock)
if(useLock)
return
var/datum/antagonist/bloodsucker/bloodsuckerdatum = 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(bloodsuckerdatum) && !owner)
if(!bloodsuckerdatum.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))
if(bloodsuckerdatum.lair != get_area(src))
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [bloodsuckerdatum.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"))
@@ -230,16 +237,16 @@
anchored = TRUE
return //No, you cant move this ever again
// No One Home
if (!has_buckled_mobs())
if(!has_buckled_mobs())
return
// CHECK TWO: Am I a non-bloodsucker?
var/mob/living/carbon/C = pick(buckled_mobs)
if (!istype(bloodsuckerdatum))
if(!istype(bloodsuckerdatum))
// Try to release this guy
user_unbuckle_mob(C, user)
return
// Bloodsucker Owner! Let the boy go.
if (C.mind)
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)
unbuckle_mob(C)
@@ -250,7 +257,7 @@
/obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target)
// Check Bloodmob/living/M, force = FALSE, check_loc = TRUE
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
// Prep...
@@ -259,21 +266,21 @@
// Step Two: Break mindshielding/antag (on approve)
// Step Three: Blood Ritual
// Conversion Process
if (convert_progress > 0)
if(convert_progress > 0)
to_chat(user, "<span class='notice'>You prepare to initiate [target] into your service.</span>")
if (!do_torture(user,target))
if(!do_torture(user,target))
to_chat(user, "<span class='danger'><i>The ritual has been interrupted!</i></span>")
else
convert_progress -- // Ouch. Stop. Don't.
// All done!
if (convert_progress <= 0)
if(convert_progress <= 0)
// FAIL: Can't be Vassal
if (!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE)) // If I'm an unconvertable Antag ONLY
to_chat(user, "<span class='danger'>[target] doesn't respond to your persuasion. It doesn't appear they can be converted to follow you. <i>\[ALT+click to release\]</span>")
if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) && HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
to_chat(user, "<span class='danger'>[target] doesn't respond to your persuasion. It doesn't appear they can be converted to follow you, they either have a mindshield or their external loyalties are too difficult for you to break.<i>\[ALT+click to release\]</span>")
convert_progress ++ // Pop it back up some. Avoids wasting Blood on a lost cause.
// SUCCESS: All done!
else
if (RequireDisloyalty(target))
if(RequireDisloyalty(target))
to_chat(user, "<span class='boldwarning'>[target] has external loyalties! [target.p_they(TRUE)] will require more <i>persuasion</i> to break [target.p_them()] to your will!</span>")
else
to_chat(user, "<span class='notice'>[target] looks ready for the <b>Dark Communion</b>.</span>")
@@ -283,8 +290,8 @@
useLock = FALSE
return
// Check: Mindshield & Antag
if (!disloyalty_confirm && RequireDisloyalty(target))
if (!do_disloyalty(user,target))
if(!disloyalty_confirm && RequireDisloyalty(target))
if(!do_disloyalty(user,target))
to_chat(user, "<span class='danger'><i>The ritual has been interrupted!</i></span>")
else if (!disloyalty_confirm)
to_chat(user, "<span class='danger'>[target] refuses to give into your persuasion. Perhaps a little more?</span>")
@@ -293,7 +300,7 @@
useLock = FALSE
return
// Check: Blood
if (user.blood_volume < convert_cost)
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].</span>")
useLock = FALSE
return
@@ -307,8 +314,8 @@
useLock = FALSE
return
// Convert to Vassal!
if (bloodsuckerdatum && bloodsuckerdatum.attempt_turn_vassal(target))
remove_loyalties(target) // In case of Mindshield, or appropriate Antag (Traitor, Internal, etc)
if(bloodsuckerdatum && bloodsuckerdatum.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
@@ -328,28 +335,28 @@
// Get Bodypart
var/target_string = ""
var/obj/item/bodypart/BP = null
if (iscarbon(target))
if(iscarbon(target))
var/mob/living/carbon/C = target
BP = pick(C.bodyparts)
if (BP)
if(BP)
target_string += BP.name
// Get Weapon
var/obj/item/I = user.get_active_held_item()
if (!istype(I))
if(!istype(I))
I = user.get_inactive_held_item()
// Create Strings
var/method_string = I?.attack_verb?.len ? pick(I.attack_verb) : pick("harmed","tortured","wrenched","twisted","scoured","beaten","lashed","scathed")
var/weapon_string = I ? I.name : pick("bare hands","hands","fingers","fists")
// Weapon Bonus + SFX
if (I)
if(I)
torture_time -= I.force / 4
torture_dmg_brute += I.force / 4
//torture_dmg_burn += I.
if (I.sharpness == IS_SHARP)
if(I.sharpness == IS_SHARP)
torture_time -= 1
else if (I.sharpness == IS_SHARP_ACCURATE)
else if(I.sharpness == IS_SHARP_ACCURATE)
torture_time -= 2
if (istype(I, /obj/item/weldingtool))
if(istype(I, /obj/item/weldingtool))
var/obj/item/weldingtool/welder = I
welder.welding = TRUE
torture_time -= 5
@@ -357,15 +364,15 @@
I.play_tool_sound(target)
torture_time = max(50, torture_time * 10) // Minimum 5 seconds.
// Now run process.
if (!do_mob(user, target, torture_time * mult))
if(!do_mob(user, target, torture_time * mult))
return FALSE
// SUCCESS
if (I)
if(I)
playsound(loc, I.hitsound, 30, 1, -1)
I.play_tool_sound(target)
target.visible_message("<span class='danger'>[user] has [method_string] [target]'s [target_string] with [user.p_their()] [weapon_string]!</span>", \
"<span class='userdanger'>[user] has [method_string] your [target_string] with [user.p_their()] [weapon_string]!</span>")
if (!target.is_muzzled())
if(!target.is_muzzled())
target.emote("scream")
target.Jitter(5)
target.apply_damages(brute = torture_dmg_brute, burn = torture_dmg_burn, def_zone = (BP ? BP.body_zone : null)) // take_overall_damage(6,0)
@@ -375,49 +382,49 @@
// OFFER YES/NO NOW!
spawn(10)
if (useLock && target && target.client) // Are we still torturing? Did we cancel? Are they still here?
if(useLock && target && target.client) // Are we still torturing? Did we cancel? Are they still here?
to_chat(user, "<span class='notice'>[target] has been given the opportunity for servitude. You await their decision...</span>")
var/alert_text = "You are being tortured! Do you want to give in and pledge your undying loyalty to [user]?"
if (HAS_TRAIT(target, TRAIT_MINDSHIELD))
/* if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
alert_text += "\n\nYou will no longer be loyal to the station!"
if (SSticker.mode.AmValidAntag(target.mind))
if(SSticker.mode.AmValidAntag(target.mind)) */
alert_text += "\n\nYou will not lose your current objectives, but they come second to the will of your new master!"
switch(alert(target, alert_text,"THE HORRIBLE PAIN! WHEN WILL IT END?!","Yes, Master!", "NEVER!"))
if("Yes, Master!")
disloyalty_accept(target)
else
disloyalty_refuse(target)
if (!do_torture(user,target, 2))
if(!do_torture(user,target, 2))
return FALSE
// NOTE: We only remove loyalties when we're CONVERTED!
return TRUE
/obj/structure/bloodsucker/vassalrack/proc/RequireDisloyalty(mob/living/target)
return SSticker.mode.AmValidAntag(target.mind) || HAS_TRAIT(target, TRAIT_MINDSHIELD)
return SSticker.mode.AmValidAntag(target.mind) //|| HAS_TRAIT(target, TRAIT_MINDSHIELD)
/obj/structure/bloodsucker/vassalrack/proc/disloyalty_accept(mob/living/target)
// FAILSAFE: Still on the rack?
if (!(locate(target) in buckled_mobs))
if(!(locate(target) in buckled_mobs))
return
// NOTE: You can say YES after torture. It'll apply to next time.
disloyalty_confirm = TRUE
if (HAS_TRAIT(target, TRAIT_MINDSHIELD))
/*if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
to_chat(target, "<span class='boldnotice'>You give in to the will of your torturer. If they are successful, you will no longer be loyal to the station!</span>")
*/
/obj/structure/bloodsucker/vassalrack/proc/disloyalty_refuse(mob/living/target)
// FAILSAFE: Still on the rack?
if (!(locate(target) in buckled_mobs))
if(!(locate(target) in buckled_mobs))
return
// Failsafe: You already said YES.
if (disloyalty_confirm)
if(disloyalty_confirm)
return
to_chat(target, "<span class='notice'>You refuse to give in! You <i>will not</i> break!</span>")
/obj/structure/bloodsucker/vassalrack/proc/remove_loyalties(mob/living/target)
// Find Mind Implant & Destroy
if (HAS_TRAIT(target, TRAIT_MINDSHIELD))
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
for(var/obj/item/implant/I in target.implants)
if(I.type == /obj/item/implant/mindshield)
I.removed(target,silent=TRUE)
@@ -444,6 +451,15 @@
/obj/structure/bloodsucker/candelabrum/update_icon()
icon_state = "candelabrum[lit ? "_lit" : ""]"
/obj/structure/bloodsucker/candelabrum/examine(mob/user)
. = ..()
if((user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) || 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)
. += {"<span class='cult'>This is a magical candle which drains at the sanity of the fools who havent yet accepted your master, as long as it is active.\n
You can turn it on and off by clicking on it while you are next to it</span>"} */
/obj/structure/bloodsucker/candelabrum/attack_hand(mob/user)
var/datum/antagonist/bloodsucker/V = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) //I wish there was a better way to do this
var/datum/antagonist/vassal/T = user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
@@ -477,4 +493,5 @@
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "vampcandle", /datum/mood_event/vampcandle)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OTHER THINGS TO USE: HUMAN BLOOD. /obj/effect/decal/cleanable/blood
/obj/item/restraints/legcuffs/beartrap/bloodsucker
@@ -28,9 +28,6 @@
return
*/
/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)
@@ -64,7 +61,7 @@
// 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)
@@ -74,17 +71,16 @@
mobCount ++
if (mobCount >= mobMax) // Already at max
break
// Spawn One
Spawn One
if(mobCount < mobMax)
// Seek Out Location
Seek Out Location
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)
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
area_turfs -= T*/
// NOTE: area_turfs is now cleared out!
if(coffin)
coffin.UnclaimCoffin()
@@ -11,7 +11,7 @@
button_icon_state = "power_mez"
bloodcost = 30
cooldown = 200
target_range = 2
target_range = 1
power_activates_immediately = FALSE
message_Trigger = "Whom will you subvert to your will?"
must_be_capacitated = TRUE
@@ -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!
var/power_time = 90 + level_current * 15
target.silent = power_time + 50
var/power_time = 90 + level_current * 12
target.silent = power_time + 20
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)
+2 -4
View File
@@ -2,7 +2,7 @@
/datum/language/vampiric
name = "Blah-Sucker"
desc = "The native language of the Bloodsucker elders, learned intuitively by Fledglings as they pass from death into immortality."
desc = "The native language of the Bloodsucker elders, learned intuitively by Fledglings and as they pass from death into immortality. Thralls are also given the ability to speak this as apart of their conversion ritual."
speech_verb = "growls"
ask_verb = "growls"
exclaim_verb = "snarls"
@@ -10,6 +10,7 @@
key = "b"
space_chance = 40
default_priority = 90
icon_state = "bloodsucker"
flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD // Hide the icon next to your text if someone doesn't know this language.
syllables = list(
@@ -22,6 +23,3 @@
"froz","etz","tzil",
"t'","k'","t'","k'","th'","tz'"
)
icon_state = "bloodsucker"
icon = 'icons/mob/hud.dmi'
@@ -27,6 +27,7 @@
unsuitable_atmos_damage = 0
minbodytemp = 0
maxbodytemp = 100000
blood_volume = 0
/mob/living/simple_animal/astral/death()
icon_state = "shade_dead"
@@ -14,6 +14,7 @@
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
maxbodytemp = INFINITY
minbodytemp = 0
blood_volume = 0
has_unlimited_silicon_privilege = 1
sentience_type = SENTIENCE_ARTIFICIAL
status_flags = NONE //no default canpush
@@ -33,6 +33,7 @@
initial_language_holder = /datum/language_holder/construct
deathmessage = "collapses in a shattered heap."
hud_type = /datum/hud/constructs
blood_volume = 0
var/list/construct_spells = list()
var/playstyle_string = "<span class='big bold'>You are a generic construct!</span><b> Your job is to not exist, and you should probably adminhelp this.</b>"
var/master = null
@@ -459,4 +460,3 @@
hud_used.healths.icon_state = "[icon_state]_health5"
else
hud_used.healths.icon_state = "[icon_state]_health6"
@@ -50,6 +50,7 @@
dextrous_hud_type = /datum/hud/dextrous/drone
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
see_in_dark = 7
blood_volume = 0
can_be_held = TRUE
held_items = list(null, null)
var/staticChoice = "static"
@@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
icon_living = "magicOrange"
icon_dead = "magicOrange"
speed = 0
blood_volume = 0
a_intent = INTENT_HARM
stop_automated_movement = 1
movement_type = FLYING // Immunity to chasms and landmines, etc.
@@ -19,6 +19,7 @@
spacewalk = TRUE
stat_attack = UNCONSCIOUS
robust_searching = 1
blood_volume = 0
harm_intent_damage = 10
obj_damage = 50
@@ -42,4 +43,4 @@
var/mob/living/carbon/C = target
C.Knockdown(60)
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
"<span class='userdanger'>\The [src] knocks you down!</span>")
"<span class='userdanger'>\The [src] knocks you down!</span>")
@@ -28,6 +28,7 @@
gold_core_spawnable = HOSTILE_SPAWN
del_on_death = 1
loot = list(/obj/effect/decal/cleanable/robot_debris)
blood_volume = 0
do_footstep = TRUE
@@ -30,6 +30,7 @@
robust_searching = TRUE
stat_attack = UNCONSCIOUS
anchored = TRUE
blood_volume = 0
var/combatant_state = SEEDLING_STATE_NEUTRAL
var/obj/seedling_weakpoint/weak_point
var/mob/living/beam_debuff_target
@@ -50,6 +50,7 @@ Difficulty: Normal
armour_penetration = 75
melee_damage_lower = 15
melee_damage_upper = 20
blood_volume = 0
speed = 1
move_to_delay = 11
ranged = 1
@@ -22,6 +22,7 @@
environment_smash = ENVIRONMENT_SMASH_NONE
sentience_type = SENTIENCE_BOSS
layer = LARGE_MOB_LAYER
blood_volume = 0
var/doing_move_loop = FALSE
var/mob/living/set_target
var/timerid
@@ -31,6 +31,7 @@
movement_type = FLYING
pressure_resistance = 300
gold_core_spawnable = NO_SPAWN //too spooky for science
blood_volume = 0
var/ghost_hair_style
var/ghost_hair_color
var/mutable_appearance/ghost_hair
@@ -12,6 +12,7 @@
emote_see = list("rattles")
a_intent = INTENT_HARM
maxHealth = 40
blood_volume = 0
health = 40
speed = 1
harm_intent_damage = 5
@@ -18,6 +18,7 @@
maxHealth = 50000
health = 50000
healable = 0
blood_volume = 0
harm_intent_damage = 10
obj_damage = 100
@@ -13,6 +13,7 @@
response_disarm = "shoves"
response_harm = "hits"
speed = 0
blood_volume = 0
stat_attack = UNCONSCIOUS
robust_searching = 1
environment_smash = ENVIRONMENT_SMASH_NONE
@@ -31,6 +31,7 @@
loot = list(/obj/item/ectoplasm)
del_on_death = TRUE
initial_language_holder = /datum/language_holder/construct
blood_volume = 0
/mob/living/simple_animal/shade/death()
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
@@ -26,6 +26,7 @@
health = 150
healable = 0
gender = NEUTER
blood_volume = 0 //Until someome reworks for them to have slime jelly
see_in_dark = 8
@@ -30,7 +30,7 @@
if(iscarbon(L))
var/mob/living/carbon/C = L
var/blood_id = C.get_blood_id()
if((blood_id == "blood" || blood_id == "jellyblood") && (method == INJECT || (method == INGEST && C.dna && C.dna.species && (DRINKSBLOOD in C.dna.species.species_traits))))
if((HAS_TRAIT(C, TRAIT_NOMARROW) || blood_id == "blood" || blood_id == "jellyblood") && (method == INJECT || (method == INGEST && C.dna && C.dna.species && (DRINKSBLOOD in C.dna.species.species_traits))))
C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM * C.blood_ratio)
// we don't care about bloodtype here, we're just refilling the mob
@@ -112,14 +112,14 @@
if (user != M)
to_chat(user, "<span class='notice'>You force [M] to drink from the [src]</span>")
user.visible_message("<span class='userdanger'>[user] forces [M] to drink from the [src].</span>")
if (!do_mob(user, M, 50))
if(!do_mob(user, M, 50))
return
else
if (!do_mob(user, M, 10))
if(!do_mob(user, M, 10))
return
to_chat(user, "<span class='notice'>You take a sip from the [src].</span>")
user.visible_message("<span class='notice'>[user] puts the [src] up to their mouth.</span>")
if (reagents.total_volume <= 0) // Safety: In case you spam clicked the blood bag on yourself, and it is now empty (below will divide by zero)
if(reagents.total_volume <= 0) // Safety: In case you spam clicked the blood bag on yourself, and it is now empty (below will divide by zero)
return
var/gulp_size = 5
var/fraction = min(gulp_size / reagents.total_volume, 1)