Citadel's folder's end (#5828)

* ERP, miscreants, clothing

* github pls

* guns, dogborg, areas, vendor

* finishes moving around the last of the stuffs

* cleaned up shit. italics on subtle messages

vore code to modular_citadel too

* updates codeowners and recompiles tgui

because it's a healthy thing to do

* reee, I had that spawner set byond

* cleans up a bad pipe

does the thing I've been meaning to do for a while now as well.

* bumps up xenobio console requirements

inb4 reee

* snowflake commenting
This commit is contained in:
Poojawa
2018-03-06 17:40:48 -06:00
committed by GitHub
parent a1416622d2
commit 86b11050b6
140 changed files with 2963 additions and 9703 deletions
-57
View File
@@ -1,57 +0,0 @@
////////////Syndicate Cortical Borer
obj/item/antag_spawner/syndi_borer
name = "syndicate brain-slug container"
desc = "Releases a modified cortical borer to assist the user."
icon = 'icons/obj/device.dmi' //Temporary? Doesn't really look like a container for xenofauna... but IDK what else could work.
icon_state = "locator"
var/polling = FALSE
obj/item/antag_spawner/syndi_borer/spawn_antag(client/C, turf/T, mob/owner)
var/mob/living/simple_animal/borer/syndi_borer/B = new /mob/living/simple_animal/borer/syndi_borer(T)
B.key = C.key
if (owner)
B.owner = owner
B.faction = B.faction | owner.faction.Copy()
B.mind.assigned_role = B.name
B.mind.special_role = B.name
var/datum/objective/syndi_borer/new_objective
new_objective = new /datum/objective/syndi_borer
new_objective.owner = B.mind
new_objective.target = owner.mind
new_objective.explanation_text = "You are a modified cortical borer. You obey [owner.real_name] and must assist them in completing their objectives."
B.mind.objectives += new_objective
to_chat(B, "<B>You are awake at last! Seek out whoever released you and aid them as best you can!</B>")
if(new_objective)
to_chat(B, "<B>Objective #[1]</B>: [new_objective.explanation_text]")
/obj/item/antag_spawner/syndi_borer/proc/check_usability(mob/user)
if(used)
to_chat(user, "<span class='warning'>[src] appears to be empty!</span>")
return 0
if(polling == TRUE)
to_chat(user, "<span class='warning'>[src] is busy activating!</span>")
return 0
return 1
/obj/item/antag_spawner/syndi_borer/attack_self(mob/user)
if(!(check_usability(user)))
return
polling = TRUE
var/list/borer_candidates = pollCandidatesForMob("Do you want to play as a syndicate cortical borer?", ROLE_BORER, null, ROLE_BORER, 150, src)
if(borer_candidates.len)
polling = FALSE
if(!(check_usability(user)))
return
used = 1
var/mob/dead/observer/theghost = pick(borer_candidates)
spawn_antag(theghost.client, get_turf(src), user)
var/datum/effect_system/spark_spread/S = new /datum/effect_system/spark_spread
S.set_up(4, 1, src)
S.start()
qdel(src)
else
polling = FALSE
to_chat(user, "<span class='warning'>Unable to connect to release specimen. Please wait and try again later or use the container on your uplink to get your points refunded.</span>")
-106
View File
@@ -1,106 +0,0 @@
#define MIN_LATE_TARGET_TIME 600 //lower bound of re-rolled timer, 1 min
#define MAX_LATE_TARGET_TIME 6000 //upper bound of re-rolled timer, 10 min
#define LATE_TARGET_HIT_CHANCE 70 //How often would the find_target succeed, otherwise it re-rolls later and tries again.
//Hit chance is here to avoid people checking github and then hovering around new arrivals within the max minute range every round.
/datum/objective/assassinate/late
martyr_compatible = FALSE
/datum/objective/assassinate/late/find_target()
var/list/possible_targets = list()
for(var/mob/M in GLOB.latejoiners)
var/datum/mind/possible_target = M.mind
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && is_unique_objective(possible_target))
possible_targets += possible_target
if(possible_targets.len > 0 && prob(LATE_TARGET_HIT_CHANCE))
target = pick(possible_targets)
martyr_compatible = TRUE //Might never matter, but I guess if an admin gives another random objective, this should now be compatible
update_explanation_text()
message_admins("[target] has been selected as the assassination target of [owner].")
log_game("[target] has been selected as the assassination target of [owner].")
to_chat(owner, "<span class='italics'>You hear a crackling noise in your ears, as a one-way syndicate message plays:</span>")
to_chat(owner, "<span class='userdanger'><font size=5>You target has been located. To succeed, find and eliminate [target], the [!target_role_type ? target.assigned_role : target.special_role].</font></span>")
return target
else
update_explanation_text()
addtimer(CALLBACK(src, .proc/find_target),rand(MIN_LATE_TARGET_TIME, MAX_LATE_TARGET_TIME))
return null
/datum/objective/assassinate/late/find_target_by_role(role, role_type=0, invert=0)
var/list/possible_targets = list()
for(var/mob/M in GLOB.latejoiners)
var/datum/mind/possible_target = M.mind
if((possible_target != owner) && ishuman(possible_target.current))
var/is_role = 0
if(role_type)
if(possible_target.special_role == role)
is_role++
else
if(possible_target.assigned_role == role)
is_role++
if(invert)
if(is_role)
continue
possible_targets += possible_target
//break
else if(is_role)
possible_targets += possible_target
//break
if(possible_targets && prob(LATE_TARGET_HIT_CHANCE))
target = pick(possible_targets)
update_explanation_text()
message_admins("[target] has been selected as the assassination target of [owner].")
log_game("[target] has been selected as the assassination target of [owner].")
to_chat(owner, "<span class='italics'>You hear a crackling noise in your ears, as a one-way syndicate message plays:</span>")
to_chat(owner, "<span class='userdanger'><font size=5>You target has been located. To succeed, find and eliminate [target], the [!target_role_type ? target.assigned_role : target.special_role].</font></span>")
else
update_explanation_text()
addtimer(CALLBACK(src, .proc/find_target_by_role, role, role_type, invert),rand(MIN_LATE_TARGET_TIME, MAX_LATE_TARGET_TIME))
/datum/objective/assassinate/late/check_completion()
if(target && target.current) //If target WAS assigned
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
return TRUE
return FALSE
else //If no target was ever given
if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
return FALSE
if(!is_special_character(owner.current))
return FALSE
return TRUE
/datum/objective/assassinate/late/update_explanation_text()
//..()
if(target && target.current)
explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
else
explanation_text = "Stay alive until your target arrives on the station, you will be notified when the target has been identified."
//BORER STUFF
//Because borers didn't use to have objectives
/datum/objective/normal_borer //Default objective, should technically never be used unmodified but CAN work unmodified.
explanation_text = "You must escape with at least one borer with host on the shuttle."
target_amount = 1
martyr_compatible = 0
/datum/objective/normal_borer/check_completion()
var/total_borer_hosts = 0
for(var/mob/living/carbon/C in GLOB.mob_list)
var/mob/living/simple_animal/borer/D = C.has_brain_worms()
var/turf/location = get_turf(C)
if(is_centcom_level(location.z) && D && D.stat != DEAD)
total_borer_hosts++
if(target_amount <= total_borer_hosts)
return TRUE
else
return FALSE
-769
View File
@@ -1,769 +0,0 @@
/datum/action/innate/cult/blood_magic //Blood magic handles the creation of blood spells (formerly talismans)
name = "Prepare Blood Magic"
button_icon_state = "carve"
desc = "Prepare blood magic by carving runes into your flesh. This rite is most effective with an <b>empowering rune</b>"
var/list/spells = list()
var/channeling = FALSE
/datum/action/innate/cult/blood_magic/Grant()
..()
button.screen_loc = "6:-29,4:-2"
button.moved = "6:-29,4:-2"
button.locked = TRUE
/datum/action/innate/cult/blood_magic/Remove()
for(var/X in spells)
qdel(X)
..()
/datum/action/innate/cult/blood_magic/IsAvailable()
if(!iscultist(owner))
return FALSE
return ..()
/datum/action/innate/cult/blood_magic/proc/Positioning()
for(var/datum/action/innate/cult/blood_spell/B in spells)
var/pos = -29+spells.Find(B)*31
B.button.screen_loc = "6:[pos],4:-2"
B.button.moved = B.button.screen_loc
B.button.locked = TRUE
/datum/action/innate/cult/blood_magic/Activate()
var/rune = FALSE
var/limit = RUNELESS_MAX_BLOODCHARGE
for(var/obj/effect/rune/empower/R in range(1, owner))
rune = TRUE
break
if(rune)
limit = MAX_BLOODCHARGE
if(spells.len >= limit)
if(rune)
to_chat(owner, "<span class='cultitalic'>Your body has reached its limit, you cannot store more than [MAX_BLOODCHARGE] spells at once. <b>Pick a spell to nullify.</b></span>")
else
to_chat(owner, "<span class='cultitalic'>Your body has reached its limit, <b><u>you cannot have more than [RUNELESS_MAX_BLOODCHARGE] spells at once without an empowering rune! Pick a spell to nullify.</b></u></span>")
var/nullify_spell = input(owner, "Choose a spell to remove.", "Current Spells") as null|anything in spells
if(nullify_spell)
qdel(nullify_spell)
return
var/entered_spell_name
var/datum/action/innate/cult/blood_spell/BS
var/list/possible_spells = list()
for(var/I in subtypesof(/datum/action/innate/cult/blood_spell))
var/datum/action/innate/cult/blood_spell/J = I
var/cult_name = initial(J.name)
possible_spells[cult_name] = J
possible_spells += "(REMOVE SPELL)"
entered_spell_name = input(owner, "Pick a blood spell to prepare...", "Spell Choices") as null|anything in possible_spells
if(entered_spell_name == "(REMOVE SPELL)")
var/nullify_spell = input(owner, "Choose a spell to remove.", "Current Spells") as null|anything in spells
if(nullify_spell)
qdel(nullify_spell)
return
BS = possible_spells[entered_spell_name]
if(QDELETED(src) || owner.incapacitated() || !BS)
return
to_chat(owner,"<span class='warning'>You begin to carve unnatural symbols into your flesh!</span>")
SEND_SOUND(owner, sound('sound/weapons/slice.ogg',0,1,10))
if(!channeling)
channeling = TRUE
else
to_chat(owner, "<span class='cultitalic'>You are already invoking blood magic!")
return
if(do_after(owner, 100 - rune*65, target = owner))
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
H.bleed(30 - rune*25)
var/datum/action/innate/cult/blood_spell/new_spell = new BS(owner)
new_spell.Grant(owner, src)
spells += new_spell
Positioning()
to_chat(owner, "<span class='warning'>Your wounds glows with power, you have prepared a [new_spell.name] invocation!</span>")
channeling = FALSE
/datum/action/innate/cult/blood_spell //The next generation of talismans
name = "Blood Magic"
button_icon_state = "telerune"
desc = "Fear the Old Blood."
var/charges = 1
var/magic_path = null
var/obj/item/melee/blood_magic/hand_magic
var/datum/action/innate/cult/blood_magic/all_magic
var/base_desc //To allow for updating tooltips
var/invocation
var/health_cost = 0
/datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM)
if(health_cost)
desc += "<br>Deals <u>[health_cost] damage</u> to your arm per use."
base_desc = desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
all_magic = BM
..()
/datum/action/innate/cult/blood_spell/Remove()
if(all_magic)
all_magic.spells -= src
if(hand_magic)
qdel(hand_magic)
hand_magic = null
..()
/datum/action/innate/cult/blood_spell/IsAvailable()
if(!iscultist(owner) || owner.incapacitated() || !charges)
return FALSE
return ..()
/datum/action/innate/cult/blood_spell/Activate()
if(magic_path) //If this spell flows from the hand
if(!hand_magic)
hand_magic = new magic_path(owner, src)
if(!owner.put_in_hands(hand_magic))
qdel(hand_magic)
hand_magic = null
to_chat(owner, "<span class='warning'>You have no empty hand for invoking blood magic!</span>")
return
to_chat(owner, "<span class='notice'>Your old wounds glow again as you invoke the [name].</span>")
return
if(hand_magic)
qdel(hand_magic)
hand_magic = null
to_chat(owner, "<span class='warning'>You snuff out the spell with your hand, saving its power for another time.</span>")
//Cult Blood Spells
/datum/action/innate/cult/blood_spell/stun
name = "Stun"
desc = "A potent spell that will stun and mute victims upon contact."
button_icon_state = "hand"
magic_path = "/obj/item/melee/blood_magic/stun"
health_cost = 10
/datum/action/innate/cult/blood_spell/teleport
name = "Teleport"
desc = "A useful spell that teleport cultists to a chosen destination on contact."
button_icon_state = "tele"
magic_path = "/obj/item/melee/blood_magic/teleport"
health_cost = 7
/datum/action/innate/cult/blood_spell/emp
name = "Electromagnetic Pulse"
desc = "A large spell that immediately disables all electronics in the area."
button_icon_state = "emp"
health_cost = 10
invocation = "Ta'gh fara'qha fel d'amar det!"
/datum/action/innate/cult/blood_spell/emp/Activate()
owner.visible_message("<span class='warning'>[owner]'s hand flashes a bright blue!</span>", \
"<span class='cultitalic'>You speak the cursed words, emitting an EMP blast from your hand.</span>")
empulse(owner, 3, 6)
owner.whisper(invocation, language = /datum/language/common)
charges--
if(charges<=0)
qdel(src)
/datum/action/innate/cult/blood_spell/shackles
name = "Shadow Shackles"
desc = "A stealthy spell that will handcuff and temporarily silence your victim."
button_icon_state = "cuff"
charges = 4
magic_path = "/obj/item/melee/blood_magic/shackles"
/datum/action/innate/cult/blood_spell/construction
name = "Twisted Construction"
desc = "<u>A sinister spell used to convert:</u><br>Plasteel into runed metal<br>25 metal into a construct shell<br>Cyborgs directly into constructs<br>Cyborg shells into construct shells<br>Airlocks into runed airlocks (harm intent)"
button_icon_state = "transmute"
magic_path = "/obj/item/melee/blood_magic/construction"
/datum/action/innate/cult/blood_spell/equipment
name = "Summon Equipment"
desc = "A crucial spell that enables you to summon either a ritual dagger or combat gear including armored robes, the nar'sien bola, and an eldritch longsword."
button_icon_state = "equip"
magic_path = "/obj/item/melee/blood_magic/armor"
/datum/action/innate/cult/blood_spell/equipment/Activate()
var/choice = alert(owner,"Choose your equipment type",,"Combat Equipment","Ritual Dagger","Cancel")
if(choice == "Ritual Dagger")
var/turf/T = get_turf(owner)
owner.visible_message("<span class='warning'>[owner]'s hand glows red for a moment.</span>", \
"<span class='cultitalic'>Red light begins to shimmer and take form within your hand!</span>")
var/obj/O = new /obj/item/melee/cultblade/dagger(T)
if(owner.put_in_hands(O))
to_chat(owner, "<span class='warning'>A ritual dagger appears in your hand!</span>")
else
owner.visible_message("<span class='warning'>A ritual dagger appears at [owner]'s feet!</span>", \
"<span class='cultitalic'>A ritual dagger materializes at your feet.</span>")
SEND_SOUND(owner, sound('sound/effects/magic.ogg',0,1,25))
charges--
desc = base_desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
if(charges<=0)
qdel(src)
else if(choice == "Combat Equipment")
..()
/datum/action/innate/cult/blood_spell/horror
name = "Hallucinations"
desc = "A <u>ranged yet stealthy</u> spell that will break the mind of the victim with nightmarish hallucinations."
button_icon_state = "horror"
var/obj/effect/proc_holder/horror/PH
charges = 4
/datum/action/innate/cult/blood_spell/horror/New()
PH = new()
PH.attached_action = src
..()
/datum/action/innate/cult/blood_spell/horror/Destroy()
var/obj/effect/proc_holder/horror/destroy = PH
. = ..()
if(destroy && !QDELETED(destroy))
QDEL_NULL(destroy)
/datum/action/innate/cult/blood_spell/horror/Activate()
PH.toggle(owner) //the important bit
return TRUE
/obj/effect/proc_holder/horror
active = FALSE
ranged_mousepointer = 'icons/effects/cult_target.dmi'
var/datum/action/innate/cult/blood_spell/attached_action
/obj/effect/proc_holder/horror/Destroy()
var/datum/action/innate/cult/blood_spell/AA = attached_action
. = ..()
if(AA && !QDELETED(AA))
QDEL_NULL(AA)
/obj/effect/proc_holder/horror/proc/toggle(mob/user)
if(active)
remove_ranged_ability("<span class='cult'>You dispel the magic...</span>")
else
add_ranged_ability(user, "<span class='cult'>You prepare to horrify a target...</span>")
/obj/effect/proc_holder/horror/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return
if(ranged_ability_user.incapacitated() || !iscultist(caller))
remove_ranged_ability()
return
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
if(target in view(7, get_turf(ranged_ability_user)))
if(!ishuman(target) || iscultist(target))
return
var/mob/living/carbon/human/H = target
H.hallucination = max(H.hallucination, 240)
SEND_SOUND(ranged_ability_user, sound('sound/effects/ghost.ogg',0,1,50))
var/image/C = image('icons/effects/cult_effects.dmi',H,"bloodsparkles", ABOVE_MOB_LAYER)
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, FALSE)
addtimer(CALLBACK(H,/atom/.proc/remove_alt_appearance,"cult_apoc",TRUE), 2400, TIMER_OVERRIDE|TIMER_UNIQUE)
to_chat(ranged_ability_user,"<span class='cult'><b>[H] has been cursed with living nightmares!</b></span>")
attached_action.charges--
attached_action.desc = attached_action.base_desc
attached_action.desc += "<br><b><u>Has [attached_action.charges] use\s remaining</u></b>."
attached_action.UpdateButtonIcon()
if(attached_action.charges <= 0)
remove_mousepointer(ranged_ability_user.client)
remove_ranged_ability("<span class='cult'>You have exhausted the spell's power!</span>")
qdel(src)
/datum/action/innate/cult/blood_spell/veiling
name = "Conceal Presence"
desc = "A multi-function spell that alternates between hiding and revealing nearby cult runes, structures, turf, and airlocks."
invocation = "Kla'atu barada nikt'o!"
button_icon_state = "gone"
charges = 10
var/revealing = FALSE //if it reveals or not
/datum/action/innate/cult/blood_spell/veiling/Activate()
if(!revealing)
owner.visible_message("<span class='warning'>Thin grey dust falls from [owner]'s hand!</span>", \
"<span class='cultitalic'>You invoke the veiling spell, hiding nearby runes.</span>")
charges--
SEND_SOUND(owner, sound('sound/magic/smoke.ogg',0,1,25))
owner.whisper(invocation, language = /datum/language/common)
for(var/obj/effect/rune/R in range(5,owner))
R.conceal()
for(var/obj/structure/destructible/cult/S in range(5,owner))
S.conceal()
for(var/turf/open/floor/engine/cult/T in range(5,owner))
T.realappearance.alpha = 0
for(var/obj/machinery/door/airlock/cult/AL in range(5, owner))
AL.conceal()
revealing = TRUE
name = "Reveal Runes"
button_icon_state = "back"
else
owner.visible_message("<span class='warning'>A flash of light shines from [owner]'s hand!</span>", \
"<span class='cultitalic'>You invoke the counterspell, revealing nearby runes.</span>")
charges--
owner.whisper(invocation, language = /datum/language/common)
SEND_SOUND(owner, sound('sound/magic/enter_blood.ogg',0,1,25))
for(var/obj/effect/rune/R in range(7,owner)) //More range in case you weren't standing in exactly the same spot
R.reveal()
for(var/obj/structure/destructible/cult/S in range(6,owner))
S.reveal()
for(var/turf/open/floor/engine/cult/T in range(6,owner))
T.realappearance.alpha = initial(T.realappearance.alpha)
for(var/obj/machinery/door/airlock/cult/AL in range(6, owner))
AL.reveal()
revealing = FALSE
name = "Conceal Runes"
button_icon_state = "gone"
if(charges<= 0)
qdel(src)
desc = base_desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
UpdateButtonIcon()
/datum/action/innate/cult/blood_spell/manipulation
name = "Blood Rites"
desc = "A complex spell that allows you to gather blood and use it for healing or other powerful spells."
invocation = "Fel'th Dol Ab'orod!"
button_icon_state = "manip"
charges = 5
magic_path = "/obj/item/melee/blood_magic/manipulator"
// The "magic hand" items
/obj/item/melee/blood_magic
name = "\improper magical aura"
desc = "Sinister looking aura that distorts the flow of reality around it."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "disintegrate"
item_state = null
flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1
w_class = WEIGHT_CLASS_HUGE
throwforce = 0
throw_range = 0
throw_speed = 0
var/invocation
var/uses = 1
var/health_cost = 0 //The amount of health taken from the user when invoking the spell
var/datum/action/innate/cult/blood_spell/source
/obj/item/melee/blood_magic/New(loc, spell)
source = spell
uses = source.charges
health_cost = source.health_cost
..()
/obj/item/melee/blood_magic/Destroy()
if(!QDELETED(source))
if(uses <= 0)
source.hand_magic = null
qdel(source)
source = null
else
source.hand_magic = null
source.charges = uses
source.desc = source.base_desc
source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>."
source.UpdateButtonIcon()
..()
/obj/item/melee/blood_magic/attack_self(mob/living/user)
afterattack(user, user, TRUE)
/obj/item/melee/blood_magic/attack(mob/living/M, mob/living/carbon/user)
if(!iscarbon(user) || !iscultist(user))
uses = 0
qdel(src)
return
add_logs(user, M, "used a cult spell on", source.name, "")
M.lastattacker = user.real_name
M.lastattackerckey = user.ckey
/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
if(invocation)
user.whisper(invocation, language = /datum/language/common)
if(health_cost)
if(user.active_hand_index == 1)
user.apply_damage(health_cost, BRUTE, "l_arm")
else
user.apply_damage(health_cost, BRUTE, "r_arm")
if(uses <= 0)
qdel(src)
else if(source)
source.desc = source.base_desc
source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>."
source.UpdateButtonIcon()
//Stun
/obj/item/melee/blood_magic/stun
color = "#ff0000" // red
invocation = "Fuu ma'jin!"
/obj/item/melee/blood_magic/stun/afterattack(atom/target, mob/living/carbon/user, proximity)
if(!isliving(target) || !proximity)
return
var/mob/living/L = target
if(iscultist(target))
return
if(iscultist(user))
user.visible_message("<span class='warning'>[user] holds up their hand, which explodes in a flash of red light!</span>", \
"<span class='cultitalic'>You stun [L] with the spell!</span>")
var/obj/item/nullrod/N = locate() in L
if(N)
target.visible_message("<span class='warning'>[L]'s holy weapon absorbs the light!</span>", \
"<span class='userdanger'>Your holy weapon absorbs the blinding light!</span>")
else
L.Knockdown(180)
L.flash_act(1,1)
if(issilicon(target))
var/mob/living/silicon/S = L
S.emp_act(EMP_HEAVY)
else if(iscarbon(target))
var/mob/living/carbon/C = L
C.silent += 6
C.stuttering += 15
C.cultslurring += 15
C.Jitter(15)
if(is_servant_of_ratvar(L))
L.adjustBruteLoss(15)
uses--
..()
//Teleportation
/obj/item/melee/blood_magic/teleport
color = RUNE_COLOR_TELEPORT
desc = "A potent spell that teleport cultists on contact."
invocation = "Sas'so c'arta forbici!"
/obj/item/melee/blood_magic/teleport/afterattack(atom/target, mob/living/carbon/user, proximity)
if(!iscultist(target) || !proximity)
to_chat(user, "<span class='warning'>You can only teleport adjacent cultists with this spell!</span>")
return
if(iscultist(user))
var/list/potential_runes = list()
var/list/teleportnames = list()
for(var/R in GLOB.teleport_runes)
var/obj/effect/rune/teleport/T = R
potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
if(!potential_runes.len)
to_chat(user, "<span class='warning'>There are no valid runes to teleport to!</span>")
log_game("Teleport talisman failed - no other teleport runes")
return
var/turf/T = get_turf(src)
if(is_away_level(T.z))
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
log_game("Teleport spell failed - user in away mission")
return
var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
return
var/turf/dest = get_turf(actual_selected_rune)
if(is_blocked_turf(dest, TRUE))
to_chat(user, "<span class='warning'>The target rune is blocked. Attempting to teleport to it would be massively unwise.</span>")
return
uses--
user.visible_message("<span class='warning'>Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!</span>", \
"<span class='cultitalic'>You speak the words of the talisman and find yourself somewhere else!</span>", "<i>You hear a sharp crack.</i>")
var/mob/living/L = target
L.forceMove(dest)
dest.visible_message("<span class='warning'>There is a boom of outrushing air as something appears above the rune!</span>", null, "<i>You hear a boom.</i>")
..()
//Shackles
/obj/item/melee/blood_magic/shackles
name = "Shadow Shackles"
desc = "Allows you to bind a victim and temporarily silence them."
invocation = "In'totum Lig'abis!"
color = "#000000" // black
/obj/item/melee/blood_magic/shackles/afterattack(atom/target, mob/living/carbon/user, proximity)
if(iscultist(user) && iscarbon(target) && proximity)
var/mob/living/carbon/C = target
if(C.get_num_arms() >= 2 || C.get_arm_ignore())
CuffAttack(C, user)
else
user.visible_message("<span class='cultitalic'>This victim doesn't have enough arms to complete the restraint!</span>")
return
..()
/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user)
if(!C.handcuffed)
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
C.visible_message("<span class='danger'>[user] begins restraining [C] with dark magic!</span>", \
"<span class='userdanger'>[user] begins shaping a dark magic around your wrists!</span>")
if(do_mob(user, C, 30))
if(!C.handcuffed)
C.handcuffed = new /obj/item/restraints/handcuffs/energy/cult/used(C)
C.update_handcuffed()
C.silent += 5
to_chat(user, "<span class='notice'>You shackle [C].</span>")
add_logs(user, C, "shackled")
uses--
else
to_chat(user, "<span class='warning'>[C] is already bound.</span>")
else
to_chat(user, "<span class='warning'>You fail to shackle [C].</span>")
else
to_chat(user, "<span class='warning'>[C] is already bound.</span>")
/obj/item/restraints/handcuffs/energy/cult //For the shackling spell
name = "shadow shackles"
desc = "Shackles that bind the wrists with sinister magic."
trashtype = /obj/item/restraints/handcuffs/energy/used
flags_1 = DROPDEL_1
/obj/item/restraints/handcuffs/energy/cult/used/dropped(mob/user)
user.visible_message("<span class='danger'>[user]'s shackles shatter in a discharge of dark magic!</span>", \
"<span class='userdanger'>Your [src] shatters in a discharge of dark magic!</span>")
. = ..()
//Construction: Creates a construct shell out of 25 metal sheets, or converts plasteel into runed metal
/obj/item/melee/blood_magic/construction
name = "Twisted Construction"
desc = "Corrupts metal and plasteel into more sinister forms."
invocation = "Ethra p'ni dedol!"
color = "#000000" // black
/obj/item/melee/blood_magic/construction/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(proximity_flag && iscultist(user))
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))
uses--
to_chat(user, "<span class='warning'>A dark cloud eminates from your hand and swirls around the metal, twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else
to_chat(user, "<span class='warning'>You need 50 metal to produce a construct shell!</span>")
else if(istype(target, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/candidate = target
var/quantity = min(candidate.amount, uses)
uses -= quantity
new /obj/item/stack/sheet/runed_metal(T,quantity)
candidate.use(quantity)
to_chat(user, "<span class='warning'>A dark cloud eminates from you hand and swirls around the plasteel, transforming it into runed metal!</span>")
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)
user.visible_message("<span class='danger'>A dark cloud eminates from [user]'s hand and swirls around [candidate]!</span>")
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
var/prev_color = candidate.color
candidate.color = "black"
if(do_after(user, 90, target = candidate))
candidate.emp_act(EMP_HEAVY)
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
user.visible_message("<span class='danger'>The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!</span>")
switch(construct_class)
if("Juggernaut")
makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
if("Wraith")
makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
if("Artificer")
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
uses--
candidate.mmi = null
qdel(candidate)
else
candidate.color = prev_color
else
uses--
to_chat(user, "<span class='warning'>A dark cloud eminates from you hand and swirls around [candidate] - twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/obj/machinery/door/airlock))
target.narsie_act()
uses--
user.visible_message("<span class='warning'>Black ribbons suddenly eminate from [user]'s hand and cling to the airlock - twisting and corrupting it!</span>")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else
to_chat(user, "<span class='warning'>The spell will not work on [target]!</span>")
..()
//Armor: Gives the target a basic cultist combat loadout
/obj/item/melee/blood_magic/armor
name = "Sinister Armaments"
desc = "A spell that will equip the target with cultist equipment if there is a slot to equip it to."
color = "#33cc33" // green
/obj/item/melee/blood_magic/armor/afterattack(atom/target, mob/living/carbon/user, proximity)
if(iscarbon(target) && proximity)
uses--
var/mob/living/carbon/C = target
C.visible_message("<span class='warning'>Otherworldly armor suddenly appears on [C]!</span>")
C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,slot_w_uniform)
C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head)
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)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade(user))
C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
..()
/obj/item/melee/blood_magic/manipulator
name = "Blood Rite"
desc = "A spell that will absorb blood from anything you touch.<br>Touching cultists and constructs can heal them.<br><b>Clicking the hand will potentially let you focus the spell into something stronger.</b>"
color = "#7D1717"
/obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity)
if(proximity)
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(NOBLOOD in H.dna.species.species_traits)
to_chat(user,"<span class='warning'>Blood rites do not work on species with no blood!</span>")
return
if(iscultist(H))
if(H.stat == DEAD)
to_chat(user,"<span class='warning'>Only a revive rune can bring back the dead!</span>")
return
if(H.blood_volume < BLOOD_VOLUME_SAFE)
var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume
if(uses*2 < restore_blood)
H.blood_volume += uses*2
to_chat(user,"<span class='danger'>You use the last of your blood rites to restore what blood you could!</span>")
uses = 0
return ..()
else
H.blood_volume = BLOOD_VOLUME_SAFE
uses -= round(restore_blood/2)
to_chat(user,"<span class='warning'>Your blood rites have restored [H == user ? "your" : "their"] blood to safe levels!</span>")
var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss()
if(overall_damage == 0)
to_chat(user,"<span class='cult'>That cultist doesn't require healing!</span>")
else
var/ratio = uses/overall_damage
if(H == user)
to_chat(user,"<span class='cult'><b>Your blood healing is far less efficient when used on yourself!</b></span>")
ratio *= 0.35 // Healing is half as effective if you can't perform a full heal
uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal
if(ratio>1)
ratio = 1
uses -= round(overall_damage)
H.visible_message("<span class='warning'>[H] is fully healed by [H==user ? "their":"[H]'s"]'s blood magic!</span>")
else
H.visible_message("<span class='warning'>[H] is partially healed by [H==user ? "their":"[H]'s"] blood magic.</span>")
uses = 0
ratio *= -1
H.adjustOxyLoss((overall_damage*ratio) * (H.getOxyLoss() / overall_damage), 0)
H.adjustToxLoss((overall_damage*ratio) * (H.getToxLoss() / overall_damage), 0)
H.adjustFireLoss((overall_damage*ratio) * (H.getFireLoss() / overall_damage), 0)
H.adjustBruteLoss((overall_damage*ratio) * (H.getBruteLoss() / overall_damage), 0)
H.updatehealth()
playsound(get_turf(H), 'sound/magic/staff_healing.ogg', 25)
new /obj/effect/temp_visual/cult/sparks(get_turf(H))
user.Beam(H,icon_state="sendbeam",time=15)
else
if(H.stat == DEAD)
to_chat(user,"<span class='warning'>Their blood has stopped flowing, you'll have to find another way to extract it.</span>")
return
if(H.cultslurring)
to_chat(user,"<span class='danger'>Their blood has been tainted by an even stronger form of blood magic, it's no use to us like this!</span>")
return
if(H.blood_volume > BLOOD_VOLUME_SAFE)
H.blood_volume -= 100
uses += 50
user.Beam(H,icon_state="drainbeam",time=10)
playsound(get_turf(H), 'sound/magic/enter_blood.ogg', 50)
H.visible_message("<span class='danger'>[user] has drained some of [H]'s blood!</span>")
to_chat(user,"<span class='cultitalic'>Your blood rite gains 50 charges from draining [H]'s blood.</span>")
new /obj/effect/temp_visual/cult/sparks(get_turf(H))
else
to_chat(user,"<span class='danger'>They're missing too much blood - you cannot drain them further!</span>")
return
if(isconstruct(target))
var/mob/living/simple_animal/M = target
var/missing = M.maxHealth - M.health
if(missing)
if(uses > missing)
M.adjustHealth(-missing)
M.visible_message("<span class='warning'>[M] is fully-healed by [user]'s blood magic!</span>")
uses -= missing
else
M.adjustHealth(-uses)
M.visible_message("<span class='warning'>[M] is healed by [user]'sblood magic!</span>")
uses = 0
playsound(get_turf(M), 'sound/magic/staff_healing.ogg', 25)
user.Beam(M,icon_state="sendbeam",time=10)
if(istype(target, /obj/effect/decal/cleanable/blood))
blood_draw(target, user)
..()
/obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user)
var/temp = 0
var/turf/T = get_turf(target)
if(T)
for(var/obj/effect/decal/cleanable/blood/B in view(T, 2))
if(B.blood_state == "blood")
if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam
temp += 30
else
temp += max((B.bloodiness**2)/800,1)
new /obj/effect/temp_visual/cult/turf/floor(get_turf(B))
qdel(B)
for(var/obj/effect/decal/cleanable/trail_holder/TH in view(T, 2))
qdel(TH)
var/obj/item/clothing/shoes/shoecheck = user.shoes
if(shoecheck && shoecheck.bloody_shoes["blood"])
temp += shoecheck.bloody_shoes["blood"]/20
shoecheck.bloody_shoes["blood"] = 0
if(temp)
user.Beam(T,icon_state="drainbeam",time=15)
new /obj/effect/temp_visual/cult/sparks(get_turf(user))
playsound(T, 'sound/magic/enter_blood.ogg', 50)
to_chat(user, "<span class='cultitalic'>Your blood rite has gained [round(temp)] charge\s from blood sources around you!</span>")
uses += round(temp)
/obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user)
if(iscultist(user))
var/list/options = list("Blood Spear (200)", "Blood Bolt Barrage (400)", "Blood Beam (600)")
var/choice = input(user, "Choose a greater blood rite...", "Greater Blood Rites") as null|anything in options
if(!choice)
to_chat(user, "<span class='cultitalic'>You decide against conducting a greater blood rite.</span>")
return
switch(choice)
if("Blood Spear (200)")
if(uses < 200)
to_chat(user, "<span class='cultitalic'>You need 200 charges to perform this rite.</span>")
else
uses -= 200
var/turf/T = get_turf(user)
qdel(src)
var/datum/action/innate/cult/spear/S = new(user)
var/obj/item/twohanded/cult_spear/rite = new(T)
S.Grant(user, rite)
rite.spear_act = S
if(user.put_in_hands(rite))
to_chat(user, "<span class='cultitalic'>A [rite.name] appears in your hand!</span>")
else
user.visible_message("<span class='warning'>A [rite.name] appears at [user]'s feet!</span>", \
"<span class='cultitalic'>A [rite.name] materializes at your feet.</span>")
if("Blood Bolt Barrage (400)")
if(uses < 400)
to_chat(user, "<span class='cultitalic'>You need 400 charges to perform this rite.</span>")
else
var/obj/rite = new /obj/item/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/blood()
uses -= 400
qdel(src)
if(user.put_in_hands(rite))
to_chat(user, "<span class='cult'><b>Your hands glow with power!</b></span>")
else
to_chat(user, "<span class='cultitalic'>You need a free hand for this rite!</span>")
qdel(rite)
if("Blood Beam (600)")
if(uses < 600)
to_chat(user, "<span class='cultitalic'>You need 600 charges to perform this rite.</span>")
else
var/obj/rite = new /obj/item/blood_beam()
uses -= 600
qdel(src)
if(user.put_in_hands(rite))
to_chat(user, "<span class='cultlarge'><b>Your hands glow with POWER OVERWHELMING!!!</b></span>")
else
to_chat(user, "<span class='cultitalic'>You need a free hand for this rite!</span>")
qdel(rite)
@@ -0,0 +1,500 @@
// Dogborg Sleeper units
/obj/item/device/dogborg/sleeper
name = "hound sleeper"
desc = "nothing should see this."
icon = 'icons/mob/dogborg.dmi'
icon_state = "sleeper"
w_class = WEIGHT_CLASS_TINY
var/mob/living/carbon/patient = null
var/mob/living/silicon/robot/hound = null
var/inject_amount = 10
var/min_health = -100
var/cleaning = FALSE
var/cleaning_cycles = 10
var/patient_laststat = null
var/list/injection_chems = list("antitoxin", "epinephrine", "morphine", "salbutamol", "bicaridine", "kelotane")
var/eject_port = "ingestion"
var/escape_in_progress = FALSE
var/message_cooldown
var/breakout_time = 300
var/list/items_preserved = list()
var/static/list/important_items = typecacheof(list(
/obj/item/hand_tele,
/obj/item/card/id,
/obj/item/device/aicard,
/obj/item/gun,
/obj/item/pinpointer,
/obj/item/clothing/shoes/magboots,
/obj/item/clothing/head/helmet/space,
/obj/item/clothing/suit/space,
/obj/item/reagent_containers/hypospray/CMO,
/obj/item/tank/jetpack/oxygen/captain,
/obj/item/clothing/accessory/medal/gold/captain,
/obj/item/clothing/suit/armor,
/obj/item/documents,
/obj/item/nuke_core,
/obj/item/nuke_core_container,
/obj/item/areaeditor/blueprints,
/obj/item/documents/syndicate,
/obj/item/disk/nuclear,
/obj/item/bombcore,
/obj/item/grenade,
/obj/item/storage
))
// Bags are prohibited from this due to the potential explotation of objects, same with brought
/obj/item/device/dogborg/sleeper/New()
..()
update_icon()
flags_1 |= NOBLUDGEON_1 //No more attack messages
/obj/item/device/dogborg/sleeper/Exit(atom/movable/O)
return 0
/obj/item/device/dogborg/sleeper/afterattack(mob/living/carbon/target, mob/living/silicon/user, proximity)
hound = loc
if(!proximity)
return
if(!iscarbon(target))
return
if(!(target.client && target.client.prefs && target.client.prefs.toggles && (target.client.prefs.toggles & MEDIHOUND_SLEEPER)))
to_chat(user, "<span class='warning'>This person is incompatible with our equipment.</span>")
return
if(target.buckled)
to_chat(user, "<span class='warning'>The user is buckled and can not be put into your [src.name].</span>")
return
if(patient)
to_chat(user, "<span class='warning'>Your [src.name] is already occupied.</span>")
return
testing("using sleeper/afterattack")
user.visible_message("<span class='warning'>[hound.name] is carefully inserting [target.name] into their [src.name].</span>", "<span class='notice'>You start placing [target] into your [src]...</span>")
if(!patient && iscarbon(target) && !target.buckled && do_after (user, 50, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
if(patient) return //If you try to eat two people at once, you can only eat one.
else //If you don't have someone in you, proceed.
if(!isjellyperson(target) && ("toxin" in injection_chems))
injection_chems -= "toxin"
injection_chems += "antitoxin"
if(isjellyperson(target) && !("toxin" in injection_chems))
injection_chems -= "antitoxin"
injection_chems += "toxin"
target.forceMove(src)
target.reset_perspective(src)
update_gut()
START_PROCESSING(SSobj, src)
user.visible_message("<span class='warning'>[hound.name]'s medical pod lights up and expands as [target.name] slips inside into their [src.name].</span>", "<span class='notice'>Your medical pod lights up as [target] slips into your [src]. Life support functions engaged.</span>")
message_admins("[key_name(hound)] has eaten [key_name(patient)] as a dogborg. ([hound ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[hound.x];Y=[hound.y];Z=[hound.z]'>JMP</a>" : "null"])")
playsound(hound, 'sound/effects/bin_close.ogg', 100, 1)
/obj/item/device/dogborg/sleeper/container_resist(mob/living/user)
hound = loc
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
if(user.a_intent == INTENT_HELP)
return
user.visible_message("<span class='notice'>You see [user] kicking against the expanded material of [hound.name]'s gut!</span>", \
"<span class='notice'>You struggle inside [src], kicking the release with your foot... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a thump from [hound.name].</span>")
if(do_after(user, breakout_time, target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src )
return
user.visible_message("<span class='warning'>[user] successfully broke out of [hound.name]!</span>", \
"<span class='notice'>You successfully break out of [hound.name]!</span>")
go_out()
/obj/item/device/dogborg/sleeper/proc/go_out(var/target)
hound = src.loc
testing("go_out activated")
hound.setClickCooldown(50)
if(length(contents) > 0)
hound.visible_message("<span class='warning'>[hound.name] empties out their contents via their release port.</span>", "<span class='notice'>You empty your contents via your release port.</span>")
if(target)
if(iscarbon(target))
var/mob/living/carbon/person = target
person.forceMove(get_turf(src))
person.reset_perspective()
else
var/obj/T = target
T.loc = hound.loc
else
for(var/C in contents)
if(iscarbon(C))
var/mob/living/carbon/person = C
person.forceMove(get_turf(src))
person.reset_perspective()
else
var/obj/T = C
T.loc = hound.loc
items_preserved.Cut()
update_gut()
cleaning = FALSE
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
else //You clicked eject with nothing in you, let's just reset stuff to be sure.
items_preserved.Cut()
cleaning = FALSE
hound.visible_message("<span class='warning'>[hound.name] belches, torso flexing.</span>")
update_gut()
/obj/item/device/dogborg/sleeper/attack_self(mob/user)
if(..())
return
ui_interact(user)
/obj/item/device/dogborg/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "dogborg_sleeper", name, 375, 550, master_ui, state)
ui.open()
/obj/item/device/dogborg/sleeper/ui_data()
var/list/data = list()
data["occupied"] = patient ? 1 : 0
if(cleaning && length(contents - items_preserved))
data["items"] = "Self-cleaning mode active: [length(contents - items_preserved)] object(s) remaining."
data["cleaning"] = cleaning
if(injection_chems != null)
data["chem"] = list()
for(var/chem in injection_chems)
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
data["chem"] += list(list("name" = R.name, "id" = R.id))
data["occupant"] = list()
var/mob/living/mob_occupant = patient
if(mob_occupant)
data["occupant"]["name"] = mob_occupant.name
switch(mob_occupant.stat)
if(CONSCIOUS)
data["occupant"]["stat"] = "Conscious"
data["occupant"]["statstate"] = "good"
if(SOFT_CRIT)
data["occupant"]["stat"] = "Conscious"
data["occupant"]["statstate"] = "average"
if(UNCONSCIOUS)
data["occupant"]["stat"] = "Unconscious"
data["occupant"]["statstate"] = "average"
if(DEAD)
data["occupant"]["stat"] = "Dead"
data["occupant"]["statstate"] = "bad"
data["occupant"]["health"] = mob_occupant.health
data["occupant"]["maxHealth"] = mob_occupant.maxHealth
data["occupant"]["minHealth"] = HEALTH_THRESHOLD_DEAD
data["occupant"]["bruteLoss"] = mob_occupant.getBruteLoss()
data["occupant"]["oxyLoss"] = mob_occupant.getOxyLoss()
data["occupant"]["toxLoss"] = mob_occupant.getToxLoss()
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
data["occupant"]["brainLoss"] = mob_occupant.getBrainLoss()
data["occupant"]["reagents"] = list()
if(mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
return data
/obj/item/device/dogborg/sleeper/ui_act(action, params)
if(..())
return
switch(action)
if("eject")
go_out()
. = TRUE
if("inject")
var/chem = params["chem"]
if(!patient)
return
inject_chem(chem)
. = TRUE
if("cleaning")
testing("cleaning attempted")
if(!contents)
testing("cleaning has no contents")
to_chat(src, "Your [src] is already cleaned.")
return
if(patient)
to_chat(patient, "<span class='danger'>[hound.name]'s [src.name] fills with caustic enzymes around you!</span>")
testing("clean_cycle activated")
to_chat(src, "<span class='danger'>Cleaning process enabled.</span>")
clean_cycle()
. = TRUE
/obj/item/device/dogborg/sleeper/proc/update_gut()
testing("update_gut proc fired")
//Well, we HAD one, what happened to them?
if(patient in contents)
if(patient_laststat != patient.stat)
if(patient.stat & DEAD)
hound.sleeper_r = 1
hound.sleeper_g = 0
patient_laststat = patient.stat
else
hound.sleeper_r = 0
hound.sleeper_g = 1
patient_laststat = patient.stat
//Update icon
hound.update_icons()
//Return original patient
return(patient)
//Check for a new patient
else
for(var/mob/living/carbon/human/C in contents)
patient = C
if(patient.stat & DEAD)
hound.sleeper_r = 1
hound.sleeper_g = 0
patient_laststat = patient.stat
else
hound.sleeper_r = 0
hound.sleeper_g = 1
patient_laststat = patient.stat
//Update icon and return new patient
hound.update_icons()
return(C)
//Cleaning looks better with red on, even with nobody in it
if(cleaning && !patient)
hound.sleeper_r = 1
hound.sleeper_g = 0
//Couldn't find anyone, and not cleaning
else if(!cleaning && !patient)
hound.sleeper_r = 0
hound.sleeper_g = 0
patient_laststat = null
patient = null
hound.update_icons()
return
//Gurgleborg process
/obj/item/device/dogborg/sleeper/proc/clean_cycle()
testing("clean_cycle activated")
//Sanity
for(var/I in items_preserved)
if(!(I in contents))
items_preserved -= I
var/list/touchable_items = contents - items_preserved
if(cleaning_cycles)
testing("clean_cycle being used")
cleaning_cycles--
cleaning = TRUE
for(var/mob/living/carbon/human/T in (touchable_items))
if((T.status_flags & GODMODE) || !T.digestable)
src.items_preserved += T
else
T.adjustBruteLoss(2)
T.adjustFireLoss(3)
update_gut()
var/atom/target = pick(touchable_items)
if(iscarbon(target)) //Handle the target being a mob
var/mob/living/carbon/T = target
if(T.stat == DEAD && T.digestable) //Mob is now dead
message_admins("[key_name(hound)] has digested [key_name(T)] as a dogborg. ([hound ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[hound.x];Y=[hound.y];Z=[hound.z]'>JMP</a>" : "null"])")
to_chat(hound,"<span class='notice'>You feel your belly slowly churn around [T], breaking them down into a soft slurry to be used as power for your systems.</span>")
to_chat(T,"<span class='notice'>You feel [hound]'s belly slowly churn around your form, breaking you down into a soft slurry to be used as power for [hound]'s systems.</span>")
src.hound.cell.give(30000) //Fueeeeellll
T.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(hound),"death_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
T.stop_sound_channel(CHANNEL_PRED)
T.playsound_local("death_prey",60)
for(var/belly in T.vore_organs)
var/obj/belly/B = belly
for(var/atom/movable/thing in B)
thing.forceMove(src)
if(ismob(thing))
to_chat(thing, "As [T] melts away around you, you find yourself in [hound]'s [name]")
for(var/obj/item/W in T)
if(!T.dropItemToGround(W))
qdel(W)
qdel(T)
update_gut()
//Handle the target being anything but a mob
else if(isobj(target))
var/obj/T = target
if(T.type in important_items) //If the object is in the items_preserved global list
src.items_preserved += T
//If the object is not one to preserve
else
qdel(T)
src.update_gut()
src.hound.cell.give(10)
else
testing("clean_cycle finished and reset")
cleaning_cycles = initial(cleaning_cycles)
cleaning = FALSE
to_chat(hound, "<span class='notice'>Your [src.name] chimes it ends its self-cleaning cycle.</span>")//Belly is entirely empty
update_gut()
if(!length(contents))
to_chat(hound, "<span class='notice'>Your [src.name] is now clean. Ending self-cleaning cycle.</span>")
cleaning = FALSE
update_gut()
return
//sound effects
for(var/mob/living/M in contents)
if(prob(50))
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(hound),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local("digest_prey",60)
if(cleaning)
addtimer(CALLBACK(src, .proc/clean_cycle), 50)
/obj/item/device/dogborg/sleeper/proc/CheckAccepted(obj/item/I)
return is_type_in_typecache(I, important_items)
/obj/item/device/dogborg/sleeper/proc/inject_chem(chem)
testing("inject chem triggered, checking power")
if(hound.cell.charge <= 800) //This is so borgs don't kill themselves with it. Remember, 750 charge used every injection.
to_chat(hound, "<span class='notice'>You don't have enough power to synthesize fluids.</span>")
return
testing("Has power, checking for overdose")
if(patient.reagents.get_reagent_amount(chem) + 10 >= 20) //Preventing people from accidentally killing themselves by trying to inject too many chemicals!
to_chat(hound, "<span class='notice'>Your stomach is currently too full of fluids to secrete more fluids of this kind.</span>")
return
testing("isn't overdosing, attempting to add_reagent")
patient.reagents.add_reagent(chem, 10)
testing("add_reagent")
src.hound.cell.use(750) //-750 charge per injection
testing("draining power")
var/units = round(patient.reagents.get_reagent_amount(chem))
to_chat(hound, "<span class='notice'>Injecting [units] unit\s of [chem] into occupant.</span>") //If they were immersed, the reagents wouldn't leave with them.
/obj/item/device/dogborg/sleeper/medihound //Medihound sleeper
name = "Mobile Sleeper"
desc = "Equipment for medical hound. A mounted sleeper that stabilizes patients and can inject reagents in the borg's reserves."
icon = 'icons/mob/dogborg.dmi'
icon_state = "sleeper"
/obj/item/device/dogborg/sleeper/K9 //The K9 portabrig
name = "Mobile Brig"
desc = "Equipment for a K9 unit. A mounted portable-brig that holds criminals."
icon = 'icons/mob/dogborg.dmi'
icon_state = "sleeperb"
inject_amount = 0
min_health = -100
injection_chems = null //So they don't have all the same chems as the medihound!
/obj/item/storage/attackby(obj/item/device/dogborg/sleeper/K9, mob/user, proximity)
K9.afterattack(src, user ,1)
/obj/item/device/dogborg/sleeper/K9/afterattack(var/atom/movable/target, mob/living/silicon/user, proximity)
hound = loc
if(!istype(target))
return
if(!proximity)
return
if(target.anchored)
return
if(isobj(target))
to_chat(user, "You are above putting such trash inside of yourself.")
return
if(iscarbon(target))
var/mob/living/carbon/brigman = target
if (!brigman.devourable)
to_chat(user, "The target registers an error code. Unable to insert into [src.name].")
return
if(patient)
to_chat(user,"<span class='warning'>Your [src.name] is already occupied.</span>")
return
if(brigman.buckled)
to_chat(user,"<span class='warning'>[brigman] is buckled and can not be put into your [src.name].</span>")
return
user.visible_message("<span class='warning'>[hound.name] is ingesting [brigman] into their [src.name].</span>", "<span class='notice'>You start ingesting [brigman] into your [src.name]...</span>")
if(do_after(user, 30, target = brigman) && !patient && !brigman.buckled)
if(!in_range(src, brigman)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
brigman.forceMove(src)
brigman.reset_perspective(src)
update_gut()
START_PROCESSING(SSobj, src)
user.visible_message("<span class='warning'>[hound.name]'s mobile brig clunks in series as [brigman] slips inside.</span>", "<span class='notice'>Your mobile brig groans lightly as [brigman] slips inside.</span>")
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1) // Really don't need ERP sound effects for robots
return
return
/obj/item/device/dogborg/sleeper/compactor //Janihound gut.
name = "garbage processor"
desc = "A mounted garbage compactor unit with fuel processor."
icon = 'icons/mob/dogborg.dmi'
icon_state = "compactor"
inject_amount = 0
min_health = -100
injection_chems = null //So they don't have all the same chems as the medihound!
var/max_item_count = 30
/obj/item/storage/attackby(obj/item/device/dogborg/sleeper/compactor, mob/user, proximity) //GIT CIRCUMVENTED YO!
compactor.afterattack(src, user ,1)
/obj/item/device/dogborg/sleeper/compactor/afterattack(var/atom/movable/target, mob/living/silicon/user, proximity)//GARBO NOMS
hound = loc
var/obj/item/target_obj = target
if(!istype(target))
return
if(!proximity)
return
if(target.anchored)
return
if(length(contents) > (max_item_count - 1))
to_chat(user,"<span class='warning'>Your [src.name] is full. Eject or process contents to continue.</span>")
return
if(isobj(target))
testing("Checking target type")
if(CheckAccepted(target))
to_chat(user,"<span class='warning'>\The [target] registers an error code to your [src.name]</span>")
return
testing("Target not on the important list")
if(target_obj.w_class > WEIGHT_CLASS_NORMAL)
to_chat(user,"<span class='warning'>\The [target] is too large to fit into your [src.name]</span>")
return
testing("Target not too large.")
user.visible_message("<span class='warning'>[hound.name] is ingesting [target.name] into their [src.name].</span>", "<span class='notice'>You start ingesting [target] into your [src.name]...</span>")
if(do_after(user, 15, target = target) && length(contents) < max_item_count)
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them. This still applies to items, don't magically eat things I picked up already.
target.forceMove(src)
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [target.name] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [target] slips inside.</span>")
playsound(hound, 'sound/machines/disposalflush.ogg', 50, 1)
if(length(contents) > 11) //grow that tum after a certain junk amount
hound.sleeper_r = 1
hound.update_icons()
else
hound.sleeper_r = 0
hound.update_icons()
return
else if(iscarbon(target))
var/mob/living/carbon/trashman = target
if (!trashman.devourable)
to_chat(user, "<span class='warning'>\The [target] registers an error code to your [src.name]</span>")
return
if(patient)
to_chat(user,"<span class='warning'>Your [src.name] is already occupied.</span>")
return
if(trashman.buckled)
to_chat(user,"<span class='warning'>[trashman] is buckled and can not be put into your [src.name].</span>")
return
user.visible_message("<span class='warning'>[hound.name] is ingesting [trashman] into their [src.name].</span>", "<span class='notice'>You start ingesting [trashman] into your [src.name]...</span>")
if(do_after(user, 30, target = trashman) && !patient && !trashman.buckled && length(contents) < max_item_count)
if(!in_range(src, trashman)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
trashman.forceMove(src)
trashman.reset_perspective(src)
update_gut()
START_PROCESSING(SSobj, src)
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [trashman] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [trashman] slips inside.</span>")
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
return
return
-13
View File
@@ -1,13 +0,0 @@
/mob/var/skincmds = list()
/obj/proc/SkinCmd(mob/user as mob, var/data as text)
/proc/SkinCmdRegister(mob/user, name as text, obj/O)
user.skincmds[name] = O
/mob/verb/skincmd(data as text)
set hidden = 1
var/ref = copytext(data, 1, findtext(data, ";"))
if (src.skincmds[ref] != null)
var/obj/a = src.skincmds[ref]
a.SkinCmd(src, copytext(data, findtext(data, ";") + 1))